带你彻底大厂手撕面试算法之链表14讲:一文吃透字节腾讯华为链表解题模板+思路详解:从基础到进阶的链表算法全攻略 文末附带本人本地vscode手撸的2k行源码

       链表作为数据结构中的基础内容,是编程面试中永远绕不开的核心考点。这次我在刷题中碰到了不少常见问题,所以自己写了一个详解:深入解析牛客 101 题单中链表相关的经典题目,解析牛客 101 题单中链表相关的 15 道核心题目,涵盖反转、合并、环检测、排序等高频考点,通过「题目描述 + 思路分析 + 多解法实现 + 复杂度对比 + 易错点」的结构i帮你吃透!!!

附带有本人手写的4k行c源码,帮你彻底吃透链表,文末自取

一、链表基础操作:反转与区间操作

BM1. 反转链表

题目描述:将单链表反转,返回反转后的头节点。
示例:输入1->2->3,输出3->2->1

解法一:迭代法(最优解)

c

struct ListNode* ReverseList(struct ListNode* pHead) {
    if (pHead == NULL || pHead->next == NULL) return pHead;
    
    struct ListNode *prev = NULL, *curr = pHead, *next = NULL;
    while (curr) {
        next = curr->next;        // 保存后继节点
        curr->next = prev;        // 反转指针
        prev = curr;              // 指针后移
        curr = next;
    }
    return prev;
}
解法二:递归法

c

struct ListNode* reverseRecursive(struct ListNode* head, struct ListNode* prev) {
    if (head == NULL) return prev;
    struct ListNode* next = head->next;
    head->next = prev;
    return reverseRecursive(next, head);
}

struct ListNode* ReverseList(struct ListNode* pHead) {
    return reverseRecursive(pHead, NULL);
}

复杂度分析

  • 时间:O (n),遍历链表一次
  • 空间:迭代法 O (1),递归法 O (n)(栈空间)

易错点:反转时需先保存后继节点,避免断链;空链表或单节点链表需特殊处理。

BM2. 链表内指定区间反转

题目描述:将链表中[m,n]区间内的节点反转,要求 O (n) 时间和 O (1) 空间。
示例:输入1->2->3->4->5,m=2, n=4,输出1->4->3->2->5

c

struct ListNode* reverseBetween(struct ListNode* head, int m, int n) {
    if (!head || m >= n) return head;
    
    struct ListNode dummy = {0, head};
    struct ListNode *prev = &dummy;
    
    // 定位到区间[m,n]的前驱节点
    for (int i = 1; i < m; i++) {
        prev = prev->next;
        if (!prev) return head;
    }
    
    struct ListNode *start = prev->next;
    struct ListNode *end = start;
    // 定位到区间终点
    for (int i = m; i < n; i++) {
        end = end->next;
        if (!end) return head;
    }
    
    struct ListNode *next = end->next;
    end->next = NULL;
    
    // 反转区间[start, end]
    prev->next = reverse(start);  // 调用BM1的反转函数
    start->next = next;
    return dummy.next;
}

关键点:使用哑节点处理头节点情况,区间反转后需正确连接前驱和后继节点。

二、链表合并与分割

BM4. 合并两个排序链表

题目描述:合并两个递增链表,结果仍递增。
示例:输入1->3->52->4->6,输出1->2->3->4->5->6

解法一:迭代法

c

struct ListNode* Merge(struct ListNode* l1, struct ListNode* l2) {
    if (!l1) return l2;
    if (!l2) return l1;
    
    struct ListNode dummy = {0, NULL};
    struct ListNode *curr = &dummy;
    
    while (l1 && l2) {
        if (l1->val <= l2->val) {
            curr->next = l1;
            l1 = l1->next;
        } else {
            curr->next = l2;
            l2 = l2->next;
        }
        curr = curr->next;
    }
    
    curr->next = l1 ? l1 : l2;
    return dummy.next;
}
解法二:递归法

