首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言單向鏈表核心操作完整實現:創建/遍歷/增刪改查/銷毀

     編輯:關於C語言

C語言單向鏈表核心操作完整實現:創建/遍歷/增刪改查/銷毀

單向鏈表是數據結構教學與工程實踐的基石。本文提供一個標準、完整、可編譯運行的C語言單向鏈表實現,涵蓋節點定義、鏈表創建、遍歷打印、清空銷毀、判空、求長度、按位置查找、插入、刪除等全部核心操作,代碼風格規範,邏輯清晰,適合教學參考與項目移植。

數據結構定義

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

typedef struct LinkNode {
    int data;                    // 數據域(本例為int,可泛化為void*)
    struct LinkNode* next;       // 指針域
} LinkNode, *LinkList;           // 別名:LinkList 等價於 LinkNode*

核心操作函數實現

1. 創建鏈表(尾插法,-1結束)

LinkList LinkCreate() {
    LinkList head = NULL, tail = NULL;
    int val;
    while (1) {
        scanf("%d", &val);
        if (val == -1) break;

        LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode));
        if (!newNode) { perror("malloc failed"); exit(EXIT_FAILURE); }
        newNode->data = val;
        newNode->next = NULL;

        if (!head) {
            head = tail = newNode;
        } else {
            tail->next = newNode;
            tail = newNode;
        }
    }
    return head;  // 返回頭指針(無哨兵節點版本)
}

2. 遍歷打印

void LinkPrint(LinkList head) {
    LinkNode* p = head;
    while (p) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

3. 銷毀鏈表(釋放所有節點)

void ClearList(LinkList head) {
    LinkNode *curr = head, *next;
    while (curr) {
        next = curr->next;
        free(curr);
        curr = next;
    }
    // 注意:調用者需自行將頭指針置NULL
}

4. 判空

bool ListEmpty(LinkList head) {
    return head == NULL;
}

5. 求長度

int ListLength(LinkList head) {
    int len = 0;
    LinkNode* p = head;
    while (p) {
        len++;
        p = p->next;
    }
    return len;
}

6. 按位置查找(1-based索引)

int GetElem(LinkList head, int pos) {
    if (pos < 1 || pos > ListLength(head)) return -1;  // 錯誤碼
    LinkNode* p = head;
    for (int i = 1; i < pos; i++) p = p->next;
    return p->data;
}

7. 按位置插入(1-based,插入到pos位置,原pos及之後後移)

bool ListInsert(LinkList* headRef, int val, int pos) {
    int len = ListLength(*headRef);
    if (pos < 1 || pos > len + 1) return false;  // 允許在尾部插入(pos=len+1)

    LinkNode* newNode = (LinkNode*)malloc(sizeof(LinkNode));
    if (!newNode) return false;
    newNode->data = val;

    if (pos == 1) {  // 頭插
        newNode->next = *headRef;
        *headRef = newNode;
        return true;
    }

    // 找到第 pos-1 個節點
    LinkNode* p = *headRef;
    for (int i = 1; i < pos - 1; i++) p = p->next;
    newNode->next = p->next;
    p->next = newNode;
    return true;
}

8. 按位置刪除(1-based)

bool ListDelete(LinkList* headRef, int pos) {
    if (pos < 1 || pos > ListLength(*headRef)) return false;

    LinkNode* delNode;
    if (pos == 1) {  // 刪除頭節點
        delNode = *headRef;
        *headRef = delNode->next;
    } else {
        LinkNode* p = *headRef;
        for (int i = 1; i < pos - 1; i++) p = p->next;
        delNode = p->next;
        p->next = delNode->next;
    }
    free(delNode);
    return true;
}

主函數測試驗證

int main() {
    printf("請輸入鏈表數據(-1結束):");
    LinkList list = LinkCreate();
    printf("創建完成:"); LinkPrint(list);

    printf("長度:%d\n", ListLength(list));
    printf("第3個元素:%d\n", GetElem(list, 3));

    ListInsert(&list, 99, 2);
    printf("在位置2插入99:"); LinkPrint(list);

    ListDelete(&list, 1);
    printf("刪除頭節點:"); LinkPrint(list);

    ClearList(list);
    printf("銷毀後判空:%s\n", ListEmpty(list) ? "真" : "假");
    return 0;
}

關鍵技術點總結

操作時間複雜度關鍵難點邊界處理
創建O(n)尾指針維護空表、單節點
遍歷O(n)指針推進空表
查找O(n)索引轉指針越界返回錯誤碼
插入O(n)前驅節點定位、頭插特判pos=1, pos=len+1
刪除O(n)前驅節點定位、釋放內存、頭刪特判pos=1, pos=len
銷毀O(n)釋放前保存next調用者置NULL

常見錯誤與最佳實踐

  1. 刪除/插入未雙向傳頭指針:頭節點變更需傳 LinkList*(二級指針)
  2. free後未置NULL:雖本函數作用域結束,但調用者殘留懸空指針極危險
  3. malloc未檢查返回值:嵌入式/高可靠系統必須檢查
  4. 索引體系不統一:全項目統一 0-based 或 1-based,本文採用 1-based 符合教材習慣
  5. 哨兵節點 vs 無哨兵:哨兵節點可統一頭插/頭刪邏輯,略增內存;本文採用無哨兵版本

擴展方向

  • 泛型鏈表:void* data + 銷毀函數指針 + 比較函數指針
  • 雙向鏈表:增加 prev 指針,O(1) 尾部操作、反向遍歷
  • 循環鏈表:尾節點指向頭,適用循環調度、Josephus問題
  • 跳表:多層索引,O(log n) 查找,Redis有序集合底層結構

總結

本文提供的單向鏈表實現代碼結構清晰、邊界處理完善、內存管理規範,涵蓋了數據結構教學大綱要求的全部基本操作。掌握本文代碼模式,即可靈活應對考試填空、面試手寫、項目開發中的鏈表相關需求。建議讀者在理解基礎上,嘗試實現帶哨兵節點版本、泛型版本及雙向鏈表,深化指針操作功力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved