1. 程式人生 > >連結串列的基本操作(C語言)詳解

連結串列的基本操作(C語言)詳解

連結串列及建立》一節我們學習瞭如何使用連結串列儲存資料元素,以及如何使用 C 語言建立連結串列。本節將詳細介紹對連結串列的一些基本操作,包括對連結串列中資料的新增、刪除、查詢(遍歷)和更改。

注意,以下對連結串列的操作實現均建立在已建立好連結串列的基礎上,建立連結串列的程式碼如下所示:
//宣告節點結構
typedef struct Link{
    int  elem;//儲存整形元素
    struct Link *next;//指向直接後繼元素的指標
}link;
//建立連結串列的函式
link * initLink(){
    link * p=(link*)malloc(sizeof(link));//建立一個頭結點
    link * temp=p;//宣告一個指標指向頭結點,用於遍歷連結串列
    //生成連結串列
    for (int i=1; i<5; i++) {
     //建立節點並初始化
        link *a=(link*)malloc(sizeof(link));
        a->elem=i;
        a->next=NULL;
        //建立新節點與直接前驅節點的邏輯關係
        temp->next=a;
        temp=temp->next;
    }
    return p;
}
從實現程式碼中可以看到,該連結串列是一個具有頭節點的連結串列。由於頭節點本身不用於儲存資料,因此在實現對連結串列中資料的"增刪查改"時要引起注意。

連結串列插入元素

順序表一樣,向連結串列中增添元素,根據新增位置不同,可分為以下 3 種情況:
  • 插入到連結串列的頭部(頭節點之後),作為首元節點;
  • 插入到連結串列中間的某個位置;
  • 插入到連結串列的最末端,作為連結串列中最後一個數據元素;

雖然新元素的插入位置不固定,但是連結串列插入元素的思想是固定的,只需做以下兩步操作,即可將新元素插入到指定的位置:
  1. 將新結點的 next 指標指向插入位置後的結點;
  2. 將插入位置前結點的 next 指標指向插入結點;

例如,我們在連結串列 {1,2,3,4} 的基礎上分別實現在頭部、中間部位、尾部插入新元素 5,其實現過程如圖 1 所示:

連結串列中插入元素的 3 種情況示意圖
圖 1 連結串列中插入元素的 3 種情況示意圖
從圖中可以看出,雖然新元素的插入位置不同,但實現插入操作的方法是一致的,都是先執行步驟 1 ,再執行步驟 2。

注意:連結串列插入元素的操作必須是先步驟 1,再步驟 2;反之,若先執行步驟 2,會導致插入位置後續的部分連結串列丟失,無法再實現步驟 1。

通過以上的講解,我們可以嘗試編寫 C 語言程式碼來實現連結串列插入元素的操作:
//p為原連結串列,elem表示新資料元素,add表示新元素要插入的位置
link * insertElem(link * p,int elem,int add){
    link * temp=p;//建立臨時結點temp
    //首先找到要插入位置的上一個結點
    for (int i=1; i<add; i++) {
        if (temp==NULL) {
            printf("插入位置無效\n");
            return p;
        }
        temp=temp->next;
    }   
    //建立插入結點c
    link * c=(link*)malloc(sizeof(link));
    c->elem=elem;
    //向連結串列中插入結點
    c->next=temp->next;
    temp->next=c;
    return  p;
}
提示,insertElem 函式中加入一個 if 語句,用於判斷使用者輸入的插入位置是否有效。例如,在已儲存 {1,2,3} 的連結串列中,使用者要求在連結串列中第 100 個數據元素所在的位置插入新元素,顯然使用者操作無效,此時就會觸發 if 語句。

連結串列刪除元素

從連結串列中刪除指定資料元素時,實則就是將存有該資料元素的節點從連結串列中摘除,但作為一名合格的程式設計師,要對儲存空間負責,對不再利用的儲存空間要及時釋放。因此,從連結串列中刪除資料元素需要進行以下 2 步操作:
  1. 將結點從連結串列中摘下來;
  2. 手動釋放掉結點,回收被結點佔用的儲存空間;

其中,從連結串列上摘除某節點的實現非常簡單,只需找到該節點的直接前驅節點 temp,執行一行程式:

temp->next=temp->next->next;

例如,從存有 {1,2,3,4} 的連結串列中刪除元素 3,則此程式碼的執行效果如圖 2 所示:

