一、普通链表
链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和指向下一个元素的引用(也称指针或链接)组成。
创建链表,并实现一些方法:
- push(element): 向链表尾部添加一个新元素。
- insert(element, position): 向链表的特定位置添加一个新元素。
- getElementAt(index): 返回链表中特定位置的元素。如果链表中不存在这样的元素则返回undefined。
- remove(element): 从链表中移除一个元素。
- indexOf(element): 返回元素在链表中的索引。
- removeAt(position): 从链表的特定位置移除一个元素。
- isEmpty(): 如果链表中不包含任何元素,返回true,如果链表长度大于0则返回false。
- size(): 返回链表包含的元素个数,与数组的length属性类似。
- toString(): 返回整个链表的字符串。
// 比较两个值是否相等
function defaultEquals(a, b) {
return a === b;
}
// Node表示要添加到链表中的项
class Node {
constructor(element) {
// element 要加入链表元素的值
this.element = element;
// next 指向链表下一个元素的指针
// 链表最后一个节点的下一个元素始终是undefined或null
this.next = undefined;
}
}
class LinkedList {
constructor(equalsFn = defaultEquals) {
this.count = 0;
this.head = undefined;
this.equalsFn = equalsFn;
}
/* 添加分为两个场景:
* 1. 向空列表添加元素
* 2. 向不为空的链表尾部添加元素
*/
push(element) {
// 把element作为值传入,创建Node项
const node = new Node(element);
// 指向链表current项
let current;
// head元素为undefined或null,表示列表为空
if(this.head == null) {
// 向空列表添加元素,让head指向node,下一个node元素会自动成为undefined
this.head = node;
}else {
// 向一个不为空的链表尾部添加元素
current = this.head;
// 循环访问链表,当current.next元素为undefined或null时,找到链表尾部
while(current.next != null) {
current = current.next;
}
// 将最后一个元素的next指针指向想要添加到链表的节点
current.next = node;
}
this.count++;
}
/* 移除,两种场景:
* 1. 移除第一个元素
* 2. 移除第一个元素之外的元素
*/
removeAt(index) {
// 检查越界值
if(index >= 0 && index < this.count) {
// current作为链表第一个元素的引用
// current是要移除节点的引用
let current = this.head;
// 移除第一项
if(index === 0) {
// 将head指向链表的第二个元素
this.head = current.next;
}else {
// 指向当前元素的前一个元素
let previous;
for(let i&