海阔凭鱼跃,天高任鸟飞。Hey 你好!我是秦爱德。😄
之前看过这样一个问题“既然曾经有数组了, 为什么还要链表?”
其实链表和数组各有千秋,都在不同的业务场景中发光发热,很多同学对链表可能是既相熟又生疏。相熟的是,咱们在刷一些八股文的时候常常会看到“链表”这个字眼,生疏的是,咱们在平时的开发中并不会太多的应用到链表。
那么咱们就来带着问题理解一下啥是链表,既然曾经有数组了, 为什么还要链表?
数据结构的概念?
咱们来把看起来艰涩难懂的专业术语拆分一下:
数据:对应的就是数据类型,在 js 中蕴含了 根本数据类型 和援用数据类型
构造:将一堆各种各样的数据依照不同的逻辑排列组合最终存储到计算机内存当中
总结:咱们把数据的各种逻辑组成,在计算机中的存储构造以及各种操作的算法设计叫做数据结构
算法和数据结构的关系
算法是建设在数据结构之上,对数据结构的操作须要用算法来形容;算法设计依赖数据的逻辑构造,算法的实现依赖数据的存储构造
- 常见的数据结构
数组、字典、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树
- 常见的算法
递归、排序、二分查找、搜寻、哈希算法、贪婪算法、分治算法、回溯算法、动静布局、字符串匹配算法等
什么是数组构造
1. 数组的定义
数组是若干个元素依照顺序排列寄存的一个汇合,并且每个元素至多存在一个 索引 (index) 或者 关键字(key) 所标识,每个元素的地位都能够通过计算索引拿到
为什么说每个元素至多有一个索引呢,那是因为数组能够是多维度的
然而咱们在日常工作中个别罕用的是一维数组,也能够称之为 线性数组
一维数组:[1,2,3]; // 数组的每一个元素是一个数据类型
二维数组:[["a","b","c"],[1,2,3],123]; // 数组的每一个元素是一个一维数组
三维数组:[[["a","b","c"],[1,2,3]],[["a","b","c"],[1,2,3]]]; // 数组的每一个元素是一个二维数组
2. 数组的优缺点
数组作为咱们工作中最为常见的一种数据结构,其最大的个性莫过于高效的 查问 数据
然而其毛病也是十分的显著,在进行 插入 和 删除 数据时,须要进行大量的数据挪动补位耗费大量的工夫
什么是链表构造
1. 链表的定义
链表构造其实是内存外部的一种存储形式,链表则是把一系列节点串联起来,每个节点上至多蕴含两个局部:数据域 与 指针域
数据:保留数据
指针:指向下一个节点的援用
链表中的每个节点,通过指针域的值,造成一个线性构造
2. 链表的优缺点
因为链表是一种 涣散 的构造体,所以当你想要找到其中的某一个节点时,只可能从 头节点 一级一级的往下找,但也因为这种涣散的构造使得其进行 插入 和 删除 时只须要扭转其 指针域 的指向即可
长处:适宜动静插入和删除的利用场景 毛病:不能疾速的定位和随机拜访数据
数组和链表的比照总结
- 数组和链表都是线性数据结构
- 数组为动态构造,动态分配内存。链表反对动静分配内存
- 数组在数据贮存时是一段间断的内存空间,链表是非间断的通过指针来串联
- 数组能够依据下标定位疾速查找,链表则须要遍历查找
- 数组在插入和删除时会有大量的数据挪动补位,链表只须要扭转指针指向
js 中链表的实现
不同于 new Array()
、new Set()
、new Map()
等数据结构,目前 js
官网还没有为咱们提供一个间接的 链表 API
实现。不过咱们能够通过对象的形式去模拟出一个 链表
链表能够分为三类:
- 单向链表:线型数据结构,指针指向下一个节点,起点指向 null
- 双向链表:能够往前或者往后增加节点,指针指向前一个节点和后一个节点
- 循环链表:循环链表的第一个节点指向最初一个节点,最初一个节点指向第一个节点(循环链表又能够划分为“单向循环链表”和“双向循环链表”)
对象化链表之后,链表的出现是这个样子
// 链表对象化,便于了解
const obj = {
data: 1,
next: {
data: 2,
next: {
data: 3,
next: null,
},
},
};
链表的插入
当咱们须要向链表中插入一个节点时,只须要将须要插入中央的 上一个节点 指向本人,并且将 以后节点 指向下一个节点就实现了
链表的删除
当咱们想要删除链表中一个节点时,只须要将指标节点的 上一个节点 指向以后节点的 下一个节点 ,并且将指标节点指向到null
实现开释,就能够实现一个删除操作
实现一个单向链表
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});
打印后果为:
感激
欢送关注我的集体公众号前端有猫腻每天给你推送陈腐的优质好文。回复“福利”即可取得我精心筹备的前端常识大礼包。愿你一路前行,眼里有光!
感兴趣的小伙伴还能够加我微信:yuyue540880 拉你进群,一起交换前端技术,一起游玩!