連結串列刪除元素示意圖
圖 2 連結串列刪除元素示意圖
因此,連結串列刪除元素的 C 語言實現如下所示:
//p為原連結串列,add為要刪除元素的值
link * delElem(link * p,int add){
    link * temp=p;
    //temp指向被刪除結點的上一個結點
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    link * del=temp->next;//單獨設定一個指標指向被刪除結點,以防丟失
    temp->next=temp->next->next;//刪除某個結點的方法就是更改前一個結點的指標域
    free(del);//手動釋放該結點,防止記憶體洩漏
    return p;
}
我們可以看到,從連結串列上摘下的節點 del 最終通過 free 函式進行了手動釋放。

連結串列查詢元素

在連結串列中查詢指定資料元素,最常用的方法是:從表頭依次遍歷表中節點,用被查詢元素與各節點資料域中儲存的資料元素進行比對,直至比對成功或遍歷至連結串列最末端的 NULL(比對失敗的標誌)。

因此,連結串列中查詢特定資料元素的 C 語言實現程式碼為:
//p為原連結串列,elem表示被查詢元素、
int selectElem(link * p,int elem){
//新建一個指標t,初始化為頭指標 p
    link * t=p;
    int i=1;
    //由於頭節點的存在,因此while中的判斷為t->next
    while (t->next) {
        t=t->next;
        if (t->elem==elem) {
            return i;
        }
        i++;
    }
    //程式執行至此處,表示查詢失敗
    return -1;
}
注意,遍歷有頭節點的連結串列時,需避免頭節點對測試資料的影響,因此在遍歷連結串列時,建立使用上面程式碼中的遍歷方法,直接越過頭節點對連結串列進行有效遍歷。

連結串列更新元素

更新連結串列中的元素,只需通過遍歷找到儲存此元素的節點,對節點中的資料域做更改操作即可。

直接給出連結串列中更新資料元素的 C 語言實現程式碼:
//更新函式,其中,add 表示更改結點在連結串列中的位置,newElem 為新的資料域的值
link *amendElem(link * p,int add,int newElem){
    link * temp=p;
    temp=temp->next;//在遍歷之前,temp指向首元結點
    //遍歷到被刪除結點
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    temp->elem=newElem;
    return p;
}

總結

以上內容詳細介紹了對連結串列中資料元素做"增刪查改"的實現過程及 C 語言程式碼,在此給出本節的完整可執行程式碼:
#include <stdio.h>
#include <stdlib.h>

typedef struct Link{
    int  elem;
    struct Link *next;
}link;
link * initLink();
//連結串列插入的函式,p是連結串列,elem是插入的結點的資料域,add是插入的位置
link * insertElem(link * p,int elem,int add);
//刪除結點的函式,p代表操作連結串列,add代表刪除節點的位置
link * delElem(link * p,int add);
//查詢結點的函式,elem為目標結點的資料域的值
int selectElem(link * p,int elem);
//更新結點的函式,newElem為新的資料域的值
link *amendElem(link * p,int add,int newElem);
void display(link *p);

int main() {
    //初始化連結串列(1,2,3,4)
    printf("初始化連結串列為:\n");
    link *p=initLink();
    display(p);
  
    printf("在第4的位置插入元素5:\n");
    p=insertElem(p, 5, 4);
    display(p);
  
    printf("刪除元素3:\n");
    p=delElem(p, 3);
    display(p);
  
    printf("查詢元素2的位置為:\n");
    int address=selectElem(p, 2);
    if (address==-1) {
        printf("沒有該元素");
    }else{
        printf("元素2的位置為:%d\n",address);
    }
    printf("更改第3的位置上的資料為7:\n");
    p=amendElem(p, 3, 7);
    display(p);
  
    return 0;
}

link * initLink(){
    link * p=(link*)malloc(sizeof(link));//建立一個頭結點
    link * temp=p;//宣告一個指標指向頭結點,用於遍歷連結串列
    //生成連結串列
    for (int i=1; i<5; i++) {
        link *a=(link*)malloc(sizeof(link));
        a->elem=i;
        a->next=NULL;
        temp->next=a;
        temp=temp->next;
    }
    return p;
}
link * insertElem(link * p,int elem,int add){
    link * temp=p;//建立臨時結點temp
    //首先找到要插入位置的上一個結點
    for (int i=1; i<add; i++) {
        if (temp==NULL) {
            printf("插入位置無效\n");
            return p;
        }
        temp=temp->next;
    }
    //建立插入結點c
    link * c=(link*)malloc(sizeof(link));
    c->elem=elem;
    //向連結串列中插入結點
    c->next=temp->next;
    temp->next=c;
    return  p;
}