c

运行

struct ListNode* Merge(struct ListNode* l1, struct ListNode* l2) {
    if (!l1) return l2;
    if (!l2) return l1;
    
    if (l1->val <= l2->val) {
        l1->next = Merge(l1->next, l2);
        return l1;
    } else {
        l2->next = Merge(l1, l2->next);
        return l2;
    }
}
BM5. 合并 k 个排序链表(补充解法)

题目描述:合并 k 个递增链表,结果仍递增。
示例:输入[1->4->5, 1->3->4, 2->6],输出1->1->2->3->4->4->5->6

解法:优先队列(最小堆)

c

// 定义堆节点
typedef struct {
    struct ListNode* node;
} HeapNode;

// 堆操作函数
void swap(HeapNode* a, HeapNode* b) {
    HeapNode temp = *a;
    *a = *b;
    *b = temp;
}

void heapify(HeapNode* heap, int n, int i) {
    int smallest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    
    if (left < n && heap[left].node->val < heap[smallest].node->val)
        smallest = left;
    if (right < n && heap[right].node->val < heap[smallest].node->val)
        smallest = right;
    
    if (smallest != i) {
        swap(&heap[i], &heap[smallest]);
        heapify(heap, n, smallest);
    }
}

struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
    if (listsSize == 0) return NULL;
    
    // 构建最小堆
    HeapNode heap[listsSize];
    for (int i = 0; i < listsSize; i++) {
        heap[i].node = lists[i];
    }
    
    for (int i = listsSize / 2 - 1; i >= 0; i--) {
        heapify(heap, listsSize, i);
    }
    
    struct ListNode dummy = {0, NULL};
    struct ListNode *curr = &dummy;
    
    while (1) {
        // 取出堆顶(最小值)
        HeapNode top = heap[0];
        if (!top.node) break;
        
        curr->next = top.node;
        curr = curr->next;
        heap[0].node = top.node->next;
        
        // 调整堆
        heapify(heap, listsSize, 0);
    }
    
    return dummy.next;
}

三、链表环问题:检测与定位

BM6. 判断链表中是否有环

题目描述:用 O (1) 空间判断链表是否有环。
示例:输入1->2->3->2(环),返回true

c

bool hasCycle(struct ListNode* head) {
    if (!head || !head->next) return false;
    
    struct ListNode *slow = head, *fast = head->next;
    while (slow != fast) {
        if (!fast || !fast->next) return false;
        slow = slow->next;
        fast = fast->next->next;
    }
    return true;
}

核心原理:快慢指针法,快指针每次走 2 步,慢指针走 1 步,若存在环则必然相遇。

BM7. 链表中环的入口结点

题目描述:找到环的入口节点,若无环返回NULL
示例:输入1->2->3->4->3(环入口为 3),返回值为 3 的节点。

c

运行

struct ListNode* detectCycle(struct ListNode* head) {
    if (!head || !head->next) return NULL;
    
    struct ListNode *slow = head, *fast = head;
    bool hasCycle = false;
    
