含义
多个元素组成的列表,元素存储不连续,通过 next 指针来链接, 最底层为 null
就类似于 父辈链接关系 吧, 比如: 你爷爷的儿子是你爸爸,你爸爸的儿子是你,而你假如目前还没有结婚生子,那你就暂时木有儿子
链表的优缺点
因为链表是一种 松散 的结构体,所以当你想要找到其中的某一个节点时,只能够从 头节点 一级一级的往下找,但也因为这种松散的结构使得其进行 插入 和 删除 时只需要改变其 指针域 的指向即可
优点:适合动态插入和删除的应用场景 缺点:不能快速的定位和随机访问数据
数组和链表的对比总结
- 数组和链表都是线性数据结构
- 数组为静态结构,静态分配内存。链表支持动态分配内存
- 数组在数据储存时是一段连续的内存空间,链表是非连续的通过指针来串联
- 数组可以根据下标定位快速查找,链表则需要遍历查找
- 数组在插入和删除时会有大量的数据移动补位,链表只需要改变指针指向
js中类似于链表的典型就是原型链, 但是js中没有链表这种数据结构,我们可以通过一个object来模拟链表
const a = {
val: "a"
}
const b = {
val: "b"
}
const c = {
val: "c"
}
const d = {
val: "d"
}
a.next = b;
b.next = c;
c.next = d;
// const linkList = {
// val: "a",
// next: {
// val: "b",
// next: {
// val: "c",
// next: {
// val: "d",
// next: null
// }
// }
// }
// }
// 遍历链表
let p = a;
while (p) {
console.log(p.val);
p = p.next;
}
// 插入
const e = { val: 'e' };
c.next = e;
e.next = d;
// 删除
c.next = d;
合并两个有序链表
// 时间复杂度O(n) n为链表1和链表2的长度之和
// 空间复杂度O(1)
var mergeTwoLists = function (list1, list2) {
const res = {
val: 0,
next: null
}
// 指向新链表的指针
let p = res;
// 建立两个指针
let p1 = list1;
let p2 = list2;
while(p1 && p2) {
if(p1.val < p2.val) {
p.next = p1
p1 = p1.next
}else {
p.next = p2
p2 = p2.next
}
// p永远要往后移动一位
p = p.next;
}
if(p1) {
p.next = p1
}
if(p2) {
p.next = p2
}
return res.next;
};
删除排序链表中的重复元素
// 1 -> 1 -> 2 -> 3 -> 3
// 1 -> 2 -> 3 -> null
// 时间复杂度 O(n) n为链表的长度
// 空间复杂度 O(1)
const deleteDuplicates = (head) => {
// 创建一个指针
let p = head;
// 遍历链表
while (p && p.next) {
// 如果当前节点的值等于下一个节点的值
if (p.val === p.next.val) {
// 删除下一个节点
p.next = p.next.next
} else {
// 否则继续遍历
p = p.next
}
}
// 最后返回原来链表
return head
}
反转链表
// 1 -> 2 -> 3 -> 4 -> 5 -> null
// 5 -> 4 -> 3 -> 2 -> 1 -> null
// 时间复杂度 O(n) n为链表的长度
// 空间复杂度 O(1)
var reverseList = function (head) {
// 创建一个指针
let p1 = head;
// 创建一个新指针
let p2 = null;
// 遍历链表
while (p1) {
// 创建一个临时变量
const tmp = p1.next;
// 将当前节点的下一个节点指向新链表
p1.next = p2;
// 将新链表指向当前节点
p2 = p1;
// 将当前节点指向临时变量
p1 = tmp;
}
// 最后返回新的这个链表
return p2;
}
reverseList(list)
删除链表中的节点
// 时间复杂和空间复杂度都是 O(1)
const deleteNode = (node) => {
// 把当前链表的指针指向下下个链表的值就可以了
node.val = node.next.val;
node.next = node.next.next
}
instanceOf
const myInstanceOf = (A, B) => {
// 声明一个指针
let p = A;
// 遍历这个链表
while (p) {
if (p === B.prototype) return true;
p = p.__proto__;
}
return false
}
myInstanceOf([], Object)
单向链表
class neNode {
constructor(data) {
this.data = data;
this.next = null;
}
}
// 实现一个单项链表
class singleLinkedList {
constructor() {
this.head = null;
}
// 添加节点
add(data) {
let node = new neNode(data);
if (this.head === null) {
this.head = node;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
}
// 插入节点
insert(data, target) {
let node = new neNode(data);
let current = this.head;
while (current.next) {
if (current.data === target) {
node.next = current.next;
current.next = node;
break;
}
current = current.next;
}
}
// 查找节点
find(data) {
let current = this.head;
while (current) {
if (current.data === data) {
return current;
}
current = current.next;
}
return null;
}
// 删除节点
remove(data) {
let current = this.head;
let previous = null;
while (current) {
if (current.data === data) {
if (previous === null) {
this.head = current.next;
} else {
previous.next = current.next;
}
return true;
}
previous = current;
current = current.next;
}
return false;
}
}
const list = new singleLinkedList();
list.add(1);
list.add(2);
list.add(3);
list.insert(4, 2);
console.dir(list, { depth: null });