link * delElem(link * p,int add){
    link * temp=p;
    //遍歷到被刪除結點的上一個結點
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    link * del=temp->next;//單獨設定一個指標指向被刪除結點,以防丟失
    temp->next=temp->next->next;//刪除某個結點的方法就是更改前一個結點的指標域
    free(del);//手動釋放該結點,防止記憶體洩漏
    return p;
}
int selectElem(link * p,int elem){
    link * t=p;
    int i=1;
    while (t->next) {
        t=t->next;
        if (t->elem==elem) {
            return i;
        }
        i++;
    }
    return -1;
}
link *amendElem(link * p,int add,int newElem){
    link * temp=p;
    temp=temp->next;//tamp指向首元結點
    //temp指向被刪除結點
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    temp->elem=newElem;
    return p;
}
void display(link *p){
    link* temp=p;//將temp指標重新指向頭結點
    //只要temp指標指向的結點的next不是Null,就執行輸出語句。
    while (temp->next) {
        temp=temp->next;
        printf("%d ",temp->elem);
    }
    printf("\n");
}
程式碼執行結果:

初始化連結串列為:
1 2 3 4
在第4的位置插入元素5:
1 2 3 5 4
刪除元素3:
1 2 5 4
查詢元素2的位置為:
元素2的位置為:2
更改第3的位置上的資料為7:
1 2 7 4

相關推薦

連結串列基本操作C語言

《連結串列及建立》一節我們學習瞭如何使用連結串列儲存資料元素,以及如何使用 C 語言建立連結串列。本節將詳細介紹對連結串列的一些基本操作,包括對連結串列中資料的新增、刪除、查詢(遍歷)和更改。 注意,以下對連結串列的操作實現均建立在已建立好連結串列的基礎上,建立連結串列的程式碼如下所示: //宣告節點結構

靜態連結串列基本操作C語言實現

上節,我們初步建立了一個靜態連結串列,本節學習有關靜態連結串列的一些基本操作,包括對錶中資料元素的新增、刪除、查詢和更改。 本節是建立在已能成功建立靜態連結串列的基礎上,因此我們繼續使用上節中已建立好的靜態連結串列學習本節內容,建立好的靜態連結串列如圖 1 所示: 圖 1 建立好的靜態連結串列 靜態

LeetCode 61. 旋轉連結串列 Rotate ListC語言

題目描述: 給定一個連結串列,旋轉連結串列,將連結串列每個節點向右移動 k 個位置,其中 k 是非負數。 示例 1: 輸入: 1->2->3->4->5->NULL, k = 2 輸出: 4->5->1->2->3

資料結構實驗之連結串列六:有序連結串列的建立C語言

#include<stdio.h> #include<stdlib.h> struct ns  { int m; struct ns *next; }; int main() { int n,i; struct ns

單鏈表的基本操作C語言//以整型為例

        單鏈表與陣列相似,但是單鏈表堆記憶體的運用更加的方便,能夠充分的利用零散的記憶體,在中間新增或者刪除一個或多個元素時不需要像陣列一樣移動大量的元素。單鏈表的操作中,涉及到單鏈表元素變化的許耀中指向指標的指標操作。        下面是單鏈表的兩種建立方式以及其

順序表的插入操作原理及實現C語言

順序表中存放資料的特點和陣列這種資料型別完全吻合,所以順序表的實現使用的是陣列。換句話說,順序表中插入元素問題也就等同於討論如何向陣列中插入資料。 因此,順序表中插入資料元素,無非三種情況: 在表頭插入; 在表的中間某個位置插入; 直接尾隨順序表,作為表的最後一個元素; 無論在順序表的什麼位置插

資料結構—連結串列基本操作c語言程式碼

連結串列連結串列也是一種線性表,與順序表不同之處在於不像順序表佔據一段連續的儲存空間,而是將儲存單元分散在記憶體的任意地址上。連結串列結構中,儲存每個資料時候都會把記錄寫在連結串列的一個結點(node)中,每個結點之間由指標相連,形成如同鏈子的結構。結點(node):可以是一

