前端知识体系
GitHub (opens new window)

GuoLiBin6

程序员永不下班
GitHub (opens new window)
  • 介绍
  • 前端基础

  • 浏览器基础

  • 软件开发

  • 数据结构

    • 栈
    • 队列
    • 链表
      • 介绍
      • 代码实现
        • 单链表
        • 双链表
  • 性能优化

  • Node.js

  • 收录

  • 搞事啦

  • 前端知识体系
  • 数据结构
GuoLiBin6
2022-07-03
目录

链表

# 介绍

链表是一种以列表存储值的数据结构,在列表中每一个值都被当作为一个节点,每一个节点都通过指针与列表的下一个值关联(若该节点是列表最后一个元素则下一个值为 null)。

有两种链表:单链表和双链表。两种链表的运作方式类似,但是在单链表中每一个节点有单指针指向下一个节点,在双链表中,每一个节点有双指针,一个指向下一个节点,一个指向上一个节点。

列表的第一个元素被当作头,列表的最后一个元素被当作尾。和数组一样,列表的长度由列表中的元素个数决定。

列表和数组主要不同包括:

  • 列表没有索引,列表中的每一个值仅“知道”其通过指针连接到的值。
  • 因为列表没有索引,所以我们不能随机访问列表中的元素。当我们想要访问一个值,必须通过从头到尾遍历整个列表的方法。
  • 没有索引的好处是添加或删除列表中任意部分比在数组中更高效。我们只需要重新分配指针指向的“相邻”值,但是在数组中,我们需要重新分配余下所有值的索引。

和其他所有数据结构一样,可以采用不同的方法来操作以链表存储的数据。通常会使用:push(在尾部添加)、pop(在尾部删除)、unshift(在头部添加)、shift(在头部删除)、get(获取)、set(设置)、remove(删除)和 reverse(反转)。

# 代码实现

# 单链表

function Node(element){ 
    this.element = element; 
    this.next = null; 
} 
function List(){ 
    this.head = new Node('head'); 
    this.find = find; 
    this.insert = insert; 
    this.display = display; 
    this.findPrevious = findPrevious;
    this.remove = remove;
} 
function find(item){ 
    let currNode = this.head; 
    while(currNode.element!==item){ 
        currNode = currNode.next; 
    } 
    return currNode; 
} 
function insert(newElement, item){ 
    let newNode = new Node(newElement); 
    var currNode = this.find(item); 
    newNode.next = currNode.next; 
    currNode.next = newNode; 
} 
function display(){ 
    let currNode = this.head; 
    while(currNode.next!=null){ 
        console.log(currNode.next.element); 
        currNode = currNode.next; 
    } 
} 
function findPrevious (item){ 
    let currNode = this.head; 
    while(currNode.next!=null && currNode.next.element!=item){ 
        currNode = currNode.next; 
    } 
    return currNode; 
} 
function remove(item){ 
    let prevNode = this.findPrevious(item); 
    let currNode = this.find(item); 
    if(currNode.next!=null){ 
        prevNode.next = currNode.next; 
        currNode.next = null; 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 双链表

function Node (val) {
  // 每一个节点包含三个属性,其值,一个指向上一个节点的指针,一个指向下一个节点的指针
  this.val = val;
  this.next = null;
  this.prev = null;
}

function DoublyLinkedList () {
  // 列表有三个属性,头,尾和列表的大小
  this.head = null
  this.tail = null
  this.length = 0

  this.push = push
  this.pop = pop
  this.shift = shift
  this.unshift = unshift
  this.get = _get
  this.set = _set
  this.insert = insert
  this.toString = toString
}

// push 方法将值作为参数并赋值给链表尾
function push(val) {
  const newNode = new Node(val)
  if (this.length === 0) {
    this.head = newNode
    this.tail = newNode
  } else {
    this.tail.next = newNode
    newNode.prev = this.tail
    this.tail = newNode
  }
  this.length++
  return this
}
// pop 方法删除链表尾
function pop() {
  if (!this.head) return undefined
  const poppedNode = this.tail
  if (this.length === 1) {
    this.head = null
    this.tail = null
  } else {
    this.tail = poppedNode.prev
    this.tail.next = null
    poppedNode.prev = null
  }
  this.length--
  return poppedNode
}
// shift 方法删除链表头
function shift() {
  if (this.length === 0) return undefined
  const oldHead = this.head
  if (this.length === 1) {
    this.head = null
    this.tail = null
  } else {
    this.head = oldHead.next
    this.head.prev = null
    oldHead.next = null
  }
  this.length--
  return oldHead
}
// unshift 方法将值作为参数并赋值给链表头
function unshift(val) {
  const newNode = new Node(val)
  if (this.length === 0) {
    this.head = newNode
    this.tail = newNode
  } else {
    this.head.prev = newNode
    newNode.next = this.head
    this.head = newNode
  }
  this.length++
  return this
}
// get 方法将索引作为参数并返回链表对应索引的值
function _get(index) {
  if (index < 0 || index >= this.length) return null
  let count, current
  if (index <= this.length / 2) {
    count = 0
    current = this.head
    while (count !== index) {
      current = current.next
      count++
    }
  } else {
    count = this.length - 1
    current = this.tail
    while (count !== index) {
      current = current.prev
      count--
    }
  }
  return current
}
// set 方法将索引和值作为参数,修改链表中索引所在的节点值为传入的参数值
function _set(index, val) {
  var foundNode = this.get(index)
  if (foundNode != null) {
    foundNode.val = val
    return true
  }
  return false
}
// insert 方法将索引和值作为参数,将值插入链表响应索引位置
function insert(index, val) {
  if (index < 0 || index > this.length) return false
  if (index === 0) return !!this.unshift(val)
  if (index === this.length) return !!this.push(val)

  var newNode = new Node(val)
  var beforeNode = this.get(index - 1)
  var afterNode = beforeNode.next

  beforeNode.next = newNode, newNode.prev = beforeNode
  newNode.next = afterNode, afterNode.prev = newNode
  this.length++
  return true
}

function toString() {
  let arr = []
  let current = this.head
  do {
    arr.push(current.val)
    current = current.next
  } while (current)
  console.log(arr.join('->'))
}

const list = new DoublyLinkedList()
list.push(1)
list.push(3)
list.push(2)
list.insert(2, 'xx')
list.push(5)
list.toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
上次更新: 2023-12-23 01:22:36
队列
预加载

← 队列 预加载→

最近更新
01
蛤蟆先生去看心理医生
04-12
02
梁永安:阅读、游历和爱情
03-20
03
阿甘正传
02-07
更多文章>
Theme by Vdoing | Copyright © 2022-2024 GuoLiBin6
冀ICP备2022013865号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式