链表的查找、定位、反转、连接等

1. 链表基础结构

单向链表
复制代码
typedef struct ListNode {
    int val;
    struct ListNode* next;
} ListNode;

// 创建节点
ListNode* create_node(int val) {
    ListNode* node = (ListNode*)malloc(sizeof(ListNode));
    node->val = val;
    node->next = NULL;
    return node;
}
双向链表
复制代码
typedef struct DListNode {
    int val;
    struct DListNode* prev;
    struct DListNode* next;
} DListNode;

2. 查找操作

2.1 按值查找
复制代码
// 在链表中查找特定值
ListNode* find_by_value(ListNode* head, int target) {
    ListNode* current = head;
    while (current != NULL) {
        if (current->val == target) {
            return current;  // 找到,返回节点
        }
        current = current->next;
    }
    return NULL;  // 未找到
}


// 递归版本
ListNode* find_by_value_recursive(ListNode* head, int target) {
    if (head == NULL) return NULL;
    if (head->val == target) return head;
    return find_by_value_recursive(head->next, target);
}
2.2 按索引查找
复制代码
// 获取第k个节点(k从0开始)
ListNode* find_by_index(ListNode* head, int k) {
    ListNode* current = head;
    int i = 0;
    
    while (current != NULL && i < k) {
        current = current->next;
        i++;
    }
    
    return current;  // 如果k超出范围,返回NULL
}

// 获取倒数第k个节点
ListNode* find_kth_from_end(ListNode* head, int k) {
    if (head == NULL || k <= 0) return NULL;
    
    // 双指针技巧:快指针先走k步
    ListNode* fast = head;
    ListNode* slow = head;
    
    // 快指针先走k步
    for (int i = 0; i < k; i++) {
        if (fast == NULL) return NULL;  // k大于链表长度
        fast = fast->next;
    }
    
    // 两个指针同时前进
    while (fast != NULL) {
        fast = fast->next;
        slow = slow->next;
    }
    
    return slow;  // slow指向倒数第k个节点
}
2.3 查找中间节点
复制代码
// 快慢指针法找中间节点
ListNode* find_middle(ListNode* head) {
    if (head == NULL) return NULL;
    
    ListNode* slow = head;
    ListNode* fast = head;
    
    // fast每次走两步,slow每次走一步
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    
    return slow;  // slow指向中间节点
}

3. 定位操作

3.1 定位到特定位置插入
复制代码
// 在指定位置插入节点
ListNode* insert_at_position(ListNode* head, int val, int position) {
    ListNode* new_node = create_node(val);
    
    // 情况1:插入到链表头部
    if (position == 0) {
        new_node->next = head;
        return new_node;  // 返回新头部
    }
    
    // 情况2:插入到中间或尾部
    ListNode* current = head;
    int i = 0;
    
    // 移动到position-1的位置
    while (current != NULL && i < position - 1) {
        current = current->next;
        i++;
    }
    
    if (current == NULL) {
        // 位置超出范围,可以插入到末尾
        // 需要找到尾节点(这里简化处理)
        printf("位置超出范围\n");
        free(new_node);
        return head;
    }
    
    // 插入新节点
    new_node->next = current->next;
    current->next = new_node;
    
    return head;
}
3.2 定位并删除
复制代码
// 删除指定位置的节点
ListNode* delete_at_position(ListNode* head, int position) {
    if (head == NULL) return NULL;
    
    // 情况1:删除头节点
    if (position == 0) {
        ListNode* to_delete = head;
        head = head->next;
        free(to_delete);
        return head;
    }
    
    // 情况2:删除中间或尾部节点
    ListNode* current = head;
    int i = 0;
    
    // 移动到position-1的位置
    while (current != NULL && current->next != NULL && i < position - 1) {
        current = current->next;
        i++;
    }
    
    if (current == NULL || current->next == NULL) {
        printf("位置超出范围\n");
        return head;
    }
    
    // 删除节点
    ListNode* to_delete = current->next;
    current->next = to_delete->next;
    free(to_delete);
    
    return head;
}
3.3 定位循环入口(检测环)
复制代码
// 检测链表是否有环,并返回环的入口节点
ListNode* detect_cycle_entry(ListNode* head) {
    if (head == NULL || head->next == NULL) return NULL;
    
    ListNode* slow = head;
    ListNode* fast = head;
    
    // 第一阶段:检测是否有环
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        
        if (slow == fast) {
            // 有环,进入第二阶段找入口
            ListNode* ptr1 = head;
            ListNode* ptr2 = slow;  // 相遇点
            
            // 两个指针以相同速度前进
            while (ptr1 != ptr2) {
                ptr1 = ptr1->next;
                ptr2 = ptr2->next;
            }
            
            return ptr1;  // 环的入口
        }
    }
    
    return NULL;  // 无环
}

