基本數據結構 -- 鏈表的遍歷、查找、插入和刪除


  本文將使用 C 語言來實現一個單鏈表,並實現遍歷、查找、插入、刪除等操作。

一、創建一個單鏈表

   首先,定義一個存放結點相關信息的結構體,結構體有兩個元素,分別是鍵值和一個指向下一節點的指針。

/* 用於存放結點信息的結構體 */
struct node {
    int key;
    struct node *next;
};

typedef struct node Node;
typedef struct node *PtrToNode;

   想要創建一個單鏈表,可以先創建一個表頭結點(啞結點),然后在表頭結點后不斷插入新的結點即可,需要注意的是,每新建一個結點都要為該結點分配一段內存空間。

/* 創建一個鏈表 */
PtrToNode CreateList(int listLen)
{
    int i, keyValue;

    /* 創建一個表頭結點,並為其分配內存空間 */
    PtrToNode headPtr = (PtrToNode)malloc(sizeof(Node));

    if (headPtr == NULL) {
        perror("malloc failed!\n");
        exit(EXIT_FAILURE);
    }

    PtrToNode tailNode = headPtr;    // 創建一個表尾結點,並將表頭結點賦給尾結點
    tailNode->next = NULL;

    for (i = 0; i < listLen; i++) {
        /* 創建一個新結點,並為其分配內存空間 */
        PtrToNode newNode = (PtrToNode)malloc(sizeof(Node));
        if (newNode == NULL) {
            perror("malloc failed!\n");
            exit(EXIT_FAILURE);
        }

        printf("請輸入第 %d 個結點的鍵值:", i + 1);
        scanf_s("%d",&keyValue);

     // 將 newNode 插入鏈表尾部
        newNode->key = keyValue;    // 賦鍵值
        newNode->next = NULL;     // next 指針指向 NULL
        tailNode->next = newNode;   // 這里的 tailNode 存放的是上一次循環中創建的 newNode,也就是現在新建結點的前驅結點
                       // 故而這里是將前驅結點的 next 指針指向當前結點

        tailNode = newNode;       // 將當前結點賦給 tailNode(實際上,tailNode 就起着一個臨時結點的作用)
    }

    return headPtr;
}

 

二、遍歷一個單鏈表

/* 遍歷鏈表 */
void TraverseList(PtrToNode List)
{
    PtrToNode ptr = List->next;
    if (ptr == NULL) {
        printf("鏈表為空\n");
    }

    while (ptr != NULL) {
        printf("%d ", ptr->key);
        ptr = ptr->next;
    }
}

   這段代碼根據鏈表表尾結點的 next 指針指向 NULL 來遍歷整個鏈表。

 

三、查找一個元素

/* 查找一個元素 */
PtrToNode FindElement(PtrToNode List,int val)
{
    PtrToNode ptr = List->next;
    if (ptr == NULL) {
        printf("鏈表為空\n");
        return NULL;
    }

    while (ptr != NULL && ptr->key != val) {
        ptr = ptr->next;
    }

    if (ptr != NULL) {
        printf("找到 %d 了\n", val);
    }
    else
    {
        printf("沒有找到 %d\n", val);
    }    
    
    return ptr;
}

  這段代碼查找元素 val 是否在鏈表中,如果在,則打印元素已找到的信息,並返回該元素在鏈表中所在的結點;如果不在鏈表中,則打印沒找到的信息,並返回一個空指針。

 

四、插入一個元素

/* 插入一個元素 */
void InsertElement(PtrToNode List,PtrToNode Position,int val) 
{
    PtrToNode tmpNode = (PtrToNode)malloc(sizeof(Node));
    if (tmpNode == NULL) {
        perror("malloc failed!\n");
        exit(EXIT_FAILURE);
    }

    tmpNode->key = val;
    tmpNode->next = Position->next;
    Position->next = tmpNode;
}

  這段代碼將元素 val 插入到鏈表中指定結點的后面。 

 

五、刪除操作

5.1 刪除整個鏈表

/* 刪除整個鏈表 */
void DeleteList(PtrToNode List)
{
    PtrToNode position, tmpNode;
    position = List->next;
    List->next = NULL;
    while (position != NULL) {
        tmpNode = position->next;        // 先將當前結點的 next 指針賦給臨時結點保存
        free(position);                    // 然后釋放當前結點
        position = tmpNode;                // 再將以保存的 next 指針賦給 position,即為下一個要刪除的結點
    }
}

  刪除整個鏈表時,需要注意一點,要提前將要刪除結點的 next 指針保存下來,再釋放該結點。而不能在釋放了一個結點后再去利用已釋放結點的 next 指針去釋放下一個結點,因為此時上一個結點已經被釋放了,故而找不到 next 指針。此外,由於在創建鏈表時,每插入一個新的結點都會用 malloc 來給結點分配一塊內存,故而在刪除鏈表時,每釋放一個結點也應該使用 free 來釋放一次內存。

5.2 刪除一個元素

/* 刪除一個元素 */
void DeleteElement(PtrToNode List,int val)
{
    PtrToNode tmpNode;
    PtrToNode prev_position = FindPrevNode(List, val);
    if (prev_position->next == NULL) {
        printf("要刪除的元素不存在!\n");
    }
    else {
        tmpNode = prev_position->next;
        prev_position->next = tmpNode->next;
        free(tmpNode);
    }

}

/* 獲取元素的前驅結點 */
PtrToNode FindPrevNode(PtrToNode List, int val)
{
    PtrToNode prev_position = List;

    while (prev_position->next != NULL && prev_position->next->key != val) {
        prev_position = prev_position->next;
    }

    return prev_position;
}

  刪除一個元素時,需要先找到該元素的前驅結點。 

 

參考資料:

《算法導論 第三版》

《數據結構與算法分析——C語言描述》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM