- 多个元素组成的列表
- 元素的存储是不连续的,用next指针连在一起
数组 vs链表
- 数组:增删非首尾元素时往往需要移动元素
- 链表:增删非首位元素时,不需要移动元素、只需要更改next指向就好了
JS 的实现
- javaScript没有链表,但可以用object来实现
原型链
- 下面用a -> b表示,a.proto等于b
- obj -> Object.prototype -> null
- func -> Function.prototype -> Object.prototype -> null
- arr -> Array.prototype -> Object.prototype -> nullz
- 知识点
- 如果A沿着原型链能找到B.prototype,那么,
A instance of B 为true - 如果在A上面找不到的方法,会沿着A的原型链,层层向上找
单向链表
图示
JS实现
// 自定义一个类,用于比较class Comparator { constructor(compareFunction) { // 如果有传进来比较函数,就用自身的比较函数 this.compare = compareFunction || Comparator.defaultCompareFunction; } /* * 对比a,b * a === b 返回0 * a < b 返回-1 * a > b 返回1 */ static defaultCompareFunction(a, b) { if(a === b) return 0; return a < b? -1: 1; } // 如果a === b 返回true equal(a, b) { return this.compare(a, b) === 0; } // 如果a < b 返回true lessThan(a, b) { return this.compare(a, b) < 0; } // 如果a > b 返回true greaterThan(a, b) { return this.compare(a, b) > 0; } // 如果a <= b 返回true lessThanOrEqual(a, b) { return this.lessThan(a, b) || this.equal(a, b); } // 如果a >= b 返回true greaterThanOrEqual(a, b) { return this.greaterThan(a, b) || this.equal(a, b); } // 反转这个类 的 比较顺序 reverse() { const compareOriginal = this.compare; this.compare = (a, b) => compareOriginal(b, a); }}
// 定义链表节点class LinkedListNode { constructor(value, next = null) { this.value = value; this.next = next; } doSomething(callback) { console.log(this.value); callback && callback(this.value); }}// 定义链表class LinkedList { constructor() { this.head = null; this.tail = null; this.compare = new Comparator(); // 本来可以接受一个比较函数,传进去,但是这里就不做了,没必要 } // 在链表头(this.head)放节点 prepend(value) { // 创建一个节点 const newNode = new LinkedListNode(value, this.head); if(!this.tail) { this.tail = newNode; } return this; } // 在链表尾(this.tail)放节点 append(value) { const newNode = new LinkedListNode(value); if (!this.head) { this.tail = newNode; this.head = newNode; } else { this.tail.next = newNode; this.tail = newNode; } return this; } // 删除节点 delete(value) { if (!this.head) return null; let deleteNodes = []; // 从head开始找,如果一直是这个值,head就一直往下指 while(this.head && this.compare.equal(this.head.value === value)) { deleteNodes.push(this.head); this.head = this.head.next; } // head不是这个值了,就往下找 let currentNode = this.head; // 有可能经过上面的while循环,已经变成空链表 if (currentNode !== null) { while(currentNode.next) { if(this.compare.equal(this.currentNode.next.value, value)) { deleteNodes.push(this.currentNode.next); this.currentNode.next = this.currentNode.next.next; } else { this.currentNode = this.currentNode.next; } } } // tail也要判断,万一等于value,上面的操作,都没有把它删掉过 if(this.compare.equal(this.tail.value, value)) { this.tail = currentNode; } // 最后把删除的节点都返回 return deleteNodes; } // 链表指向反转 reverse() { // 需要用三个指针 let currNode = this.head; let prevNode = null; let nextNode = null; while(currNode) { // 把下一个节点保存起来 nextNode = currNode.next; // 反转currNode指向 currNode.next = prevNode; // 移动prevNode和currNode指针,以便下次反转 prevNode = currNode; currNode = nextNode; } // 记得把head和tail指针,交换位置 this.tail = this.head; this.head = prevNode; return this; }}