C語言中單鏈表的基本操作指南(增刪改查)
1.鏈表概述
鏈表是一種常見的數(shù)據(jù)結(jié)構(gòu)。它與常見的數(shù)組是不同的,使用數(shù)組時先要指定數(shù)組包含元素的個數(shù),即為數(shù)組的長度,但是如果向這個數(shù)組中加入的元素超過了數(shù)組的大小時,便不能將內(nèi)容全部保存。
鏈表這種存儲方式,其元素個數(shù)是不受限定的,當(dāng)進(jìn)行添加元素的時候存儲的個數(shù)就會隨之改變。
鏈表一般有兩種形式,有空頭鏈表和無空頭鏈表。
在鏈表中有一個頭指針變量,這個指針變量保存一個地址,通過這個地址來找到這個鏈表,頭指針節(jié)點指向第一個節(jié)點,在鏈表中每個節(jié)點包含兩個部分:數(shù)據(jù)部分和指針部分。雖然結(jié)構(gòu)體不能含有與本身類型相同的結(jié)構(gòu),但是可以含有之相同類型結(jié)構(gòu)的指針,這種定義是鏈表的基礎(chǔ),鏈表中每一項都包含在何處能找到下一項的信息。而最后一個節(jié)點的指針指向必須為空NULL,從鏈表的原理來看不用擔(dān)心鏈表的長度會超出范圍這種問題。
2.鏈表的基本使用
2.0 準(zhǔn)備工作
使用鏈表時,首先應(yīng)包含一些基本的頭文件,因為涉及到內(nèi)存的操作和字符串的操作。
#include "stdio.h" #include "stdlib.h" //提供malloc()和free() #include "string.h" //提供strcpy()等
malloc函數(shù)
其函數(shù)原型如下:
void *malloc(unsigned int size);
這個函數(shù)返回的是個void類型指針,所以在使用時應(yīng)注意強(qiáng)制類型轉(zhuǎn)換成需要的指針類型。
free函數(shù)
其函數(shù)原型如下:
void free(void *p);
這個函數(shù)是用來釋放指針p作指向的內(nèi)存區(qū)。
2.1 創(chuàng)建節(jié)點(結(jié)構(gòu)體)
struct Node { int a; //數(shù)據(jù)域 struct Node* next; //指針域(指向節(jié)點的指針) };
2.2 全局定義鏈表頭尾指針 方便調(diào)用
struct Node* head= NULL; struct Node* end = NULL;
2.3 創(chuàng)建鏈表,實現(xiàn)在鏈表中增加一個數(shù)據(jù)(尾添加)————增
void AddListTill(int a ) { //創(chuàng)建一個節(jié)點 struct Node* temp=(struct Node*)malloc(sizeof(struct Node)); //此處注意強(qiáng)制類型轉(zhuǎn)換 //節(jié)點數(shù)據(jù)進(jìn)行賦值 temp->a=a; temp->next=NULL; //連接分兩種情況1.一個節(jié)點都沒有2.已經(jīng)有節(jié)點了,添加到尾巴上 if(NULL==head) { head=temp; // end=temp; } else { end->next=temp; // end=temp; //尾結(jié)點應(yīng)該始終指向最后一個 } end=temp; //尾結(jié)點應(yīng)該始終指向最后一個 }
AddListTill函數(shù)的功能是尾添加的方式在鏈表的尾部增加一個節(jié)點,其中輸入的參數(shù)是這個節(jié)點的數(shù)據(jù)。首先創(chuàng)建一個節(jié)點并申請一個節(jié)點的內(nèi)存,之后對傳入節(jié)點的數(shù)據(jù)進(jìn)行賦值,注意尾添加的新節(jié)點的指針應(yīng)指向空;此時分兩種情況,1是鏈表中一個節(jié)點都沒有,那么這個節(jié)點既是頭結(jié)點也是尾結(jié)點;2是已經(jīng)有節(jié)點,那么新添加的節(jié)點將成為最后一個節(jié)點,而之前的節(jié)點因為成為了倒數(shù)第二個節(jié)點了所以它的指針應(yīng)該指向新添加的節(jié)點,之后全局變量尾結(jié)點應(yīng)該指向現(xiàn)在的節(jié)點(注意操作的先后順序不能變)。
2.4 遍歷鏈表 —————查
void ScanList() { struct Node *temp =head; //定義一個臨時變量來指向頭 while (temp !=NULL) { printf("%d\n",temp->a); temp = temp->next; //temp指向下一個的地址 即實現(xiàn)++操作 } }
ScanList函數(shù)的功能是遍歷這個鏈表,首先定義一個用于遍歷的臨時指針,用while循環(huán)實現(xiàn)遍歷輸出等操作。
2.5 查詢指定的節(jié)點 (遍歷 一個個找)
struct Node* FindNode(int a ) { struct Node *temp =head; while(temp !=NULL) { if(a == temp->a) { return temp; } temp = temp->next; } //沒找到 return NULL; }
FindNode函數(shù)的功能仍然是遍歷鏈表,只不過會對每個節(jié)點中的數(shù)據(jù)進(jìn)行一一判斷,若找到則返回該節(jié)點,若沒找到則返回NULL。
2.6 鏈表清空——————全部刪除
void FreeList() { //一個一個NULL struct Node *temp =head; //定義一個臨時變量來指向頭 while (temp !=NULL) { // printf("%d\n",temp->a); struct Node* pt =temp; temp = temp->next; //temp指向下一個的地址 即實現(xiàn)++操作 free(pt); //釋放當(dāng)前 } //頭尾清空 不然下次的頭就接著0x10 head =NULL; end =NULL; }
FreeList函數(shù)仍是采用遍歷的方式一個一個的將節(jié)點內(nèi)存釋放,最后實現(xiàn)全部刪除的效果,但是要注意在最后應(yīng)該講頭尾節(jié)點至NULL否則下次的鏈表將會接著這次的頭尾。
2.7.在指定位置插入節(jié)點 ————在指定位置增
void AddListRand(int index,int a) { if (NULL==head) { printf("鏈表沒有節(jié)點\n"); return; } struct Node* pt =FindNode(index); if(NULL==pt) //沒有此節(jié)點 { printf("沒有指定節(jié)點\n"); return; } //有此節(jié)點 //創(chuàng)建臨時節(jié)點,申請內(nèi)存 struct Node* temp =(struct Node *)malloc(sizeof(struct Node)); //節(jié)點成員進(jìn)行賦值 temp->a=a; temp->next=NULL; //連接到鏈表上 1.找到的節(jié)點在尾部 2.找到的節(jié)點在中間 if (pt == end) { //尾巴的下一個指向新插入的節(jié)點 end->next=temp; //新的尾巴 end=temp; }else { // 先連后面 (先將要插入的節(jié)點指針指向原來找到節(jié)點的下一個) temp->next=pt->next; //后連前面 pt->next=temp; } }
首先要知道在指定節(jié)點插入的過程就像手拉手得人在一條線,這時來了一個新人,他要求站在甲之后,首先要找到甲的位置,如果鏈表為空或者沒有甲則無法插入,如果鏈表不為空并且甲在這個鏈表中,則還要看甲是在鏈表中間還是甲就在最后的尾巴上,如果在尾巴上則新插入的即為尾巴如圖1,若在甲乙之間則需要先連上后面乙再連上前面的甲,如圖2。
2.8尾刪除————刪
void DeleteListTail() { if (NULL == end) { printf("鏈表為空,無需刪除\n"); return; } //鏈表不為空 //鏈表有一個節(jié)點 if (head==end) { free(head); head=NULL; end=NULL; } else { //找到尾巴前一個節(jié)點 struct Node* temp =head; while (temp->next!=end) { temp = temp->next; } //找到了,刪尾巴 //釋放尾巴 free(end); //尾巴遷移 end=temp; //尾巴指針為NULL end->next=NULL; } }
尾刪除的過程和前面一樣首先應(yīng)判斷這個鏈表是不是為空或者只有一個節(jié)點,若只有一個節(jié)點則直接置NULL,若不為空,則先通過遍歷找到倒數(shù)第二個節(jié)點,安徽將最后一個節(jié)點釋放內(nèi)存,再講倒數(shù)第二個節(jié)點設(shè)置為end,然后將它的指針指向NULL。
2.9 刪除頭——————刪
void DeleteListHead() { //記住舊頭 struct Node* temp=head; //鏈表檢測 if (NULL==head) { printf("鏈表為空\n"); return; } head=head->next;//頭的第二個節(jié)點變成新的頭 free(temp); }
先定義一個臨時變量指向舊的頭,將頭的第二個記為新的頭指針head,之后將舊的頭釋放
2.10 刪除指定節(jié)點
void DeleteListRand(int a) { //鏈表判斷 是不是沒有東西 if(NULL==head) { printf("鏈表沒東西\n"); return; } //鏈表有東西,找這個節(jié)點 struct Node* temp =FindNode(a); if(NULL==temp) { printf("查無此點\n"); return; } //找到了,且只有一個節(jié)點 if(head==end) { free(head); head=NULL; end=NULL; } else if(head->next==end) //有兩個節(jié)點 { //看是刪除頭還是刪除尾 if(end==temp) { DeleteListTail(); } else if(temp==head) { DeleteListHead(); } } else//多個節(jié)點 { //看是刪除頭還是刪除尾 if(end==temp) DeleteListTail(); else if(temp==head) DeleteListHead(); else //刪除中間某個節(jié)點 { //找要刪除temp前一個,遍歷 struct Node*pt =head; while(pt->next!=temp) { pt=pt->next; } //找到了 //讓前一個直接連接后一個 跳過指定的即可 pt->next=temp->next; free(temp); } } }
情況與前面增加類似不再贅述,具體見圖
3. 測試主程序
下面是測試用的主程序,主要實現(xiàn)了鏈表的增刪查改等基本操作。
void main () { struct Node *pFind ; //創(chuàng)建5個節(jié)點 for(i=0;i<6;i++) AddListTill(i); // AddListRand(4,14); //在指定位置4增加節(jié)點14 // DeleteListTail(); //刪除一個尾結(jié)點 DeleteListRand(4); //刪除4節(jié)點 ScanList(); //便利輸出鏈表 FreeList(); //刪除鏈表 /* pFind = FindNode(5); //查找5節(jié)點 if (pFind != NULL) { printf("找到%d\n",pFind->a); //找到節(jié)點并且輸出該節(jié)點數(shù)據(jù) } else { printf("No Find!\n"); } */ }
有關(guān)無空頭的單鏈表的基本操作就總結(jié)到這里,當(dāng)然還有雙鏈表等更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),以及遍歷和查找的優(yōu)化算法也有待進(jìn)一步探索與學(xué)習(xí)。
總結(jié)
到此這篇關(guān)于C語言中單鏈表的增刪改查基本操作的文章就介紹到這了,更多相關(guān)C語言單鏈表增刪改查操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt6遠(yuǎn)程連接MySQL數(shù)據(jù)庫的簡單易上手版
在Qt應(yīng)用程序里,可實現(xiàn)遠(yuǎn)程MySQL服務(wù)器的連接操作,本文就來介紹一下Qt6遠(yuǎn)程連接MySQL數(shù)據(jù)庫,具有一定的參考價值,感興趣的可以了解一下2023-11-11