概述
今天看到一道有意思的算法题: 如何判断一个链表是否存在环,如果存在环,如何获取环的位置。先抛开问题,j假设我现在实现了算法,我该如何验证我的算法是否正确呢?
当然可以在力扣上面直接找到对应的题目,直接验证就行了。但是我内心实在好奇,于是准备自己创建一个有环链表,于是有了本文。。。。
一、什么是有环链表
所谓有环的链表,就是链表到一定长度以后,将尾指针指向中间的某一个位置的操作。如图所示:
我们如何来创建这样一个链表呢?接着往下吧。。。。
二、问题分析
先进行简单的需求分析:
我准备实现一个类去完成它
1. 数据成员:
- index 头节点到环的距离 重要
- circleLegth 环的周长 重要
- head 链表的头指针(返回值)
- tail 链表构造过程采用尾插法,需要一个尾指针
2. 方法成员
- 构造函数,接受三个参数 ,函数签名是
(value,index,circleLegth)=>list
,value
是初始节点的值。head
和tai
l 都指向它。然后初始化这个链表。有环链表的总长度为index + circleLength
- addTail (核心方法)按照前面的规则,往创建好的方法中加入一个节点,如果链表节点数已经到达index + circleLength, 就循环链表中的环,更改对应节点的数据为新的value
3. 实现:
思路在代码注释中中有很详细的解释。主要分为四个阶段
阶段一:通过构造函数初始化链表。
阶段二: 往链表中加入 节点从
0
到index
这一段阶段三: 往链表中加入 节点从
index
到index+circleLength
这一段阶段四: 遍历循环这个环,用新的
value
更新环形链表的值。
js
class Node {
value = undefined;
next = null;
constructor(value) {
this.value = value;
}
}
class List {
head = null;
tail = null;
entry = null;
constructor(value, index = 3, circleLength = 5) {
const node = new Node(value); // 初始节点
this.head = node; // 头指针
this.tail = node; // 尾指针
this.index = index; // 头节点到入口的距离
this.circleLength = circleLength; // 环的长度
}
addTail(value) {
// 计数头节点到入口这一段距离
if (this.index >= 0) this.index--;
// 如果链表的头节点到环入口这一段链表已经完成,就开始计数环的长度
if (this.index === -1 && this.circleLength >= 0) this.circleLength--;
// 只要环还没有达到指定的长度(this.circleLength 还没有减为0),就可以一直新增节点
if (this.circleLength > 0) { // 阶段二、三
this.tail.next = new Node(value);
this.tail = this.tail.next;
}
//如果链表达到环的入口,用entry 记录入口的位置
if (this.index === 0) this.entry = this.tail; //阶段二结束
// 如果环的长度也够了,就把尾指针指向入口处
if (this.circleLength === 0) {
this.tail.next = this.entry; //阶段三结束
}
// circleLength 等于-1 ,说明链表环的长度也完成了,不用再新建节点,更新链表就行了
if (this.circleLength === -1) {
this.tail.next.value = value; // 阶段四
this.tail = this.tail.next;
}
}
// 用于测试
print() {
let p = this.head;
for (let i = 0; i < 40; i++) {
console.log(p.value);
p = p.next;
}
}
}
四、测试
链表的总长度的 8 ,插入 20 个数据
js
const list = new List(0);
for (let i = 1; i < 20; i++) {
list.addTail(i);
}
// 测试
list.print();
运行结果:
分析结果:
- 0,1,2 是链表的index 部分,index 长度是3 ,符合预期
- 15,16,17,18,19,是链表的环形部分,长度是5 ,符合预期
撒花,大功告成!!!!