单链表链表结构的实现

class Node { constructor(value) { this.value = value; this.next = null; }}class LinkedList { constructor() { this.length = 0; this.head = null; } equalsFn(a, b) { return a === b; }}
功能
- push(element):向链表尾部添加一个新元素。
- insert(element, position):向链表的特定位置插入一个新元素。
- getElementAt(index):返回链表中特定位置的元素。如果链表中不存在这样的元素,则返回undefined。
- remove(element):从链表中移除一个元素。
- indexOf(element):返回元素在链表中的索引。如果链表中没有该元素则返回-1。
- removeAt(position):从链表的特定位置移除一个元素。
- isEmpty():如果链表中不包含任何元素,返回true,如果链表长度大于0 则返回false。
- size():返回链表包含的元素个数,与数组的length 属性类似。
- toString():返回表示整个链表的字符串。由于列表项使用了Node 类,就需要重写继承自JavaScript 对象默认的toString 方法,让其只输出元素的值。
push
push(val) { let newNode = new Node(val); let curr; if (!this.head) { // 刚开始链表为空,就把这个设置为head this.head = newNode; } else { curr = this.head; while (curr.next) { // 一直找到链表末尾 curr = curr.next; } curr.next = newNode; } this.length++; }
removeAt

removeAt(index) { if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) { this.head = curr.next; } else { // 找到index前一个后停止,下一个就是要删除的结点 for (let i = 1; i < index; i++) { curr = curr.next; } let beRemove = curr.next; // 改变要被删除结点的上一个结点的指向 curr.next = beRemove.next; this.length--; return beRemove; } } }
getElementAt
getElementAt(index) { if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) return curr; else { for (let i = 1; i <= index; i++) { curr = curr.next; } return curr; } } }
重写removeAt
removeAt(index) { let curr = this.getElementAt(index - 1); curr.next = curr.next.next;
insert

insert(index, value) { let newNode = new Node(value); if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) { // index 为0,改变头结点指向就行了 this.head = newNode; this.head.next = curr; } else { // 找到插入位置的前一个, for (let i = 1; i < index; i++) { curr = curr.next; } let nextNode = curr.next; curr.next = newNode; newNode.next = nextNode; } this.length++; } }
indexOf
indexOf(value) { let curr = this.head; // 存入head if (this.equalsFn(curr.value, value)) { return 0; } for (let i = 1; i < this.length; i++) { curr = curr.next; if (this.equalsFn(curr.value, value)) { return i; } } return -1; }
removeValue
removeValue(value) { let curr = this.head; let prev = null; if (this.equalsFn(curr.value, value)) { this.head = curr.next; this.length--; } for (let i = 1; i < this.length; i++) { prev = curr; curr = curr.next; if (this.equalsFn(curr.value, value)) { prev.next = curr.next; this.length--; } } return undefined; }
toString
toString() { let objString = ""; let curr = this.head; if (!curr) { return objString; } else { objString = `${curr.value}`; for (let i = 1; i < this.length; i++) { curr = curr.next; objString = `${objString}, ${curr.value}`; } return objString; } }
完整代码
class Node { constructor(value) { this.value = value; this.next = null; }}class LinkedList { constructor() { this.length = 0; this.head = null; } equalsFn(a, b) { return a === b; } push(val) { let newNode = new Node(val); let curr; if (!this.head) { // 刚开始链表为空,就把这个设置为head this.head = newNode; } else { curr = this.head; while (curr.next) { // 一直找到链表末尾 curr = curr.next; } curr.next = newNode; } this.length++; } removeAt(index) { let curr = this.getElementAt(index - 1); curr.next = curr.next.next; } getElementAt(index) { if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) return curr; else { for (let i = 1; i <= index; i++) { curr = curr.next; } return curr; } } } insert(index, value) { let newNode = new Node(value); if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) { // index 为0,改变头结点指向就行了 this.head = newNode; this.head.next = curr; } else { // 找到插入位置的前一个, for (let i = 1; i < index; i++) { curr = curr.next; } let nextNode = curr.next; curr.next = newNode; newNode.next = nextNode; } this.length++; } else { throw "索引值错误"; } } indexOf(value) { let curr = this.head; // 存入head if (this.equalsFn(curr.value, value)) { return 0; } for (let i = 1; i < this.length; i++) { curr = curr.next; if (this.equalsFn(curr.value, value)) { return i; } } return -1; } removeValue(value) { let curr = this.head; let prev = null; if (this.equalsFn(curr.value, value)) { this.head = curr.next; this.length--; } for (let i = 1; i < this.length; i++) { prev = curr; curr = curr.next; if (this.equalsFn(curr.value, value)) { prev.next = curr.next; this.length--; } } return undefined; } toString() { let objString = ""; let curr = this.head; if (!curr) { return objString; } else { objString = `${curr.value}`; for (let i = 1; i < this.length; i++) { curr = curr.next; objString = `${objString}, ${curr.value}`; } return objString; } } getHead() { return this.head; } isEmpty() { return this.length === 0 ? true : false; } size() { return this.length; }}let linkedList = new LinkedList();linkedList.push("a");linkedList.push("b");linkedList.push("c");// linkedList.removeAt(1);linkedList.insert(1, "aa");console.log(linkedList.getElementAt(2));console.log(linkedList.indexOf("a"));console.log(linkedList.removeValue("c"));console.log(linkedList.size());console.log(linkedList.isEmpty());console.log(linkedList);console.log(linkedList.toString());
双向链表的实现

class Node { constructor(value) { this.value = value; this.next = null; this.prev = null; }}class DBLinkedList { constructor() { this.length = 0; this.head = null; } equalsFn(a, b) { return a === b; }}
双向链表需要讨论的情况
- 当结点为头结点时
- 当结点为最后一个结点时
- 当结点有且只有一个结点时
重构链表方法
class Node { constructor(value) { this.value = value; this.next = null; this.prev = null; }}class DBLinkedList { constructor() { this.length = 0; this.head = null; } equalsFn(a, b) { return a === b; } push(val) { let newNode = new Node(val); let prev = this.head; let curr; if (!this.head) { // 刚开始链表为空,就把这个设置为head this.head = newNode; } else { curr = this.head; while (curr.next) { // 一直找到链表末尾 curr = curr.next; prev = curr; } curr.next = newNode; newNode.prev = prev; } this.length++; } removeAt(index) { if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) { this.head = curr.next; if (this.length !== 1) { this.head.prev = null; } this.length--; } else { // 找到index前一个后停止,下一个就是要删除的结点 for (let i = 1; i < index; i++) { curr = curr.next; } let beRemove = curr.next; // 改变要被删除结点的上一个结点的指向 curr.next = beRemove.next; if (index !== this.length - 1) { beRemove.next.prev = curr; } this.length--; return beRemove; } } } getElementAt(index) { if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) return curr; else { for (let i = 1; i <= index; i++) { curr = curr.next; } return curr; } } } insert(index, value) { let newNode = new Node(value); if (index < this.length && index >= 0) { let curr = this.head; if (index === 0) { // index 为0,改变头结点指向就行了 this.head = newNode; this.head.next = curr; if (this.length > 1) { this.head.prev = null; } } else { // 找到插入位置的前一个, for (let i = 1; i < index; i++) { curr = curr.next; } let nextNode = curr.next; curr.next = newNode; newNode.prev = curr; newNode.next = nextNode; if (index !== this.length - 1) { nextNode.prev = newNode; } } this.length++; } else { throw "索引值错误"; } } indexOf(value) { let curr = this.head; // 存入head if (this.equalsFn(curr.value, value)) { return 0; } for (let i = 1; i < this.length; i++) { curr = curr.next; if (this.equalsFn(curr.value, value)) { return i; } } return -1; } removeValue(value) { let curr = this.head; let prev = null; if (this.equalsFn(curr.value, value)) { this.head = curr.next; if (this.head) { this.head.prev = null; } this.length--; } for (let i = 1; i < this.length; i++) { prev = curr; curr = curr.next; if (this.equalsFn(curr.value, value)) { prev.next = curr.next; if (curr.next) { curr.next.prev = prev; } this.length--; } } return undefined; } toString() { let objString = ""; let curr = this.head; if (!curr) { return objString; } else { objString = `${curr.value}`; for (let i = 1; i < this.length; i++) { curr = curr.next; objString = `${objString}, ${curr.value}`; } return objString; } } getHead() { return this.head; } isEmpty() { return this.length === 0 ? true : false; } size() { return this.length; }}
循环链表的概念

- 循环链表可以像链表一样只有单向引用,也可以像双向链表一样有双向引用。
- 循环链表和链表之间唯一的区别在于,最后一个元素指向下一个元素的指针不是引用undefined,而是指向第一个元素(head)