    // 找相遇点
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) {
            hasCycle = true;
            break;
        }
    }
    
    if (!hasCycle) return NULL;
    
    // 找入口:慢指针回表头,快慢同速走
    slow = head;
    while (slow != fast) {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

数学推导:设头到入口为 a,入口到相遇点为 b,环长为 c,则a = (k-1)*c + (c-b),即头到入口距离等于相遇点绕环 k-1 圈加剩余距离。

四、链表定位与特殊操作

BM8. 链表中倒数最后 k 个结点

题目描述:找到链表中倒数第 k 个节点。
示例:输入1->2->3->4->5,k=2,返回 4 的节点。

c

struct ListNode* FindKthToTail(struct ListNode* head, int k) {
    if (!head || k <= 0) return NULL;
    
    struct ListNode *fast = head, *slow = head;
    // 快指针先走k步
    for (int i = 0; i < k; i++) {
        if (!fast) return NULL; // k超过链表长度
        fast = fast->next;
    }
    
    // 快慢同速走
    while (fast) {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}
BM10. 两个链表的第一个公共结点

题目描述:找两个无环链表的第一个公共节点。
示例:输入1->2->6->74->5->6->7,返回 6 的节点。

c

struct ListNode* FindFirstCommonNode(struct ListNode* pHead1, struct ListNode* pHead2) {
    if (!pHead1 || !pHead2) return NULL;
    
    struct ListNode *p1 = pHead1, *p2 = pHead2;
    while (p1 != p2) {
        p1 = p1 ? p1->next : pHead2;
        p2 = p2 ? p2->next : pHead1;
    }
    return p1;
}

关键思路:双指针遍历总长度相等(m+n),若有公共节点则相遇,若无则同时到 NULL。

五、链表运算与排序

BM11. 链表相加 (二)

题目描述:两链表各节点代表数字一位(逆序存储),求两数之和。
示例:输入9->3->76->3,输出1->0->0->0(937+63=1000)。

c

struct ListNode* addInList(struct ListNode* head1, struct ListNode* head2) {
    struct ListNode dummy = {0, NULL};
    struct ListNode *curr = &dummy;
    int carry = 0;
    
    while (head1 || head2 || carry) {
        int val1 = head1 ? head1->val : 0;
        int val2 = head2 ? head2->val : 0;
        int sum = val1 + val2 + carry;
        carry = sum / 10;
        
        struct ListNode *newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
        newNode->val = sum % 10;
        newNode->next = NULL;
        
        curr->next = newNode;
        curr = curr->next;
        
        if (head1) head1 = head1->next;
        if (head2) head2 = head2->next;
    }
    return dummy.next;
}
BM12. 单链表的排序

题目描述:对链表排序,要求 O (n log n) 时间和 O (1) 空间。
示例:输入4->2->1->3,输出1->2->3->4

c

// 找链表中点(快慢指针)
struct ListNode* findMiddle(struct ListNode* head) {
    if (!head || !head->next) return head;
    struct ListNode *slow = head, *fast = head->next;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

// 合并有序链表(同BM4)
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2);

struct ListNode* sortList(struct ListNode* head) {
    if (!head || !head->next) return head;
    
    struct ListNode *mid = findMiddle(head);
    struct ListNode *rightHead = mid->next;
    mid->next = NULL; // 分割链表
    
    struct ListNode *left = sortList(head);
    struct ListNode *right = sortList(rightHead);
    return mergeTwoLists(left, right);
}

六、链表高级特性判断

BM13. 判断一个链表是否为回文结构

题目描述:判断链表是否是回文(正读反读相同)。
示例:输入1->2->2->1,返回true;输入1->2,返回false

解法一:快慢指针 + 栈(O (n) 空间)

c

bool isPalindrome(struct ListNode* head) {
    if (!head || !head->next) return true;
    
    struct ListNode *slow = head, *fast = head;
    // 快指针到中点,慢指针到前半段末尾
    while (fast->next && fast->next->next) {
        slow = slow->next;
        fast = fast->next->next;
    }
    
    // 栈存储前半段
    struct ListNode *curr = head;
    int stack[10000], top = 0;
    while (curr != slow) {
        stack[top++] = curr->val;
        curr = curr->next;
    }
    
    // 比较后半段与栈
    curr = slow->next;
    while (curr) {
        if (top == 0 || stack[--top] != curr->val)
            return false;
        curr = curr->next;
    }
    return true;
}
解法二:反转后半段(O (1) 空间)

c

bool isPalindrome(struct ListNode* head) {
    if (!head || !head->next) return true;
    
    // 找中点
    struct ListNode *slow = head, *fast = head;
    while (fast->next && fast->next->next) {
        slow = slow->next;
        fast = fast->next->next;
    }
    
    // 反转后半段
    struct ListNode *secondHalf = reverse(slow->next); // 调用BM1的反转函数
    slow->next = NULL;
    
    // 比较两段
    struct ListNode *p1 = head, *p2 = secondHalf;
    bool res = true;
    while (p1 && p2) {
        if (p1->val != p2->val) {
            res = false;
            break;
        }
        p1 = p1->next;
        p2 = p2->next;
    }
    
    // 恢复链表(可选)
    slow->next = reverse(secondHalf);
    return res;
}

七、链表元素删除与重排

BM15. 删除有序链表中重复的元素 - I

题目描述:删除有序链表中重复的节点,保留首次出现的节点。
示例:输入1->2->2->3,输出1->2->3

c

struct ListNode* deleteDuplicates(struct ListNode* head) {
    if (!head || !head->next) return head;
    
    struct ListNode *curr = head;
    while (curr->next) {
        if (curr->val == curr->next->val) {
            struct ListNode *temp = curr->next;
            curr->next = temp->next;
            free(temp); // 释放重复节点内存
        } else {
            curr = curr->next;
        }
    }
    return head;
}
BM16. 删除有序链表中重复的元素 - II

题目描述:删除有序链表中所有重复的节点,只保留不重复的节点。
示例:输入1->2->2->3->3,输出1

c

struct ListNode* deleteDuplicates(struct ListNode* head) {
    if (!head || !head->next) return head;
    
    struct ListNode dummy = {0, head};
    struct ListNode *prev = &dummy;
    struct ListNode *curr = head;
    
    while (curr) {
        // 找到不重复的区间
        while (curr->next && curr->val == curr->next->val) {
            curr = curr->next;
        }
        
        if (prev->next == curr) {
            // 无重复,指针后移
            prev = prev->next;
        } else {
            // 有重复,跳过所有重复节点
            prev->next = curr->next;
        }
        curr = curr->next;
    }
    return dummy.next;
}
BM14. 链表的奇偶重排

题目描述:将链表奇数位置节点和偶数位置节点分别排列,奇数在前,偶数在后。
示例:输入1->2->3->4->5,输出1->3->5->2->4

struct ListNode* oddEvenList(struct ListNode* head) {
    if (!head || !head->next) return head;
    
    struct ListNode *odd = head;
    struct ListNode *even = head->next;
    struct ListNode *evenHead = even;
    
    while (even && even->next) {
        odd->next = even->next;
        odd = odd->next;
        even->next = odd->next;
        even = even->next;
    }
    
    odd->next = evenHead;
    return head;
}

我总结的一些技巧:

  1. 哑节点:处理头节点特殊情况,避免额外条件判断
  2. 双指针:快慢指针(环检测、中点查找)、前后指针(删除节点)
  3. 递归:反转、合并、排序等问题可利用递归简化逻辑
  4. 空间换时间:哈希表记录节点(环检测、公共节点)

四种你可能碰到的陷阱:

  • 空链表、单节点链表的边界条件
  • 指针操作时的内存泄漏(如删除节点未 free)
  • 环问题中快慢指针的初始化顺序
  • 区间操作时的指针断链风险

***最终附录,本人的vscode本地手写源码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// 定义链表节点结构
struct ListNode {
    int val;
    struct ListNode *next;
};

// 辅助函数:创建新节点
struct ListNode* createNode(int val) {
    struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = NULL;
    return newNode;
}

// 辅助函数:打印链表
void printList(struct ListNode* head) {
    struct ListNode* curr = head;
    while (curr != NULL) {
        printf("%d -> ", curr->val);
        curr = curr->next;
    }
    printf("NULL\n");
}

// 辅助函数:释放链表
void freeList(struct ListNode* head) {
    struct ListNode* temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

// BM1: 反转链表
struct ListNode* ReverseList(struct ListNode* pHead) {
    struct ListNode* prev = NULL;
    struct ListNode* curr = pHead;
    struct ListNode* next = NULL;
    
    while (curr != NULL) {
        next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    
    return prev;
}

// BM2: 链表内指定区间反转
struct ListNode* reverseBetween(struct ListNode* head, int m, int n) {
    if (head == NULL || m >= n) return head;
    
    struct ListNode dummy = {0, head};
    struct ListNode* prev = &dummy;
    
    // 找到第m-1个节点
    for (int i = 1; i < m; i++) {
        prev = prev->next;
    }
    
    struct ListNode* start = prev->next;
    struct ListNode* end = start;
    
    // 找到第n个节点
    for (int i = m; i < n; i++) {
        end = end->next;
    }
    
    struct ListNode* next = end->next;
    end->next = NULL;
    
    // 反转区间[m,n]
    prev->next = ReverseList(start);
    start->next = next;
    
    return dummy.next;
}

// BM4: 合并两个排序的链表
struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2) {
    struct ListNode dummy = {0, NULL};
    struct ListNode* tail = &dummy;
    
    while (pHead1 && pHead2) {
        if (pHead1->val < pHead2->val) {
            tail->next = pHead1;
            pHead1 = pHead1->next;
        } else {
            tail->next = pHead2;
            pHead2 = pHead2->next;
        }
        tail = tail->next;
    }
    
    if (pHead1) tail->next = pHead1;
    if (pHead2) tail->next = pHead2;
    
    return dummy.next;
}

// BM5: 合并k个已排序的链表
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
    if (listsSize == 0) return NULL;
    if (listsSize == 1) return lists[0];
    
    int mid = listsSize / 2;
    struct ListNode* left = mergeKLists(lists, mid);
    struct ListNode* right = mergeKLists(lists + mid, listsSize - mid);
    
    return Merge(left, right);
}

// BM6: 判断链表中是否有环
bool hasCycle(struct ListNode *head) {
    if (head == NULL || head->next == NULL) return false;
    
    struct ListNode* slow = head;
    struct ListNode* fast = head->next;
    
    while (slow != fast) {
        if (fast == NULL || fast->next == NULL) return false;
        slow = slow->next;
        fast = fast->next->next;
    }
    
    return true;
}

// BM7: 链表中环的入口结点
struct ListNode* EntryNodeOfLoop(struct ListNode* pHead) {
    if (pHead == NULL || pHead->next == NULL) return NULL;
    
    struct ListNode* slow = pHead;
    struct ListNode* fast = pHead;
    
    // 找到相遇点
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) break;
    }
    
    if (fast == NULL || fast->next == NULL) return NULL;
    
    // 找到环的入口
    slow = pHead;
    while (slow != fast) {
        slow = slow->next;
        fast = fast->next;
    }
    
    return slow;
}

