猶豫了幾天,看了很多大牛寫的關於c語言鍊錶,感觸很多,終於下定決心,把自己對於鍊錶的理解隨之附上,可用與否,自行裁奪。由於作者水平有限也是第一次寫,不足之處,竭誠希望得到各位大神的批評指正。製作不易,不喜勿噴,謝謝!!!
在正文開始之前,我先對陣列和鍊錶進行簡單的對比分析。
鍊錶也是一種很常見的資料結構,不同於陣列的是它是動態進行儲存分配的一種結構。陣列存放資料時,必須要事先知道元素的個數。舉個例子,比如乙個班有40個人,另乙個班有100個人,如果要用同乙個陣列先後來存放這兩個班的學生資料,那麼必須得定義長度為100的陣列。如果事先不確定乙個班的人數,只能把陣列定義的足夠大,以能存放任何班級的學生資料。這樣就很浪費記憶體,而且陣列對於記憶體的要求必須是是連續的,資料小的話還好說,資料大的話記憶體分配就會失敗,陣列定義當然也就失敗。還有陣列對於插入以及刪除元素的效率也很低這就不一一介紹了。然而鍊錶就相對於比較完美,它很好的解決了陣列存在的那些問題。它儲存資料時就不需要分配連續的空間,對於元素的插入以及刪除效率就很高。可以說鍊錶對於記憶體就是隨用隨拿,不像陣列要事先申請。當然,有優點就必然有缺點,就比如說煉表裡每乙個元素裡面都多包含乙個位址,或者說多包含乙個存放位址的指標變數,所以記憶體開銷就很大。還有因為鍊錶的記憶體空間不是連續的,所以想找到其中的某乙個資料就沒有陣列那麼方便,必須先得到該元素的上乙個元素,根據上乙個元素提供的下一元素位址去找到該元素。所以不提供「頭指標」(下文中「頭指標」為「phead」),那麼整個鍊錶將無法訪問。鍊錶就相當於一條鐵鍊一環扣一環(這個稍後會詳細的說)。
單向鍊錶
上面我提到過煉表是動態進行儲存分配的一種結構。鍊錶中的每乙個元素稱為「結點」,每個結點都包括兩部分:一部分為使用者需要的實際資料,另一部分為下一結點的位址。鍊錶有乙個「頭指標(phead)」變數,存放著乙個位址,該位址指向第乙個結點,第乙個結點裡面存放著第二個結點的位址,第二個結點又存放著第三個結點位址。就這樣頭指標指向第乙個結點,第乙個結點又指向第二個…直到最後乙個結點。最後乙個結點不再指向其他結點,位址部分存放乙個「null」。 見下圖:(表中有乙個尾指標(pend)其作用後面會解釋)
c語言單項鍊表尾新增整體**如下:(詳解附後)
#include
#include
#include
//函式宣告
//尾新增
void
wei_tian_jia
(struct node*
* phead,
struct node*
* pend,
int shu_ju)
;//尾新增(沒有尾指標)
void
wei_tian_jia_
(struct node*
* phead,
int shu_ju)
;//釋放鍊錶
void
shi_fang_lian_biao
(struct node* phead)
;//釋放鍊錶(並是頭指標(phead)尾指標(pend)指向空)
void
shi_fang_lian_biao_free
(struct node*
* phead,
struct node*
* pend)
;//輸出鍊錶
void
shu_chu
(struct node* phead)
;//定義乙個鍊錶結構體
struct node
;int
main
(void
)//尾新增
void
wei_tian_jia
(struct node*
* phead,
struct node*
* pend,
int shu_ju)
else}}
//尾新增(沒有尾指標)
void
wei_tian_jia_
(struct node*
* phead1,
int shu_ju)
else
ptemp2->pnext = ptemp;}}
}//輸出鍊錶
void
shu_chu
(struct node* phead)
}//釋放鍊錶
void
shi_fang_lian_biao
(struct node* phead)
free
(phead);}
//釋放鍊錶(並是頭指標(phead)尾指標(pend)指向空)
void
shi_fang_lian_biao_free
(struct node*
* phead,
struct node*
* pend)
*phead =
null
;*phead =
null
;}
部分**詳解:
(再次申明:由於作者水平有限,所以有的變數名用的拼音。見笑,莫怪!!!為了簡單明瞭,方便起見,我定義了乙個實際資料。)
「頭指標」(phead)以及「尾指標」(pend):
頭指標很好理解指向首結點用於遍歷整個陣列,而尾指標呢?我們先看下面兩段**一段是有尾指標的一段是沒有尾指標的:
顯然這是一段有尾指標的**。這裡的思想就是當寫入第乙個成員進鍊表的時候,此時鍊錶就乙個成員,即是頭(phead),也是尾(pend),當寫入第二個成員的時候,煉表頭(pheald)不動鍊錶尾(pend)向後移,指向最後乙個結點。
//尾新增
void
wei_tian_jia
(struct node*
* phead,
struct node*
* pend,
int shu_ju)
else
}}
那麼下面這段**是沒有尾指標的。它的思想就是頭指標一直指向第乙個結點,然後通過遍歷來找到最後乙個結點,從而使最後乙個結點裡面的指標指向所要插入的元素。
//尾新增(沒有尾指標)
void
wei_tian_jia_
(struct node*
* phead1,
int shu_ju)
else
ptemp2->pnext = ptemp;}}
}
我把上面**裡面的一段摘出來說明一下。
這段**裡面可以看到我又定義了乙個ptemp2指標變數,為什麼呢?前面我提到過沒有尾指標的時候新增結點的思想就是要遍歷陣列,從而找到最後乙個結點然後讓它指向我們要插入的結點,如果沒有這個phead2,我們遍歷完鍊錶以後我們的頭指標phead1就已經指向了最後乙個結點了,單項鍊表如果頭指標移動了,資料就會找不到了。所以我定義了乙個中間變數裝著頭指標然後去遍歷鍊錶,讓頭指標永遠指向鍊錶的頭。
else
ptemp2->pnext = ptemp;
}
可以看到有尾指標的**和沒有尾指標的**裡面,有尾指標的鍊錶裡面我每次新增完資料都讓尾指標指向最後乙個結點,然後通過尾指標來新增資料。而沒有尾指標的鍊錶裡面每次新增資料都要通過迴圈來遍歷鍊錶找到最後乙個結點然後指向所新增的結點。如果乙個鍊錶裡面有幾萬個結點,每次都通過迴圈遍歷鍊錶來新增資料,那麼速度就相對於有尾指標的鍊錶慢很多。總而言之,還是看個人愛好吧。不管黑貓還是白貓能抓到耗子都是好貓。 C語言單項鍊表的實現
include include typedef int typedata define node length sizeof node 定義鍊錶的結構體 typedef struct tagnode node 函式宣告 node createlist typedata tdindata int fo...
插入鍊錶《c和指標》筆記 簡潔的單項鍊表插入操作
文章結束給大家來個程式設計師笑話 m 單項鍊表插入操縱,我想應該是最基本不過的貨色,今天要介紹的是比較簡練的版本。需求 插入乙個node到鍊錶的準確位置,以後鍊錶中節點的value已經按照由小到大進行排列。傳統的插入操縱 int insertnode node rootp,int new value...
c語言動態鍊錶之尾節點新增
在鍊錶的尾部動態新增節點,新增資訊包括圖書編號和 下面是動態新增節點的完整c 直接複製貼上到main.c中就可以執行 include include typedef struct book book book head null 初始化頭指標為空 int n 0 總節點數目 動態新增節點 void ...