链表——环形链表I

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

判断链表是否有环最优解法是快慢指针法(龟兔赛跑算法),时间复杂度O(n),空间复杂度O(1),不需要额外的哈希表存储节点。

核心思路

  1. 定义两个指针:慢指针slow(每次走一步)、快指针fast(每次走2步)
  2. 两个指针同时从头节点出发
  3. 如果链表有环,快指针最终会在环内追上慢指针(相遇)
  4. 如果链表无环,快指针会先走到链表末尾(fast或fast->nullptr)

代码关键点解释

1、边界判断:空链表或只有1个节点的链表,不可能有环,直接返回false
2、循环条件:fast!=nullptr&&fast->next!=nullptr

  • 快指针每次走2步,必须保证fast->next不为空,否则会访问空指针报错

3、指针移动:慢指针一步,快指针两步,保证有环时一定会相遇
4、相遇判断:只要slow==fast,说明两个指针指向同一个节点,链表有环

完整代码实现如下

#include
using namespace std;

// 定义链表节点结构
struct ListNode {

int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
bool hasCycle(ListNode *head) {

// 边界条件:空链表 或 只有一个节点,一定无环
if (head == nullptr || head->next == nullptr) {
return false;
}

// 初始化快慢指针
ListNode* slow = head;
ListNode* fast = head;

// 快指针遍历链表(必须判断 fast 和 fast->next,防止空指针访问)
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next; // 慢指针走1步
fast = fast->next->next; // 快指针走2步

// 快慢指针相遇 → 有环
if (slow == fast) {
return true;
}
}

// 快指针走到末尾 → 无环
return false;
}
};

// 测试用例
int main() {

// 构造有环链表:1->2->3->2 (环在2节点)
ListNode* n1 = new ListNode(1);
ListNode* n2 = new ListNode(2);
ListNode* n3 = new ListNode(3);
n1->next = n2;
n2->next = n3;
n3->next = n2; // 构造环

Solution sol;
cout << boolalpha << sol.hasCycle(n1) << endl; // 输出 true

// 构造无环链表:1->2->3->nullptr
ListNode* a1 = new ListNode(1);
ListNode* a2 = new ListNode(2);
a1->next = a2;
cout << sol.hasCycle(a1) << endl; // 输出 false

return 0;
}

posted @ 2026-04-06 15:46  ZealousMclaren  阅读(7)  评论(0)    收藏  举报