// BM8: 链表中倒数最后k个结点
struct ListNode* FindKthToTail(struct ListNode* pHead, int k) {
    if (pHead == NULL || k <= 0) return NULL;
    
    struct ListNode* fast = pHead;
    struct ListNode* slow = pHead;
    
    // 快指针先走k步
    for (int i = 0; i < k; i++) {
        if (fast == NULL) return NULL; // k大于链表长度
        fast = fast->next;
    }
    
    // 快慢指针同时走
    while (fast != NULL) {
        slow = slow->next;
        fast = fast->next;
    }
    
    return slow;
}

// BM10: 两个链表的第一个公共结点
struct ListNode* FindFirstCommonNode(struct ListNode* pHead1, struct ListNode* pHead2) {
    if (pHead1 == NULL || pHead2 == NULL) return NULL;
    
    struct ListNode* p1 = pHead1;
    struct ListNode* p2 = pHead2;
    
    while (p1 != p2) {
        p1 = p1 ? p1->next : pHead2;
        p2 = p2 ? p2->next : pHead1;
    }
    
    return p1;
}

// BM11: 链表相加(二)
struct ListNode* addInList(struct ListNode* head1, struct ListNode* head2) {
    // 先反转两个链表
    head1 = ReverseList(head1);
    head2 = ReverseList(head2);
    