連結串列的插入和刪除操作C語言實現+註釋

連結串列的基本操作中,連結串列結點的插入和刪除相對比較複雜,需根據結點插入位置的不同,使用合理的方法在不破壞原連結串列結構的前提下將其插入到連結串列中。 本節將詳解介紹這兩種操作的具體實現方法,讀者只需牢記實現步驟,即可輕鬆解決這兩大難點。 連結串列中插入結點 連結串列中插入結點,根據插入位置的不同,可

單鏈表,迴圈連結串列,雙鏈表及其基本操作C++實現

    最近在學習嚴蔚敏教授的《資料結構》,有一些感想,在這裡寫下來,留做筆記,希望能對以後學習有所幫助。     我們知道,線性表就是n個數據元素的有限序列,它有兩種實現方式,其一為順序表,即陣列+偽指標的方式實現,另一為連結串列,採用的是指標的方式實現。由於順序表的知識

棧的基本操作C語言

概念 一種特殊的線性表,只能在固定的一端進行插入和刪除操作,這個固定的一端稱為棧頂,另外一端稱為棧底,沒有任何元素的棧稱為空棧!! 棧的特性 先進後出或者說後進先出!! 另外,棧分為順序棧以及鏈式棧。 棧的功能 將資料從一種序列改變為另外

堆疊的簡單實現之一:基本操作C語言實現

堆疊(Stack)是一種操作受限的線性表,堆疊的插入和刪除操作只能在一端進行。堆疊遵循著先進後出或者叫後進先出的原則。在堆疊中,允許插入和刪除的一端叫著棧頂(Top),另外一端叫著棧底(Bottom)

連結串列-遊標實現C語言

如果用C/C++寫連結串列的話,用指標會比較方便,但很多語言都沒有指標,那麼怎麼實現比較好呢?遊標是個不錯的選擇。 在用指標實現的連結串列中,有這樣兩個特點: 1.資料存在一組結構體中,並且每個結構體都有指向下一個結構體的指標。 2.一個新

學習筆記——單鏈表的基本操作C語言實現

線性表的儲存結構有順序儲存結構(順序表)和鏈式儲存結構(連結串列)兩種。順序表在之前的部落格有介紹過,不明白的朋友可檢視:靜態分配順序表的基本操作及動態分配順序表的基本操作。相對於順序表來說,連結串列稍微難一些,本人花了兩天的時間認真查看了一些資料,終於大致明白了一些東西。現

資料結構—順序表基本操作c語言程式碼

順序表計算機內部儲存一張線性表是用一組連續地址記憶體單元,這種儲存結構即為順序儲存結構,這種結構下的線性表叫順序表。順序表有兩種定義方法:                                    1.靜態定義                           

二叉樹的相關操作c語言

二叉樹的相關操作:包括先序序列+中序序列建樹丶後序序列+中序序列建樹丶層次序列+中序序列建樹;先序遍歷丶中序遍歷丶後序遍歷丶層次遍歷;二叉樹的深度及最大寬度;度分別為0,1,2的節點個數以及總結點個數 #include<stdio.h> #include<malloc.h> #i

順序迴圈佇列的基本運算C語言

迴圈佇列sq中: 1. front(隊頭指標)指向實際佇列元素的第一個元素的前一個位置,rear(隊尾指標)指向實際佇列元素的最後一個元素位置。(可根據需要自定義) 2. 迴圈佇列中的滿並非真正意義上的

資料庫的基本使用C#語言

目錄 insert select 的使用 delete update 更新 ADO.Net 平臺的使用 在C#中使用的格式 insert 在 C# 的使用 delete 的使用 資料庫的基本使用 @ insert 格式: insert i

資料結構——單鏈表實現及操作c語言

#include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #d

資料結構之順序佇列的操作C語言

#include <stdio.h> #include <stdlib.h> #include <string.h> #define QUEUELEN 15 //資料結構的定義 typedef struct { char name[

順序表基本操作c實現

順序表就是以陣列形式儲存的線性表,本文將在PTA上做過的題的程式碼copy下來,供以參考,詳解見註釋 //庫函式標頭檔案包含 #include<stdio.h> #include<malloc.h> #include<stdlib.h>