4. 反转操作

4.1 迭代反转(三指针法)
复制代码
// 迭代方式反转链表
ListNode* reverse_iterative(ListNode* head) {
    ListNode* prev = NULL;
    ListNode* current = head;
    ListNode* next = NULL;
    
    while (current != NULL) {
        // 保存下一个节点
        next = current->next;
        
        // 反转当前节点的指针
        current->next = prev;
        
        // 移动指针
        prev = current;
        current = next;
    }
    
    return prev;  // prev是新的头节点
}
4.2 递归反转
复制代码
// 递归方式反转链表
ListNode* reverse_recursive(ListNode* head) {
    // 递归终止条件
    if (head == NULL || head->next == NULL) {
        return head;
    }
    
    // 递归反转剩余部分
    ListNode* new_head = reverse_recursive(head->next);
    
    // 处理当前节点
    head->next->next = head;
    head->next = NULL;
    
    return new_head;
}
4.3 反转部分链表
复制代码
// 反转链表中从位置m到n的部分

ListNode* reverse_between(ListNode* head, int m, int n) {
    if (head == NULL || m >= n) return head;
    
    // 创建哑节点简化边界处理
    ListNode dummy;
    dummy.next = head;
    ListNode* pre = &dummy;
    
    // 移动到第m-1个节点
    for (int i = 0; i < m - 1; i++) {
        pre = pre->next;
    }
    
    // 开始反转
    ListNode* start = pre->next;  // 反转开始的节点
    ListNode* then = start->next; // 将要移动到前面的节点
    
    // 反转m到n之间的节点
    for (int i = 0; i < n - m; i++) {
        start->next = then->next;
        then->next = pre->next;
        pre->next = then;
        then = start->next;
    }
    
    return dummy.next;
}
4.4 分组反转
复制代码
// K个一组反转链表
ListNode* reverse_k_group(ListNode* head, int k) {
    if (head == NULL || k <= 1) return head;
    
    // 计算链表长度
    int length = 0;
    ListNode* temp = head;
    while (temp != NULL) {
        length++;
        temp = temp->next;
    }
    
    // 创建哑节点
    ListNode dummy;
    dummy.next = head;
    ListNode* pre = &dummy;
    ListNode* curr = head;
    
    // 分组反转
    for (int i = 0; i < length / k; i++) {
        // 反转当前组
        for (int j = 0; j < k - 1; j++) {
            ListNode* next = curr->next;
            curr->next = next->next;
            next->next = pre->next;
            pre->next = next;
        }
        
        // 移动到下一组
        pre = curr;
        curr = curr->next;
    }
    
    return dummy.next;
}

5. 连接操作