    struct ListNode dummy = {0, NULL};
    struct ListNode* tail = &dummy;
    int carry = 0;
    
    while (head1 || head2 || carry) {
        int sum = carry;
        if (head1) {
            sum += head1->val;
            head1 = head1->next;
        }
        if (head2) {
            sum += head2->val;
            head2 = head2->next;
        }
        
        carry = sum / 10;
        struct ListNode* newNode = createNode(sum % 10);
        tail->next = newNode;
        tail = tail->next;
    }
    
    // 反转结果链表
    return ReverseList(dummy.next);
}

// BM12: 单链表的排序
struct ListNode* sortList(struct ListNode* head) {
    if (head == NULL || head->next == NULL) return head;
    
    // 快慢指针找到中间节点
    struct ListNode* slow = head;
    struct ListNode* fast = head->next;
    
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    
    struct ListNode* mid = slow->next;
    slow->next = NULL;
    
    // 递归排序左右两部分
    struct ListNode* left = sortList(head);
    struct ListNode* right = sortList(mid);
    
    // 合并两个有序链表
    return Merge(left, right);
}

// BM13: 判断一个链表是否为回文结构
bool isPalindrome(struct ListNode* head) {
    if (head == NULL || head->next == NULL) return true;
    
    // 找到中间节点
    struct ListNode* slow = head;
    struct ListNode* fast = head->next;
    
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    
    // 反转后半部分链表
    struct ListNode* secondHalf = ReverseList(slow->next);
    
    // 比较前半部分和反转后的后半部分
    struct ListNode* p1 = head;
    struct ListNode* p2 = secondHalf;
    bool result = true;
    
    while (p2 != NULL) {
        if (p1->val != p2->val) {
            result = false;
            break;
        }
        p1 = p1->next;
        p2 = p2->next;
    }
    
    // 恢复链表(可选)
    slow->next = ReverseList(secondHalf);
    
    return result;
}

