線性表(亦作順序表)是最基本、最簡單、也是最常用的一種資料結構。線性表中資料元素之間的關係是一對一的關係,即除了第乙個和最後乙個資料元素之外,其它資料元素都是首尾相接的。
線性表有兩種儲存結構:
①順序儲存結構,即儲存單元在一段連續的位址上儲存,常見的陣列就是順序儲存結構的線性表;
②鏈式儲存結構,即儲存單元在不連續的位址上儲存。因為其不連續性,除了要存資料元素資訊(資料域)外,還要儲存它後繼元素(結點)的位址(指標域,鏈)。學習鏈式結構最好將結點結構牢記於心,如下圖:
鍊錶的每個結點只含有乙個指標域就叫做單鏈表,單鏈表是其他形式鍊錶以及其他資料結構的基礎,所以是這篇文章著重講的地方。
在這裡還要先提前補充一點知識,時間複雜度與大o計法,正是因為有了這些指標,不同情況下不同資料結構有各自的優越之處。時間複雜度,記作:t(n) = o(f(n)),表示隨問題規模n的增大,演算法執行時間的增長率和f(n)的增長率相同,f(n)是問題規模(**執行次數)的函式。大o階計算方法:
①用常數1取代時間中所有的加法常數;
②修改後的執行次數函式f(n)中,只保留最高端,並去除最高端前面相乘的常數。
舉個例子:
在陣列中我們訪問資料時,都只需要執行一條語句,f(n)=1,則時間複雜度為o(1);
如果需要插入或刪除時,最壞情況(一般都是考慮最壞情況)是在第乙個元素插入,則需要把所有元素都向後挪動一位,這樣需要作n次處理則f(n)=n,時間複雜度為o(n)。
最後再介紹兩個函式,就可以開始舉例項了。
①void *malloc(unsigned int num_bytes)
動態分配記憶體指標函式,如果分配成功則返回指向被分配記憶體的指標(此儲存區中的初始值不確定),否則返回空指標null。需要進行強制型別轉換。
②void free(void *ptr)
釋放ptr指向的儲存空間。被釋放的空間通常被送入可用儲存區池,以後可在呼叫malloc等函式來再分配。
例項:單鏈表的各種操作,原本想分類乙個函式乙個函式講,太亂了,一起擺又太長了,就當是給那些找demo的人吧!全都是自己寫的,後面的也沒注釋,真的很糟糕~~
#include "stdio.h"
#include "malloc.h"
#include "stdlib.h"
// 乙個結點結構體
typedef struct node
node;
/** 功能:建立乙個單鏈表
* 輸入:鍊錶長度
*/node *createlist(int n)
return h; // 返回頭結點指標}/*
* 功能:得到鍊錶長度
* 輸入:鍊錶的頭結點
* 輸出:整形
*/int getsize(node *head)
return size;}/*
* 功能:得到鍊錶特定位置的資料
* 輸入:鍊錶的頭結點,獲取資料的位置
* 輸出:整形
*/int get(node *h,int position)
result = s->data;
return result;}/*
* 功能:插入資料
* 輸入:鍊錶的頭結點,插入的位置,插入的資料
* 輸出:無
*/void insert(node *h,int position,int data)
s->next = p->next;
p->next = s; }/*
* 功能:動態插入資料在最後一項
* 輸入:鍊錶的頭結點,插入的資料
* 輸出:無
*/void insertatlast(node *h,int data)
p->next = s; }/*
* 功能:刪除資料
* 輸入:鍊錶的頭結點,刪除資料的位置
* 輸出:無
*/void remove(node *h,int position)
s = p->next;
p->next = s->next;
free(s); }/*
* 輸入:鍊錶的頭結點,所查資料
* 輸出:結點指標
*/node *search(node *h,int data)
s = p->next;
return s;}/*
* 功能:在特定的結點後面插入資料
* 輸入:鍊錶的頭結點,插入的資料
* 輸出:無
*/void insertafterpoint(node *point,int data)
/** 功能:刪除整個鍊錶
* 輸入:鍊錶的頭結點
* 輸出:無
*/void deletelist(node *h)
h->next = null;}/*
* 功能:列印所有元素的值
* 輸入:鍊錶的頭結點,鍊錶長度
* 輸出:無
*/void printall(node *h,int n)
}void main(int argc, char* argv)
列印結果:
如果在我們不知道第i個結點的指標位置,單鏈表資料結構在插入和刪除操作上的時間複雜度也為o(n),但是如果要插入10個資料時,我們找到了i個結點的指標位置,插入第乙個資料的演算法複雜度是o(n),後面的都是o(1),而陣列操作則每次都是o(n)。可見:對於插入或刪除資料越頻繁的操作,單鏈表的效率優勢就越明顯。
總而言之,對於單鏈表的操作,就是操作頭結點,前驅結點,當前結點;
前驅結點的指標域資料就是當前結點的指標。
除了單鏈表外還有迴圈鍊錶(終端結點的指標域指向頭結點)和雙向鍊錶(增加乙個前驅結點的指標域),以後有需要時再作深入學習。
資料結構專題 線性表之單鏈表
對比了好幾本書,比較少涉及單鏈表的賦值,為了親自跑出其他功能,花了不少時間,畢竟是打基礎嘛,相信以後會越來熟練 你為什麼那麼熟練,明明是我先 話不多說,下面是 及實驗結果。include include define elementtype int define maxsize 1000 defin...
C資料結構 線性表之單鏈表
單鏈表的設計之初,筆者在考慮乙個首要的問題,就是單鏈表的節點是在插入的函式內部建立,還是在函式外部建立。考慮到使用者在插入的時候,變數生命週期的不確定性以及容易造成記憶體洩漏等問題,綜合考慮之下使用了內部建立節點的方式。筆者設計的單鏈表中包含了單鏈表的反轉和合併等有趣的操作,其中的奧妙如果讀者有興趣...
資料結構 線性表之帶頭結點單鏈表
之前跟著朱老師寫的乙個帶頭結點的 建立鍊錶時有兩種方法,一種是先初始化 建立乙個空鍊錶 然後對這個空鍊錶進行結點輸入,建立鍊錶 這個時候,由於已經有了頭結點,將其傳入,直接在頭結點的後面進行操作 另外一種是將初始化和建立鍊錶放到乙個函式裡,這時候傳入的鍊錶就什麼都沒有,連頭結點也沒有 先建立頭結點,...