目录
- 前言
- 我的思路
- 思路一 (哈希表记录链表的访问):
- 思路二 (双指针,快指针在前,慢指针在后):
- 我的代码
- 运行结果
前言
前几天我写的代码,都是把所有的内容写在main函数里,没有体现CPP面向对象的特性,我感觉很不好,所以接下来我的代码都会设计类,把不同的功能封装在类的成员函数里面。
我的思路
思路一 (哈希表记录链表的访问):
其实我最开始的思路就是设置一个visit数组
,大小为100,但是这里需要链表里面存储的data是不超过99的,这样我就能通过visit[Lnode->data]
在O(1)
的时间复杂度里面快速判断这个数组有没有被访问过。如果遍历到一个被访问过的结点,那就说明这个链表有环。
思路二 (双指针,快指针在前,慢指针在后):
这个思路最开始我没想到,参考了教程。其实原理就在于:
设想有两个人在操场上面跑步,一个人跑的比另外一个人快,那么最后快的肯定能追上慢的,这个时候快的已经比慢的领先一圈了。
我们考虑用双指针来实现,一个指针一步一步的走,一个指针两步两步的走。最后如果这两个指针能重合,那么就说明有环。
值得注意的是,这里的判断条件稍微有点复杂,null->next,cpp是会报错的
。
- 为什么要这样设置?
- 看这里 小浩算法–题解–环形链表
我的代码
#include<iostream>
#include <unordered_map>
using namespace std;
typedef struct Lnode {
int data;
struct Lnode* next;
Lnode(int val) :
data(val), next(NULL) {
}
};
class LinkedList {
private:
Lnode* head;
Lnode* rear;
int node_num;
public:
LinkedList() : head(nullptr),rear(head) {
cout << "请输入链表的结点总数" << endl;
cin >> this->node_num;
int nodeData;
//把链表的总长度存储在头结点的数据域
head = new Lnode(node_num);
Lnode* p = head;
Lnode* q;
for (int i = 0; i < node_num; i++) {
cin >> nodeData;
q = new Lnode(nodeData);
p->next = q;
p = p->next;
}
p = head->next;
//输出生成的链表
cout << "您已经生成如下链表: " << endl;
while (p->next != NULL) {
cout << p->data << " -> ";
p = p->next;
}
cout << p->data<<endl;
rear = p;
}
~LinkedList() {
Lnode* current = head;
while (current != rear->next && current != nullptr) {
Lnode* next = current->next;
delete current;
current = next;
}
}
void append(int val) {
rear->next = new Lnode(val);
rear = rear->next;
}
void generateRing(int x) {
Lnode* ring_place = head;
while (x-- != 0) {
ring_place = ring_place->next;
}
rear->next = ring_place;
}
void print_ring_des() {
cout << "环的终点是:" << rear->next->data << endl;
}
//根据哈希表来判断是否是个环
void check_Ring() {
Lnode* p = head;
unordered_map<Lnode*, int> m;
while (p != nullptr) {
// 如果当前节点已存在于map中,则表示存在环
if (m.find(p) != m.end()) {
cout << "========哈希表结果:================" << endl;
cout << "链表存在环!" << endl;
return;
}
// 将当前节点加入map
m[p] = 1;
p = p->next;
}
// 遍历结束,未发现环
cout << "========哈希表结果:================" << endl;
cout << "链表不存在环!" << endl;
}
/// <summary>
/// 利用双指针跑圈来判断是否有环,一个跑慢点(每次遍历1一个),一个跑快点(每次遍历2个)
/// </summary>
void check_Ring_2() {
Lnode* slow = head, *fast = head->next;
while (fast->next != nullptr && slow != fast &&fast != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
if (slow == fast) {
cout << "=======双指针跑圈结果:=================" << endl;
cout << "链表存在环!" << endl;
}
else {
cout << "=======双指针跑圈结果:=================" << endl;
cout << "链表不存在环!" << endl;
}
}
};
int main() {
LinkedList Llist;
Llist.generateRing(2);
Llist.print_ring_des();
Llist.check_Ring();
Llist.check_Ring_2();
}
运行结果