// BM14: 链表的奇偶重排
struct ListNode* oddEvenList(struct ListNode* head) {
    if (head == NULL || head->next == NULL) return head;
    
    struct ListNode* odd = head;
    struct ListNode* even = head->next;
    struct ListNode* evenHead = even;
    
    while (even != NULL && even->next != NULL) {
        odd->next = even->next;
        odd = odd->next;
        even->next = odd->next;
        even = even->next;
    }
    
    odd->next = evenHead;
    return head;
}

// BM15: 删除有序链表中重复的元素-I
struct ListNode* deleteDuplicates(struct ListNode* head) {
    struct ListNode* curr = head;
    
    while (curr != NULL && curr->next != NULL) {
        if (curr->val == curr->next->val) {
            struct ListNode* temp = curr->next;
            curr->next = temp->next;
            free(temp);
        } else {
            curr = curr->next;
        }
    }
    
    return head;
}

// BM16: 删除有序链表中重复的元素-II
struct ListNode* deleteDuplicatesII(struct ListNode* head) {
    if (head == NULL || head->next == NULL) return head;
    
    struct ListNode dummy = {0, head};
    struct ListNode* prev = &dummy;
    struct ListNode* curr = head;
    
    while (curr != NULL) {
        bool isDuplicate = false;
        while (curr->next != NULL && curr->val == curr->next->val) {
            isDuplicate = true;
            struct ListNode* temp = curr;
            curr = curr->next;
            free(temp);
        }
        
        if (isDuplicate) {
            // 删除最后一个重复节点
            struct ListNode* temp = curr;
            curr = curr->next;
            free(temp);
            prev->next = curr;
        } else {
            prev = curr;
            curr = curr->next;
        }
    }
    
    return dummy.next;
}

