循环链表 - 使用JavaScript封装
我学习了一生,现在我还在学习,而将来,只要我还有精力,我还要学习下去。” —— 别林斯基
目录
- 循环链表:
- 封装循环链表 - js:
- 应用场景:
循环链表:
循环链表和链表之间唯一的区别在于,最后一个元素指向下一个元素的指针不是引用undefined,而是指向第一个元素 head。
图为千锋教育所截,侵权联系删除。
封装循环链表 - js:
这里封装的循环链表还是继承了之前写的单链表。。。
<script>
class Node {
constructor(element) {
this.element = element;
this.next = null;
}
}
class LinkedList {
// #
constructor() {
this.count = 0;
this.head = null;
}
// push 添加一个节点
push (element) {
const node = new Node(element);
// header是空
if (this.head === null) {
this.head = node;
} else {
let current = this.head;
while (current.next !== null) {
current = current.next;
}
current.next = node;
}
this.count++;
}
// 指定位置删除 传入索引
removeAt (index) {
if (index >= 0 && index < this.count) {
let current = this.head;
if (index == 0) {
this.head = this.head.next;
} else {
let previous;
for (let i = 0; i < index; i++) {
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.count--;
return current.element;
}
return;
}
// 指定位置删除-方法二利用getNodeAt(index) 传入索引
removeAt2 (index) {
if (index >= 0 && index < this.count) {
let current = this.head;
if (index == 0) {
this.head = this.head.next;
} else {
let previous = this.getNodeAt(index - 1);
current = previous.next;
previous.next = current.next;
}
this.count--;
return current.element;
}
return;
}
// 根据索引获得节点node
getNodeAt (index) {
if (index >= 0 && index < this.count) {
let node = this.head;
for (let i = 0; i < index; i++) {
node = node.next;
}
return node;
}
return;
}
// 判断是否相等
equalFn (a, b) {
// 暴力写法:
// 也有缺陷 JSON.stringify({a:1,b:2}) !== JSON.stringify({b:2,a:1})
return JSON.stringify(a) === JSON.stringify(b);
// 可以使用第三方库
}
// 根据元素返回索引
indexOf (element) {
let current = this.head;
for (let i = 0; i < this.count; i++) {
if (this.equalFn(current.element, element)) {
return i;
}
current = current.next;
}
}
// 直接根据值删除
remove (element) {
// 根据数据返回索引的方法
const index = this.indexOf(element);
return this.removeAt(index);
}
// 指定位置插入内容
insert (element, index) {
if (index >= 0 && index <= this.count) {
const node = new Node(element);
if (index == 0) {
const current = this.head;
node.next = current;
this.head = node;
} else {
const previous = this.getNodeAt(index - 1);
const current = previous.next;
previous.next = node;
node.next = current;
}
this.count++;
return true;
}
return false;
}
// 判断是否为空
isEmpty () {
return this.size() === 0;
}
// 判断长度
size () {
return this.count;
}
// 返回链头
getHead () {
return this.head;
}
}
</script>
<script>
class CirularLinkedList extends LinkedList {
constructor() {
super()
}
push (element) {
const node = new Node(element);
let current;
if (this.head === null) {
this.head = node;
} else {
current = this.getNodeAt(this.size() - 1);
current.next = node;
}
node.next = this.head;
this.count++;
}
insert (element, index) {
if (index >= 0 && index <= this.count) {
const node = new Node(element);
let current = this.head;
if (index === 0) {
if (this.head === null) {
this.head = node;
node.next = this.head;
} else {
node.next = current;
current = this.getNodeAt(this.size() - 1);
this.head = node;
current.next = this.head;
}
} else {
const previous = this.getNodeAt(index - 1);
node.next = previous.next;
previous.next = node;
}
this.count++;
return true;
}
return false;
}
removeAt (index) {
if (index >= 0 && index < this.count) {
let current = this.head;
if (index === 0) {
if (this.size() === 1) {
this.head = null;
} else {
let last = this.getNodeAt(this.size() - 1);
this.head = this.head.next;
last.next = this.head;
}
} else {
const previous = this.getNodeAt(index - 1);
current = previous.next;
previous.next = current.next;
}
this.count--;
return current.element;
}
return;
}
}
var list = new CirularLinkedList()
</script>
应用场景:
- 循环遍历:可以从任意节点开始遍历整个链表,无需额外的条件判断。
- 动态数据结构:循环链表可以根据需要动态增长或缩小,不需要事先定义大小。
- 非连续存储:节点在内存中不必连续存储,每个节点通过指针连接。
- 插入和删除效率高:在循环链表中插入或删除节点的时间复杂度为O(1),只需调整指针即可。