我先來帶你認識一下什麼是鏈表:
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱爲結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。 相比於線性表順序結構,操作複雜。由於不必須按順序存儲,鏈表在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查找一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。
看完上面這段話,是不是覺得這十幾年的教育都白學了。明明每個字都認識,但是爲什麼連在一起就看不懂了呢?
簡單來說:
鏈表就是不再按照順序來連接了,鏈表的開始是由頭指針開始的,頭指針指向第一個節點或者頭結點。每個結點都有兩部分組成:一個數據域用來存儲你這個元素的數據,一個指針域用來存儲下一個數據的位置,這個是不是感覺有點像港片裏面的線人?一旦你的直屬上司掛掉了,你就變成gu兒了? 同理,如果你的指針域沒有指向下一個結點的話(最後一個結點的指針域都是指向“NULL”的)。那麼就代表這個鏈表已經結束了。
瞭解了鏈表的基礎,那麼現在我們就來看看鏈表的數據結構:
//數據結構
typedef struct monster{
int id; //編號
char *name; //名稱
//指向下一結點的指針
struct monster *pNext;
}Monster;
光看結構是看不出什麼來的,所以還是要大家來實戰一下來加強印象:
//示例
typedef struct Monster{
int id;
char *name;
struct Monter *next; //指向下個結點的指針
}Monster;
void test()
{
Monster monster1 = {1, "喬布斯"};
Monster monster2 = {2, "比爾·蓋茨"};
Monster monster3 = {3, "巴菲特"};
//monster1 就是頭指針
monster1.next = &monster2;
monster2.next = &monster3;
monster3.next = NULL;
}
這裏再給大家講講頭指針和頭結點的基本概念:
頭指針:鏈表中的第一個結點的存儲位置;
頭結點:在單鏈表的第一個結點前附設的一個結點。
兩者的異同點
頭指針 | 頭結點 |
---|---|
若鏈表有頭結點,則是指向頭結點的指針;若沒有則是鏈表指向第一個結點的指針; | 頭結點是爲了操作的統一和方便而設立的,放在第一個結點之前;其數據域一般無意義(但是可以存儲鏈表的長度) |
頭指針具有表示作用,所以常常用頭指針表示鏈表的名字; | 有了頭結點,在第一個結點前插入和刪除第一個幾點時,操作與其他結點就統一了。 |
無論鏈表是否爲空,頭指針均不爲空。 | 頭指針是鏈表的必要元素 頭結點不一定是鏈表的必須要素。 |
最後總結:
- 鏈表結點包括數據域和指針域
- 鏈表是由n 個結點鏈結成,第一個結點的存儲位置叫做頭指針,最後一個結點的指針爲“空”
相較於順序表的優點:
- 定義時不用規定長度;
- 存儲的元素個數不受限制;
- 插入和刪除元素時,不用移動其它元素。
好了,看到這裏的時候。我們就要開始我們的老規矩準備說再見了。
這次這次給大家普及了一點鏈表的知識,下一篇文章我會帶大家學習“鏈表”的大兒子“單鏈表”
如果覺得本篇文章對你有幫助的話,麻煩各位兄弟萌點個贊幫忙轉發一下~