5.1 连接两个链表
复制代码
// 连接两个链表(直接连接)
ListNode* concatenate(ListNode* list1, ListNode* list2) {
    if (list1 == NULL) return list2;
    if (list2 == NULL) return list1;
    
    // 找到list1的尾节点
    ListNode* current = list1;
    while (current->next != NULL) {
        current = current->next;
    }
    
    // 连接list2
    current->next = list2;
    
    return list1;
}
5.2 有序链表合并
复制代码
// 合并两个有序链表(升序)
ListNode* merge_sorted_lists(ListNode* l1, ListNode* l2) {
    // 创建哑节点简化代码
    ListNode dummy;
    ListNode* tail = &dummy;
    dummy.next = NULL;
    
    // 合并两个链表
    while (l1 != NULL && l2 != NULL) {
        if (l1->val <= l2->val) {
            tail->next = l1;
            l1 = l1->next;
        } else {
            tail->next = l2;
            l2 = l2->next;
        }
        tail = tail->next;
    }
    
    // 连接剩余部分
    if (l1 != NULL) {
        tail->next = l1;
    } else {
        tail->next = l2;
    }
    
    return dummy.next;
}

// 递归版本
ListNode* merge_sorted_lists_recursive(ListNode* l1, ListNode* l2) {
    if (l1 == NULL) return l2;
    if (l2 == NULL) return l1;
    
    if (l1->val < l2->val) {
        l1->next = merge_sorted_lists_recursive(l1->next, l2);
        return l1;
    } else {
        l2->next = merge_sorted_lists_recursive(l1, l2->next);
        return l2;
    }
}
5.3 交叉连接(合并两个链表)
复制代码
// 交叉合并两个链表:l1[0]→l2[0]→l1[1]→l2[1]→...
ListNode* interleave_lists(ListNode* l1, ListNode* l2) {
    if (l1 == NULL) return l2;
    if (l2 == NULL) return l1;
    
    ListNode* p1 = l1;
    ListNode* p2 = l2;
    
    while (p1 != NULL && p2 != NULL) {
        ListNode* temp1 = p1->next;
        ListNode* temp2 = p2->next;
        
        // 连接p1和p2
        p1->next = p2;
        
        // 如果p1后面还有节点,连接p2到下一个p1
        if (temp1 != NULL) {
            p2->next = temp1;
        }
        
        // 移动指针
        p1 = temp1;
        p2 = temp2;
    }
    
    return l1;
}
5.4 链表排序(归并排序)
复制代码
// 使用归并排序对链表排序
ListNode* sort_list(ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    
    // 找到中间节点并分割链表
    ListNode* slow = head;
    ListNode* fast = head;
    ListNode* prev = NULL;
    
    while (fast != NULL && fast->next != NULL) {
        prev = slow;
        slow = slow->next;
        fast = fast->next->next;
    }
    
    prev->next = NULL;  // 分割链表
    
    // 递归排序两个子链表
    ListNode* l1 = sort_list(head);
    ListNode* l2 = sort_list(slow);
    
    // 合并排序后的链表
    return merge_sorted_lists(l1, l2);
}
相关推荐
数字哨兵(和中)2 小时前
和中科技分享高危漏洞CVE-2025-51482修复方法
运维·服务器·网络·安全
专业开发者2 小时前
Bluetooth® Mesh网络中的设备管理
网络·物联网
qq_479875434 小时前
C++ 网络编程中的 Protobuf 消息分发 (Dispatcher) 设计模式
网络·c++·设计模式
Tandy12356_4 小时前
手写TCP/IP协议——IP层输出处理
c语言·网络·c++·tcp/ip·计算机网络
luoganttcc4 小时前
tcp 三次 握手
网络·网络协议·tcp/ip
程序员小白条11 小时前
0经验如何找实习?
java·开发语言·数据结构·数据库·链表
土星云SaturnCloud11 小时前
不止是替代:从机械风扇的可靠性困局,看服务器散热技术新范式
服务器·网络·人工智能·ai
liulilittle11 小时前
C++ 浮点数封装。
linux·服务器·开发语言·前端·网络·数据库·c++
lang2015092811 小时前
Sentinel核心机制:Context与EntranceNode解析
网络·sentinel