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);
}