連結串列常用操作 單鏈表反轉 連結串列中環的檢測 兩個有序的連結串列合併 刪除連結串列倒數第 n 個結點 求連結串列的中間結點
#include <stdio.h> #include <stdlib.h>
/** * 1) 單鏈表反轉 * 2) 連結串列中環的檢測 * 3) 兩個有序的連結串列合併 * 4) 刪除連結串列倒數第 n 個結點 * 5) 求連結串列的中間結點 * * Author: Smallfly */
typedef struct SinglyLinkedNode { int data; struct SinglyLinkedNode* next; } SinglyLinkedNode;
void insertNode(SinglyLinkedNode** head_ref, int data); void printLinkedList(SinglyLinkedNode* head);
/** 反轉單鏈表 */
void reverse(SinglyLinkedNode** head_ref) { if (*head_ref == NULL) return; SinglyLinkedNode *prev = NULL; SinglyLinkedNode *current = *head_ref; while (current) { SinglyLinkedNode *next = current->next; if (!next) { // 到達尾結點時,將地址存入 head_ref *head_ref = current; } current->next = prev; prev = current; current = next; } }
void test_reverse() { SinglyLinkedNode* head = NULL; insertNode(&head, 3); insertNode(&head, 2); insertNode(&head, 1); reverse(&head); printLinkedList(head); }
/** 檢測單鏈表是否有環 */
// 這裡使用一級指標也可以 int checkCircle(SinglyLinkedNode** head_ref) { if (*head_ref == NULL) return 0; SinglyLinkedNode *slow = *head_ref, *fast = *head_ref; while (fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; if (slow == fast) return 1; } return 0; }
void test_checkCircle() { SinglyLinkedNode* head = NULL; insertNode(&head, 3); insertNode(&head, 2); insertNode(&head, 1); int result1 = checkCircle(&head); printf("has circle: %d\n", result1); // make circle linklist SinglyLinkedNode* current = malloc(sizeof(SinglyLinkedNode)); current->data = 0; SinglyLinkedNode* h = current; for (int i = 1; i < 4; ++i) { SinglyLinkedNode* node = malloc(sizeof(SinglyLinkedNode)); node->data = i; current->next = node; } current->next = h; int result2 = checkCircle(&h); printf("has circle: %d\n", result2); }
/** 有序連結串列合併 */
void moveNode(SinglyLinkedNode** dest_ref, SinglyLinkedNode** src_ref);
SinglyLinkedNode* mergeSortedLinkedList(SinglyLinkedNode* la, SinglyLinkedNode* lb) { // 輔助結點,next 指標持有合併後的有序連結串列 SinglyLinkedNode dummy; // 有序連結串列的尾結點 SinglyLinkedNode* tail = &dummy; while (1) { // 如果有一個連結串列為空,直接與另一個連結串列接起來 if (!la) { tail->next = lb; break; } else if (!lb) { tail->next = la; break; } // 將頭結點較小的優先新增到 tail if (la->data <= lb->data) { moveNode(&(tail->next), &la); } else { moveNode(&(tail->next), &lb); } tail = tail->next; } return dummy.next; }
// 將 src_ref 的頭結點,新增到 dest_ref 的頭部。 void moveNode(SinglyLinkedNode** dest_ref, SinglyLinkedNode** src_ref) { if (*src_ref == NULL) return; SinglyLinkedNode* new_node = *src_ref; *src_ref = new_node->next; new_node->next = *dest_ref; *dest_ref = new_node; }
void test_mergeSortedLinkedList() { SinglyLinkedNode* a = NULL; insertNode(&a, 10); insertNode(&a, 5); insertNode(&a, 0); SinglyLinkedNode* b = NULL; insertNode(&b, 8); insertNode(&b, 6); insertNode(&b, 3); SinglyLinkedNode* result = mergeSortedLinkedList(a, b); printLinkedList(result); SinglyLinkedNode* result2 = mergeSortedLinkedList(a, NULL); printLinkedList(result2); }
/** 刪除倒數第 K 個結點 */
void deleteLastKth(SinglyLinkedNode** head_ref, int k) { if (*head_ref == NULL || k == 0) return; // 快指標向前移動 k-1 SinglyLinkedNode* fast = *head_ref; int i = 1; while (i < k && fast != NULL) { fast = fast->next; ++i; } // 如果快指標為空,說明結點個數小於 k if (fast == NULL) return; SinglyLinkedNode* slow = *head_ref; SinglyLinkedNode* prev = NULL; while (fast->next != NULL) { fast = fast->next; prev = slow; slow = slow->next; } // 如果 prev 為空,頭結點剛好是第 k 個結點 if (!prev) { (*head_ref) = (*head_ref)->next; } else { prev->next = slow->next; } free(slow); }
void test_deleteLastKth() { SinglyLinkedNode* head = NULL; insertNode(&head, 1); insertNode(&head, 2); insertNode(&head, 3); insertNode(&head, 4); insertNode(&head, 5); // 1. 刪除頭結點 deleteLastKth(&head, 5); printLinkedList(head); // 2. 刪除中間結點 deleteLastKth(&head, 2); printLinkedList(head); }
/** 求中間結點 */
SinglyLinkedNode* findMiddleNode(SinglyLinkedNode* head) { if (!head) return NULL; SinglyLinkedNode* slow = head; SinglyLinkedNode* fast = head; // 1. 慢指標走一步,快指標兩步 while (fast->next != NULL && fast->next->next != NULL) { slow = slow->next; fast = fast->next->next; } return slow; }
void test_findMiddleNode() { SinglyLinkedNode* head = NULL; insertNode(&head, 1); insertNode(&head, 2); insertNode(&head, 3); insertNode(&head, 4); insertNode(&head, 5); SinglyLinkedNode* middleNode = findMiddleNode(head); printf("%d\n", middleNode->data); printLinkedList(head); }
/** 工具方法 */
// 插入新結點到連結串列頭部 void insertNode(SinglyLinkedNode** head_ref, int data) { SinglyLinkedNode* new_node = malloc(sizeof(SinglyLinkedNode)); new_node->data = data; new_node->next = *head_ref; *head_ref = new_node; }
// 列印連結串列 void printLinkedList(SinglyLinkedNode* node) { printf("--- start ---\n"); while (node) { printf("data: %d\n", node->data); node = node->next; } printf("--- end ---\n"); }
// 跑測試 void test() { test_reverse(); // test_checkCircle(); // test_mergeSortedLinkedList(); // test_deleteLastKth(); // test_findMiddleNode(); }