数据结构 - 循环链表(JavaScript实现)
源码地址
循环链表(CircularLinkedList)
单向循环链表
单向循环链表是在单向链表的基础上,将尾节点的 next 指向 头节点,形成了一个环
初始化
1 2 3 4 5 6 7 8 9 10 11 12
| class CircularLinkedList { constructor(){ this.head = null this.rear = null } node(data){ return { data, next: null } } }
|
基本操作
插入
头部插入
- 如果头节点为空,head 和 rear 都指向新节点node
- 头节点不为空,取出头节点 temp = head
- node.next 指向 temp
- 设置头指针指向新节点node head = node, 设置尾部节点的 next 指向新节点 rear.next = node
1 2 3 4
| 1->2->3->1 0->1->2->3 0->1->2->3->0
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| prepend(data){ let node = this.node(data) if(!this.head){ this.head = node this.rear = node node.next = this.head return node.data } let temp = this.head node.next = temp this.head = node this.rear.next = this.head return node.data }
|
尾部插入
- 取出头尾节点 head,rear,temp = rear
- 新节点 node.next 指向 head
- temp.next 指向新节点 node
- rear 指针指向新节点 node
1 2 3 4
| 1->2->3->1
1->2->3->4 1->2->3->4->1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| append(data){ let node = this.node(data) if(!this.rear){ this.rear = node this.head = node node.next = this.head return node.data } let temp = this.rear node.next = this.head temp.next = node this.rear = node return node.data }
|
指定位置插入
- 找到插入的位置 curr,创建新节点 node,temp = curr.next
- 把 curr.next 指向 node
- 把 node.next 指向 temp
1 2 3 4
| 1->2->4->1 取出 2 创建 3 1->2->3 1->2->3->4->1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| add(el, data){ let curr = this.contains(el) if(!curr) throw null if(curr == this.rear) return this.append(data) let node = this.node(data) let temp = curr.next curr.next = node node.next = temp return node.data }
|
删除
头部删除
- 取出头节点 temp = head,如果节点不存在,返回 null。
- 把 head 的指针 指向原 head.next
- 把 rear.next 指向新的 head
1 2 3
| 1->2->3->1 2->3->1 2->3->2
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| removeHead(){ let temp = this.head if(!temp) return null if(this.head == this.rear) { this.head = null this.rear = null return temp.data } this.head = temp.next this.rear.next = this.head return temp.data }
|
尾部删除
- 取出头节点 head 尾节点 rear ,找出 rear 的前置节点 curr
- 将 curr.next 指向 rear.next
- 把尾指针指向 curr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| removeRear(){ let curr = this.head if(this.head == this.rear) { this.head = null this.rear = null return curr.data } while (curr){ if(curr.next == this.rear) break curr = curr.next } let rear = this.rear curr.next = this.rear.next this.rear = curr return rear.data }
|
指定位置删除
- 判断删除位置是否头节点,还是尾节点,还是中间节点
- 取出 前置节点 curr,通过 curr.next 取出目标节点 node
- curr.next 指向 node.next
1 2 3
| 1->2->3-> 取出 1 2 1->3->1
|
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
| remove(el){ if(!this.head) return null if(this.head.data == el){ let temp = this.head if(this.head == this.rear){ this.head = null this.rear = null return temp.data } this.head = this.head.next this.rear.next = this.head temp.next = null return temp.data } let curr = this.head do { if(curr.next.data == el) break curr = curr.next } while (curr != this.head) if(curr.next == this.rear){ let node = curr.next curr.next = this.head this.rear = curr return node.data } let node = curr.next curr.next = node.next return node.data }
|
查找
- 循环查找,直到 curr 再次等于 head 的时候,跳出循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| contains(el){ if(!this.head) return null let curr = this.head do { if(curr.data === el) break curr = curr.next } while (curr != this.head); if(curr.data != el) return null return curr }
|
遍历
正序遍历
- 从头节点开始循环,直到 curr 再次等于 head 的时候,跳出循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| traverse(callback=(item)=>item){ let res = [] if(!this.head) return res let curr = this.head do { res.push(callback(curr.data)) curr = curr.next } while (curr != this.head); return res }
|
反序遍历
- 取出头节点跟尾节点,反序取出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| reverseTraversal(callback=(item)=>item){ let res = [] if(!this.head) return res let curr = this.rear while(curr != this.head){ let prev = this.head while(prev.next != curr){ prev = prev.next } res.push(callback(curr.data)) curr = prev } res.push(callback(curr.data)) return res }
|
反转
- 步骤跟单链表差不多,但是需要在后面处理尾指针的指向
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
| reverse() { if(!this.head) return null let curr = this.head let next = null let prev = null while(curr){ next = curr.next curr.next = prev prev = curr curr = next } this.head = this.rear this.rear = prev return this }
|
取出中间节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| findMid(){ if(!this.head) return null let search = this.head let mid = this.head do { if(search.next.next != this.head){ search = search.next.next mid = mid.next }else{ search = search.next } } while (search.next != this.head); return mid }
|