You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环链表创建与环起点查找实现问题咨询

解决循环链表环起点查找及链表构建问题

嘿,看起来你在手动构建带环链表时碰到了「函数内输出正常,但main调用后出问题」的情况,还要实现环起点的查找——我来帮你把这些问题理顺,一步步解决。


一、先搞定带环链表的正确构建

你提到创建链表的函数里cout head->data能输出正确值,但main里调用后出问题,大概率是链表头指针没有正确返回或者构建过程中指针处理出错了。这里给你一个靠谱的构建实现,顺便避开常见坑:

完整构建函数示例

#include <iostream>
using namespace std;

// 定义链表节点结构
struct ListNode {
    int data;
    ListNode* next;
    ListNode(int val) : data(val), next(nullptr) {}
};

// 构建带环链表:参数为链表长度、环起点的位置(从1开始计数)
ListNode* createCyclicList(int length, int cyclePos) {
    if (length <= 0) return nullptr;
    
    // 创建头节点
    ListNode* head = new ListNode(1);
    ListNode* current = head;
    ListNode* cycleStart = nullptr;
    
    // 遍历创建后续节点
    for (int i = 2; i <= length; ++i) {
        current->next = new ListNode(i);
        current = current->next;
        // 记录环的起点节点
        if (i == cyclePos) {
            cycleStart = current;
        }
    }
    
    // 让尾节点指向环起点,形成环;如果没指定合法环位置,默认指向头节点
    current->next = (cyclePos >=1 && cyclePos <= length) ? cycleStart : head;
    
    // 函数内测试输出
    cout << "函数内head节点值:" << head->data << endl;
    return head;
}

构建时要注意的点

  • 必须返回头指针:如果你的构建函数是void类型,main里根本拿不到正确的链表头,这是最容易犯的错误;
  • 环起点要准确记录:遍历节点时要把指定位置的指针存下来,最后让尾节点指向它,不能随便乱指;
  • 输入合法性检查:要确保用户输入的环位置在1到链表长度之间,避免出现无效环。

二、环起点的查找:用经典的快慢指针法

搞定链表构建后,查找环起点用Floyd判圈算法(快慢指针)最高效,时间复杂度O(n),空间复杂度O(1)。

实现代码

// 查找环的起点
ListNode* findCycleStart(ListNode* head) {
    // 空链表或只有一个节点,直接返回空
    if (!head || !head->next) return nullptr;
    
    ListNode* slow = head;
    ListNode* fast = head;
    
    // 第一步:快慢指针移动,判断是否有环
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        // 相遇说明有环,跳出循环
        if (slow == fast) break;
    }
    
    // 如果fast走到尽头,说明无环
    if (!fast || !fast->next) return nullptr;
    
    // 第二步:把慢指针移回头部,快慢指针同速前进,相遇点就是环起点
    slow = head;
    while (slow != fast) {
        slow = slow->next;
        fast = fast->next;
    }
    
    return slow;
}

算法原理简单说

当快慢指针第一次相遇时,快指针走的路程是慢指针的2倍。设链表头到环起点的距离为a,环起点到相遇点的距离为b,环长度为c,可以推导出:a = k*c - b(k是快指针绕环的圈数)。也就是说,从链表头到环起点的距离,等于相遇点绕环回到起点的距离。所以把慢指针移回头部,两者同速走,相遇时就是环起点。


三、main函数里的正确调用示例

int main() {
    int listLength, cyclePosition;
    cout << "输入链表长度:";
    cin >> listLength;
    cout << "输入环起点的位置(从1开始):";
    cin >> cyclePosition;
    
    // 构建带环链表
    ListNode* head = createCyclicList(listLength, cyclePosition);
    
    // 测试main里的head是否正常
    cout << "main函数内head节点值:" << head->data << endl;
    
    // 查找环起点
    ListNode* startNode = findCycleStart(head);
    if (startNode) {
        cout << "环的起点值为:" << startNode->data << endl;
    } else {
        cout << "链表无环" << endl;
    }
    
    // 记得释放内存(带环链表的释放需要特殊处理,避免死循环)
    // 这里可以写一个辅助函数来释放,比如:
    // releaseCyclicList(head, startNode);
    
    return 0;
}

最后提醒

如果你的main里还是拿不到正确的head,先检查构建函数的返回值是否正确——比如是不是函数里的head是局部变量但没返回,或者返回了临时指针导致野指针。另外,用完链表一定要记得释放内存,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Blooddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:57:30