环形链表(C)

一、题目内容

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

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

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

示例 1:

复制代码
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

复制代码
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

复制代码
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

二、源代码(部分)

复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct hashTable {
    struct ListNode* key;
    UT_hash_handle hh;
};

struct hashTable* hashtable;

struct hashTable* find(struct ListNode* ikey) {
    struct hashTable* tmp;
    HASH_FIND_PTR(hashtable, &ikey, tmp);
    return tmp;
}

void insert(struct ListNode* ikey) {
    struct hashTable* tmp = malloc(sizeof(struct hashTable));
    tmp->key = ikey;
    HASH_ADD_PTR(hashtable, key, tmp);
}

bool hasCycle(struct ListNode* head) {
    hashtable = NULL;
    while (head != NULL) {
        if (find(head) != NULL) {
            return true;
        }
        insert(head);
        head = head->next;
    }
    return false;
}

三、题目解析

1. 数据结构定义
  • struct hashTable:用于实现哈希表的节点结构,包含两个成员:
    • struct ListNode* key:存储链表节点的指针(作为哈希表的键)。
    • UT_hash_handle hh:UT_hash 库的内部句柄,用于维护哈希表的结构(如哈希值、链表指针等)。
  • struct hashTable* hashtable:全局哈希表指针,作为整个哈希表的入口。
2. 哈希表操作函数
  • find 函数:在哈希表中查找指定的链表节点。

    • 调用 HASH_FIND_PTR 宏(UT_hash 库提供),通过链表节点指针 ikey 在哈希表 hashtable 中查找对应节点。
    • 若找到则返回该哈希表节点,否则返回 NULL
  • insert 函数:向哈希表中插入新的链表节点。

    • 动态分配一个哈希表节点 tmp,将其 key 成员指向待插入的链表节点 ikey
    • 调用 HASH_ADD_PTR 宏(UT_hash 库提供),将 tmp 插入哈希表 hashtable,以 key 作为哈希键。
3. 核心函数 hasCycle
  • 功能:判断单链表是否存在环(即链表中是否有节点被重复访问)。
  • 逻辑:
    1. 初始化哈希表为空(hashtable = NULL)。
    2. 遍历链表:从 head 开始,逐个访问节点。
    3. 检查当前节点是否已在哈希表中:若 find(head) != NULL,说明该节点之前已被访问过,链表存在环,返回 true
    4. 若未找到,将当前节点插入哈希表,继续访问下一个节点(head = head->next)。
    5. 若遍历结束(head == NULL)仍未发现重复节点,说明链表无环,返回 false

四、实验总结

1. 实验目的

验证单链表中是否存在环,通过哈希表记录已访问的节点,实现环的检测。

2. 实验原理
  • 利用哈希表的快速查找特性(平均时间复杂度 O(1)),记录链表中每个被访问过的节点。
  • 若遍历过程中再次遇到已存在于哈希表中的节点,说明链表存在环(该节点是环的入口或环上的重复节点);若遍历至链表末尾(head == NULL),则无环。
3. 实验结果分析
  • 正确性 :该算法能准确检测链表是否有环。对于有环链表,会在首次重复访问节点时返回 true;对于无环链表,遍历结束后返回 false
  • 时间复杂度O(n),其中 n 是链表节点数。每个节点的插入和查找操作平均为 O(1),整体遍历一次链表。
  • 空间复杂度O(n),最坏情况下(无环链表),哈希表需存储所有 n 个节点的指针。
4. 优缺点
  • 优点:逻辑直观,实现简单,依赖哈希表的高效查找能力,能在遍历一次链表后得出结果。
  • 缺点 :需要额外的哈希表空间存储节点,空间复杂度较高。相比之下,"快慢指针法" 可在 O(1) 空间复杂度下实现环检测,更适用于空间敏感的场景。
5. 结论

本代码通过哈希表记录已访问节点的方式,成功实现了单链表的环检测功能,逻辑正确且易于理解,但空间开销较大。在实际应用中,可根据空间限制选择更优的算法(如快慢指针)。

相关推荐
xiaoye-duck2 小时前
数据结构之二叉树-链式结构(下)
数据结构·算法
Kt&Rs2 小时前
11.13 LeetCode 题目汇总与解题思路
数据结构·算法
yuuki2332333 小时前
【数据结构】常见时间复杂度以及空间复杂度
c语言·数据结构·后端·算法
前端小L4 小时前
图论专题(五):图遍历的“终极考验”——深度「克隆图」
数据结构·算法·深度优先·图论·宽度优先
代码不停4 小时前
Java分治算法题目练习(快速/归并排序)
java·数据结构·算法
AI科技星6 小时前
引力编程时代:人类文明存续与升维
数据结构·人工智能·经验分享·算法·计算机视觉
罗义凯15 小时前
其中包含了三种排序算法的注释版本(冒泡排序、选择排序、插入排序),但当前只实现了数组的输入和输出功能。
数据结构·c++·算法
kevien_G115 小时前
JAVA之二叉树
数据结构·算法
2401_8612775517 小时前
软考程序员2016年上半年二叉排序树案例题解答
c语言·决策树·链表