Skip to main content

链表

什么是链表?

链表是由一组节点组成的集合。每一个节点都使用一个对象的引用指向它的后续节点。指向另外一个节点的引用叫做链。(这个描述有点不能恍然大悟 😒)

为什么叫链表, 其实就和链子一样后面的一节挂在上一节后面 来看一下链表结构

链表的每个节点由元素(el),指针(next)组成

next 指向下一个元素,下个元素的 next 指向下一个元素... 直到最后 next 为 null

{
el:"0",
next: {
el: "1",
next:{
el: "2",
next: {
.......
next: null // 链尾为null 结束
}
}
}
}

列表分为

  • 单项列表
  • 双向列表
  • 循环列表

单项列表

单项链表特点

  • 用一组任意的内存空间去存储数据元素(这里的内存空间可以是连续的,也可以是不连续的)
  • 每个节点(node)都由数据本身和一个指向后续节点的指针组成
  • 整个链表的存取必须从头指针开始,头指针指向第一个节点
  • 最后一个节点的指针指向空(NULL)

单项链表实现

链表中的主要操作

  • 创建节点
  • 插入节点
  • 搜索/遍历节点
  • 删除节点
  • 获取最后节点

初始化节点

  • 指针指向空
  • 存储数据
class Node {
constructor(el) {
this.el = el;
this.next = null;
}
}

初始化链表

  • head 链表
  • length 链表长度
class linkedList {
constructor() {
this.head = null;
this.length = 0;
}
}

创建节点

  • append 方法

append(el) {
const node = new Node(el)
if(this.head === null) {
this.head = node
} else {

let current = this.head
while(current.next) {
current = current.next
}
current.next = node;

}

this.length++
}


插入节点

  • 头部插入
  • 中间插入

头部插入

    appHead(el) {
const node = new Node(el);
if(this.head){
const current = this.head
node.next = current
}

this.head = node;

this.length++

}

中间插入

  • 指定位置插入节点时候 当前插入位置必须在链表范围内
  • 获取当前节点将当前节点 next 设置到新节点 node.next。将 新节点 node 设置当前节点 next

insert(position, el) {

// 插入元素必须在链表范围内
if(position<0 || position > this.length) return false

// 如果是第一位 走 头部插入
if(position === 0) this.appHead(el) return;

let previous = null // 上一个节点
let current = this.head // 当前节点
let index = 0
while(index++< position) {

previous = current
current = current.next

}
node.next = current
previous.next = node
this.length++


}

搜索节点

  • 位置搜索
  • 节点搜索

位置搜索

返回搜索到的节点

    searchPosition(position) {
// 节点必须在链表范围内
if(position < 0 || position > this.length) return null;
let current = this.head
while(position--) {
current = current.next
}

return current
}

节点搜索

通过节点元素进行查询


find(el) {

let current = this.head

// 判断 当前节点 元素 是否登录查询节点元素 current 为空表示 该链表不存在该查询节点
while (current !== null && current.el != el) {
current = current.next
}
return current

}

删除节点

  • 删除指定节点

  • 找到当前节点 移动当前节点 next 到 上一个节点 next

    delete(position) {
// 节点必须在链表范围内
if(position < 0 || position > this.length) return false;

let previous = null
let current = this.head
let index = 0
while(index++ < position) {
previous = current
current = current.next
}

previous.next = current.next
this.length--
}

获取最后节点

    // 获取最后一个节点
findLast() {
let current = this.head;

while (current.next) {
current = current.next;
}

return current;
}

双向列表

单向列表值节点永远指向一个方向,那双向列表就是节点同时能够指向两侧。也是是一个节点同时存在上指针(指向上一个节点)和下指针(指向下节点)

节点结构

双向链表的节点对于单项列表节点就多了一个上指针(prev)

{   prev: null,  // 上指针
el: el,
next: null // 下指针
}

双向链表实现

class Node {
constructor(el) {
this.prev = null;
this.el = el;
this.next = null;
}
}
class DoubleLinkedList {
constructor() {
this.head = null;
this.length = 0;
}

append(el) {
let node = new Node(el);
let previous = null;
let current = this.head;
if (this.head) {
while (current.next) {
current = current.next;
}
}

current.next = node;
node.prev = current;
this.length++;
}
}

...

循环列表

  • 单循环列表

单循环列表

单循环列表 就是将链表的尾部指向链表的头部这样就形成了循环