单向链表
链表和数组一样,都可以用于存储一系列的元素。链表的每个结点(最后一个结点除外)由一个存储元素本身的结点的数据和一个指向下一个元素的引用(指针)组成。
这有点类似于一个火车,火车的每节车厢都装着自己的东西并连接着下一节车厢(最后一节车厢除外)。
链表通常有一个head 属性(头指针)一直指向第一个结点,最后一个结点指向 null
数组与链表的对比
数组
- 内存中是一块连续的空间,一般需要提前分配固定的空间大小,空间利用率不高
- 在数组的起始位置插入和删除数据效率低,改变一个数据需要移动后续所有的数据
- 随机访问的效率高,查找速度快
链表
- 空间是分散的不连续的,空间利用率高
- 任意位置的插入和删除数据的效率较高
- 查找效率低,每次查找都需要从头结点开始查找
常见操作
- push(data):向链表尾部添加新的结点
- getNode(position):根据位置返回相应的结点(从0开始)
- indexOd(data):根据结点返回对应的位置,没有则返回 -1
- insert(data, position):向链表的特定位置插入数据
- updateByData(data, newData):通过数据修改数据
- updateByPosition(position, newData):通过下标修改数据
- toString(separator = ’ '):将所有的数据输出,默认分割方式为空格
- isEmpty():是否为空
- size():大小
单向链表的封装
结点的定义
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
属性的定义
constructor() {
this.length = 0;
this.head = null;
}
push方法
// 向链表末尾添加数据
push(data) {
const newNode = new Node(data);
let current = this.head;
// 判断第一个结点是否为空
if (this.length === 0) {
this.head = newNode;
} else {
// 第二个结点不为空,则找到最后一个结点
while (current.next) {
current = current.next;
}
// 找到后将next 指向新的结点
current.next = newNode;
}
this.length++;
}
toString方法
toString(separator = ' ') {
// separator:分割符,数据之间以什么符号进行分割,默认空格
let str = '';
let temp = this.head;
while (temp) {
str += temp.data;
if (temp.next) {
str += separator
}
temp = temp.next;
}
return str;
}
insert方法
insert(data, position) {
if (position < 0 || position > this.length) {