1. 程式人生 > >連結串列常用操作 單鏈表反轉 連結串列中環的檢測 兩個有序的連結串列合併 刪除連結串列倒數第 n 個結點 求連結串列的中間結點

連結串列常用操作 單鏈表反轉 連結串列中環的檢測 兩個有序的連結串列合併 刪除連結串列倒數第 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(); }