int main() {
    printf("==== 链表算法测试 ====\n");
    
    // 测试BM1: 反转链表
    printf("\nBM1: 反转链表\n");
    struct ListNode* head1 = createNode(1);
    head1->next = createNode(2);
    head1->next->next = createNode(3);
    head1->next->next->next = createNode(4);
    printf("原始链表: ");
    printList(head1);
    struct ListNode* reversed = ReverseList(head1);
    printf("反转后: ");
    printList(reversed);
    freeList(reversed);
    
    // 测试BM2: 链表内指定区间反转
    printf("\nBM2: 链表内指定区间反转\n");
    struct ListNode* head2 = createNode(1);
    head2->next = createNode(2);
    head2->next->next = createNode(3);
    head2->next->next->next = createNode(4);
    head2->next->next->next->next = createNode(5);
    printf("原始链表: ");
    printList(head2);
    struct ListNode* reversedRange = reverseBetween(head2, 2, 4);
    printf("区间[2,4]反转后: ");
    printList(reversedRange);
    freeList(reversedRange);
    
    // 测试BM4: 合并两个排序的链表
    printf("\nBM4: 合并两个排序的链表\n");
    struct ListNode* list1 = createNode(1);
    list1->next = createNode(3);
    list1->next->next = createNode(5);
    struct ListNode* list2 = createNode(2);
    list2->next = createNode(4);
    list2->next->next = createNode(6);
    printf("链表1: ");
    printList(list1);
    printf("链表2: ");
    printList(list2);
    struct ListNode* merged = Merge(list1, list2);
    printf("合并后: ");
    printList(merged);
    freeList(merged);
    
    // 测试BM5: 合并k个已排序的链表
    printf("\nBM5: 合并k个已排序的链表\n");
    struct ListNode* lists[3];
    lists[0] = createNode(1);
    lists[0]->next = createNode(4);
    lists[0]->next->next = createNode(5);
    lists[1] = createNode(1);
    lists[1]->next = createNode(3);
    lists[1]->next->next = createNode(4);
    lists[2] = createNode(2);
    lists[2]->next = createNode(6);
    printf("链表1: ");
    printList(lists[0]);
    printf("链表2: ");
    printList(lists[1]);
    printf("链表3: ");
    printList(lists[2]);
    struct ListNode* mergedK = mergeKLists(lists, 3);
    printf("合并后: ");
    printList(mergedK);
    freeList(mergedK);
    
    // 测试BM6: 判断链表中是否有环
    printf("\nBM6: 判断链表中是否有环\n");
    struct ListNode* loopList = createNode(1);
    loopList->next = createNode(2);
    loopList->next->next = createNode(3);
    loopList->next->next->next = createNode(4);
    loopList->next->next->next->next = loopList->next; // 创建环
    printf("链表是否有环: %s\n", hasCycle(loopList) ? "是" : "否");
    // 注意:有环链表不能直接释放,需先破环
    
    // 测试BM7: 链表中环的入口结点
    printf("\nBM7: 链表中环的入口结点\n");
    struct ListNode* loopList2 = createNode(1);
    loopList2->next = createNode(2);
    loopList2->next->next = createNode(3);
    loopList2->next->next->next = createNode(4);
    loopList2->next->next->next->next = loopList2->next; // 环入口为2
    struct ListNode* loopEntry = EntryNodeOfLoop(loopList2);
    printf("环的入口值: %d\n", loopEntry ? loopEntry->val : -1);
    
    // 测试BM8: 链表中倒数最后k个结点
    printf("\nBM8: 链表中倒数最后k个结点\n");
    struct ListNode* list8 = createNode(1);
    list8->next = createNode(2);
    list8->next->next = createNode(3);
    list8->next->next->next = createNode(4);
    list8->next->next->next->next = createNode(5);
    printf("原始链表: ");
    printList(list8);
    struct ListNode* kthNode = FindKthToTail(list8, 2);
    printf("倒数第2个结点值: %d\n", kthNode->val);
    freeList(list8);
    
    // 测试BM10: 两个链表的第一个公共结点
    printf("\nBM10: 两个链表的第一个公共结点\n");
    struct ListNode* commonNode = createNode(6);
    commonNode->next = createNode(7);
    
    struct ListNode* list10a = createNode(1);
    list10a->next = createNode(2);
    list10a->next->next = commonNode;
    
    struct ListNode* list10b = createNode(4);
    list10b->next = createNode(5);
    list10b->next->next = commonNode;
    
    printf("链表1: ");
    printList(list10a);
    printf("链表2: ");
    printList(list10b);
    struct ListNode* common = FindFirstCommonNode(list10a, list10b);
    printf("第一个公共结点值: %d\n", common->val);
    
    // 测试BM11: 链表相加(二)
    printf("\nBM11: 链表相加(二)\n");
    struct ListNode* add1 = createNode(9);
    add1->next = createNode(3);
    add1->next->next = createNode(7);
    
    struct ListNode* add2 = createNode(6);
    add2->next = createNode(3);
    
    printf("链表1: ");
    printList(add1);
    printf("链表2: ");
    printList(add2);
    struct ListNode* sum = addInList(add1, add2);
    printf("相加后: ");
    printList(sum);
    freeList(sum);
    
    // 测试BM12: 单链表的排序
    printf("\nBM12: 单链表的排序\n");
    struct ListNode* unsorted = createNode(4);
    unsorted->next = createNode(2);
    unsorted->next->next = createNode(1);
    unsorted->next->next->next = createNode(3);
    printf("原始链表: ");
    printList(unsorted);
    struct ListNode* sorted = sortList(unsorted);
    printf("排序后: ");
    printList(sorted);
    freeList(sorted);
    
    // 测试BM13: 判断一个链表是否为回文结构
    printf("\nBM13: 判断一个链表是否为回文结构\n");
    struct ListNode* palindrome = createNode(1);
    palindrome->next = createNode(2);
    palindrome->next->next = createNode(2);
    palindrome->next->next->next = createNode(1);
    printf("链表: ");
    printList(palindrome);
    printf("是否为回文: %s\n", isPalindrome(palindrome) ? "是" : "否");
    freeList(palindrome);
    
    // 测试BM14: 链表的奇偶重排
    printf("\nBM14: 链表的奇偶重排\n");
    struct ListNode* list14 = createNode(1);
    list14->next = createNode(2);
    list14->next->next = createNode(3);
    list14->next->next->next = createNode(4);
    list14->next->next->next->next = createNode(5);
    printf("原始链表: ");
    printList(list14);
    struct ListNode* oddEven = oddEvenList(list14);
    printf("奇偶重排后: ");
    printList(oddEven);
    freeList(oddEven);
    
    // 测试BM15: 删除有序链表中重复的元素-I
    printf("\nBM15: 删除有序链表中重复的元素-I\n");
    struct ListNode* duplicates1 = createNode(1);
    duplicates1->next = createNode(2);
    duplicates1->next->next = createNode(2);
    duplicates1->next->next->next = createNode(3);
    printf("原始链表: ");
    printList(duplicates1);
    struct ListNode* cleaned1 = deleteDuplicates(duplicates1);
    printf("删除重复后: ");
    printList(cleaned1);
    freeList(cleaned1);
    
    // 测试BM16: 删除有序链表中重复的元素-II
    printf("\nBM16: 删除有序链表中重复的元素-II\n");
    struct ListNode* duplicates2 = createNode(1);
    duplicates2->next = createNode(2);
    duplicates2->next->next = createNode(2);
    duplicates2->next->next->next = createNode(3);
    duplicates2->next->next->next->next = createNode(3);
    printf("原始链表: ");
    printList(duplicates2);
    struct ListNode* cleaned2 = deleteDuplicatesII(duplicates2);
    printf("删除所有重复后: ");
    printList(cleaned2);
    freeList(cleaned2);
    
    return 0;
}



谢谢 ,觉得写的不错请点赞收藏关注!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值