链表是常用的数据的一种,链表是节点的组合,节点包括指针和值,当列表为空值,头指针指向 null,链表有单链表和双链表,下面我们针对单链表来展开,首先看下链表的“样子”
链表的代码实现
通过上面的图示,我们知道节点是由值和指针组成,我们通过代码来表示
class Node { constructor(value) { this.value = value; this.next = null; }}
接下来创建链表,链表是有一个 head 指针,size 表示链表的节点个数
class LinkedList { constructor() { this.head = null; this.size = 0; }}
整个链表的结构已经创建好了,我们先了解节点是如何插入和删除的
节点插入图示
插入前
插入后
节点的删除
通过上面图示可以看出,链表节点的插入和删除操作就是操作指针的指向即可
接下来将会对链表新增以下方法,代码很简单,看注释即可
add(value)
往链表新增节点insert(index, value)
指定位置插入节点removeByIndex(index)
指定位置删除节点indexOf(value)
查找目标值的节点下标removeByValue(value)
指定值删除节点pop()
弹出最后一个节点isEmpty()
判断节点是否为空print()
打印链表的值
add(value)
/** * 尾部新增节点 * @param {*} value */add(value) { const node = new Node(value); let curr; if (this.head === null) { // 空链表 this.head = node; } else { // 非空,获取到最后一个节点,更改指向 curr = this.head; while (curr.next) { curr = curr.next; } curr.next = node; } this.size += 1;}
insert(index, value)
/** * 指定位置插入节点 * @param {*} index * @param {*} value * @returns */insert(index, value) { if (index < 0 || index > this.size - 1) { return false; } else { const node = new Node(value); let prev, curr = this.head; // 头部插入 if (index === 0) { node.next = curr; } else { // 非头部插入,查找到节点,改变指针指向 while (index > 0) { prev = curr; curr = curr.next; index -= 1; } prev.next = node; node.next = curr; } this.size += 1; }}
removeByIndex(index)
/** * 通过下标移除节点 * @param {*} index * @returns */removeByIndex(index) { if (index < 0 || index > this.size - 1) { return; } let prev, curr = this.head; if (index === 0) { this.head = curr.next; } else { // 遍历获取指定下标的节点 while (index > 0) { prev = curr; curr = curr.next; index -= 1; } prev.next = curr.next; } this.size -= 1; return curr.value;}
indexOf(value)
/** * 查找目标值的节点下标 * @param {*} value * @returns */indexOf(value) { // 未找到返回-1 let index = 0; let curr = this.head; while (curr) { if (curr.value === value) { // 找到了直接退出循环 return index; break; } curr = curr.next; index += 1; } return -1;}
removeByValue(value)
/** * 通过值移除节点 * @param {*} value * @returns */removeByValue(value) { const index = this.indexOf(value); return this.removeByIndex(index);}
pop()
/** * 删除尾部节点 */pop() { let prev, curr = this.head; // 空链表,直接返回null if (this.size === 0) return null; if (!curr.next) { // 只有一个节点的情况 this.head = null; } else { while (curr.next) { prev = curr; curr = curr.next; } prev.next = null; } this.size -= 1;}
isEmpty()
/** * 判断是否为空 */isEmpty() { return this.size === 0;}
print()
/** * 打印链表的值 */print() { const arr = []; let curr = this.head; while (curr) { arr.push(curr.value); curr = curr.next; } console.log(arr.join('->'))}
结果测试
最后我们测试下结果
const linkList = new LinkedList();linkList.add(1);linkList.add(5);linkList.add(8);linkList.print(); // 1->5->8linkList.insert(2, 4);linkList.print(); // 1->5->4->8console.log(linkList.indexOf(5)); // 1console.log('remove value is ' + linkList.removeByIndex(1)); // remove value is 5linkList.print(); // 1->4->8console.log('remove value is ' + linkList.removeByIndex(8)); // remove value is undefinedlinkList.print(); // 1->4->8linkList.removeByValue(4);linkList.print(); // 1->8linkList.pop();linkList.print(); // 1linkList.insert(0, 32);linkList.print(); // 32->1linkList.insert(1, 44);linkList.print(); // 32->44->1linkList.removeByValue(32);linkList.print(); // 44->1linkList.removeByValue(1);linkList.print(); // 44linkList.removeByValue(44);linkList.print(); // 空console.log(linkList.isEmpty()) // true