一、線性表的基本概念
線性表是由n(n≥0)個數據元素(結點)a1,a2,a3,……an組成的有限序列;數據元素的個數n定義為表的長度。當n=0時,稱為空表。
將非空的線性表(n>0)記作:L=(a1,a2,a3,……,an)
- a1:起始結點(沒有直接前驅)
- an:終端結點(沒有直接后繼)。
- a1稱為a2的直接前驅
- a3稱為a2的直接后繼
線性表的特點:
- 線性表中只有1個起始結點,1個終端結點,
- 起始結點沒有直接前驅,有1個直接后繼。
- 終端結點有1個直接前驅,沒有直接后繼。
- 除這2個結點外,每個結點都有且只有1個直接前驅和1個直接后繼。
線性表的基本運算
- 1,初始化 Initiate(L) :建立一個空表L=(),L不含數據元素。
- 2,求表長度 Length(L):返回線性表L的長度。
- 3,取表元 Get(L,i):返回線性表第i個數據元素,當i不滿足1≤i≤Length(L)時,返回一特殊值。
- 4,定位 Locate(L,x):查找線性表中數據元素值等於x的結點序號,若有多個數據元素值與x相等,運算結果為這些結點中序號的最小值,若找不到該結點,則運算結果為0。
- 5,插入 Insert(L,x,i):在線性表L的第i個數據元素之前插入一個值為x的新數據元素,參數i的合法取值范圍是1≤i≤n+1。操作結束后線性表L由(a1,a2,…,ai-1,ai,ai+1,.…,an )變為(a1,a2,…,ai-1,x,ai,ai+1 .…,an )表長度加1。
- 6,刪除 Delete(L,i):刪除線性表L的第i個數據元素ai ,i的有效取值范圍是1≤i≤n。刪除后線性表L由(a1,a2,…,ai-1,ai,ai+1,.…,an )變為(a1,a2,…,ai-1,ai+1,.…,an ),表長度減1
二、線性表的順序存儲
線性表順序存儲的方法:將表中的結點依次存放在計算機內存中一組連續的存儲單元中。
- ◆ 數據元素在線性表中的鄰接關系決定其在存儲空間中的存儲位置。
- ◆ 即邏輯結構中相鄰的結點,其物理存儲位置也相鄰。
- ◆ 用順序存儲實現的線性表稱為順序表。一般使用數組存儲
順序存儲結構的特點:
- 線性表的邏輯結構與存儲結構一致
- 可以對數據元素實現隨機讀取
- 設線性表中所有結點的類型相同,則每個結點所占用存儲空間大小亦相同。
- 假設表中每個結點占用L個存儲單元,其中第一個單元的存儲地址則是該結點的存儲地址
- 並設表中開始結點a1 的存儲地址是d,那么結點ai 的存儲地址LOC(ai)=d+(i-1)*L
順序表是用一維數組實現的線性表,數組下標可以看成是元素的相對地址;邏輯上相鄰的元素,存儲在物理位置也相鄰的單元中
1、線性表的基本運算在順序表上的實現
=======================插入========================
插入 Insert(L,x,i):在線性表L的第i個數據元素之前插入一個值為x的新數據元素,參數i的合法取值范圍是1≤i≤n+1。操作結束后線性表L由(a1,a2,…,ai-1,ai,ai+1,.…,an )變為(a1,a2,…,ai-1,x,ai,ai+1 .…,an )表長度加1。
注意:
- 當表空間已滿,不可再做插入操作。
- 當插入位置是非法位置,不可做正常的插入操作。
順序表插入操作過程
- ① 將表中位置為n ,n-1,…,i上的結點,依次后移到位置n+1,n,…,i+1上,空出位置i。
- ② 在位置i上插入新結點x。(當插入位置i=n+1時,無須移動結點,直接將x插入表的末尾)
- ③ 該順序表長度加1。
結論:
- 假設線性表中含有n個數據元素,在進行插入操作時,有n+1個位置可插入,在每個位置插入數據的概率是:1/(n+1),在i位置插入時,要移動n-i+1個數據
- 假定在n+1個位置上插入元素的可能性均等,則平均移動元素的個數為:n/2,平均時間復雜度O(n)
===================刪除========================
刪除 Delete(L,i):刪除線性表L的第i個數據元素ai ,i的有效取值范圍是1≤i≤n。刪除后線性表L由(a1,a2,…,ai-1,ai,ai+1,.…,an )變為(a1,a2,…,ai-1,ai+1,.…,an ),表長度減1
注意:當要刪除元素的位置i不在表長范圍內(即i<1或i>L->length)時,為非法位置,不能做正常的刪除操作
順序表刪除操作過程:
- 1,若i=n,則只要刪除終端結點,無須移動結點;
- 2,若1≤i≤n-1,則必須將表中位置i+1,i+2,…,n的結點,依次前移到位置i,i+1,…,n-1上,以填補刪除操作造成的空缺。
- 3,該表長度減1
刪除算法的分析
- 假設線性表中含有n個數據元素,在進行刪除操作時,有n個位置可刪除;每個位置刪除數據的概率是:1/n,在i位置刪除時,要移動n-i個數據;
- 假定在n個位置上刪除元素的可能性均等,則平均移動元素的個數為:(n-1)/2;平均時間復雜度O(n)
插入和刪除的結論:順序存儲結構表示的線性表,在做插入或刪除操作時,平均需要移動大約一半的數據元素。當線性表的數據元素量較大,並且經常要對其做插入或刪除操作時,這一點需要值得考慮。
===================定位=================
定位(查找):定位運算LocateSeqlist(L,X)的功能是求L中值等於X的結點序號的最小值,當不存在這種結點時結果為0。
算法的過程:從第一個元素 a1 起依次和x比較,直到找到一個與x相等的數據元素,則返回它在順序表中的存儲下標或序號;或者查遍整個表都沒有找到與 x 相等的元素,返回0。
算法分析:
- 最好情況下,第1個元素就是x值,此時查找比較次數為1。
- 最壞情況下,最后1個元素是x值,此時查找比較次數為n。
- 故平均查找長度為(n+1)/2。平均時間復雜度O(n)
三、線性表的鏈接存儲
鏈式存儲的結構:數據項 + 指針項
鏈表(Link List):使用鏈式存儲的線性表
鏈表的具體存儲表示為:用一組任意的存儲單元來存放; 鏈表中結點的邏輯次序和物理次序不一定相同,還必須存儲指示其后繼結點的地址信息。
所有結點通過指針鏈接而組成單鏈表
NULL稱為空指針
Head稱為 頭指針變量,存放鏈表中第一個結點地址;在單鏈表中,增加頭結點的目的是方便運算的實現
鏈表的表示:由於我們常常只注重結點間的邏輯順序,不關心每個結 點的實際位置,可以用箭頭來表示鏈域中的指針,單鏈表就 可以表示為下圖形式。
單鏈表特點:
❖ 起始節點又稱為首結點,無前驅,故設頭指針head 指向開始結點。
❖ 鏈表由頭指針唯一確定,單鏈表可以用頭指針的名字 來命名。頭指針名是head的鏈表可稱為表head。
❖ 終端結點又稱尾結點,無后繼,故終端結點的指針域 為空,即NULL
❖ 除頭結點之外的結點為表結點
❖ 為運算操作方便,頭結點中不存數據
單鏈表的基本運算
=====================初始化=====================
空表由一個頭指針和一個頭結點組成;在算法中,變量head是鏈表的頭指針,它指向新創建的結點,即頭結 點。一個空單鏈表僅有一個頭結點,它的指針域為NULL。
====================求表長====================
在單鏈表存儲結構中,線性表的長度等於單鏈表所 含結點的個數(不含頭結點)
步驟:
1,令計數器j為0
2,令p指向頭結點
3,當下一個結點不空時,j加1,p指向下一個結點
4,j的值即為鏈表中結點個數,即表長度
=================讀表元素:查找第i個結點============
步驟:
1、令計數器j為0
2、令p指向頭結點
3、當下一個結點不空時,並且j<i 時,j加1,p指向下一個結點
4、如果j等於i,則p所指結點為要找的第i結點否則,鏈表中無第i結點
===============定位=================
定位運算是對給定表元素的值,找出這個元素的位置。對 於單鏈表,給定一個結點的值,找出這個結點是單鏈表的 第幾個結點。定位運算又稱為按值查找。
具體步驟:
1、令p指向頭結點
2、令i=0
3、當下一個結點不空時,p指向下一個結點,同時i的值加1
4、直到p指向的結點的值為x,返回i+1的值。
5、如果找不到結點值為x的話,返回值為0
===================插入====================
===========刪除===========
刪除運算是將表的第i個結點刪去。
(1)找到ai-1的存儲位置p
(2)令p->next指向ai的直接后繼結點
(3)釋放結點ai的空間,將其歸還給"存儲池" 。
free(p)是必不可少的,因為當一個結點從鏈表移出后,如果不釋放它的空間,它將變成一個無用的結點,它會一直占用着系統內存空間,其他程序將無法使用這塊空間。
四、單項循環鏈表
普通鏈表的終端結點的next值為NULL;循環鏈表的終端結點的next指向頭結點,在循環鏈表中,從任一結點出發能夠掃描整個鏈表。
如何找到循環鏈表的尾結點:在循環鏈表中附設一個 rear 指針指向尾結點,適用於經常使用頭尾結點的鏈表操作中
若p為指向循環鏈表中某鏈結點的指針變量,判斷循環鏈表是否只有一個結點的標志是:p->next=p
五、雙向循環鏈表
在鏈表中設置兩個指針域,一個指向后繼結點,一個指向前驅結點這樣的鏈表叫做雙向鏈表
雙向循環鏈表適合應用在需要經常查找結點的前驅和后繼的場合。找前驅和后繼的復雜度均為:O(1)
雙向鏈表中結點的刪除:設p指向待刪結點,刪除*p可通過下述語句完成:
- (1)p->prior->next=p->next; //p前驅結點的后鏈指向p的后繼結點
- (2)p->next->prior=p->prior; //p后繼結點的前鏈指向p的前驅結點
- (3)free(p); //釋放*p的空間;(1)、(2)這兩個語句的執行順序可以顛倒。
雙向鏈表中結點的插入:在p所指結點的后面插入一個新結點*t,需要修改四個指針
- (1)t->prior=p;
- (2)t->next=p->next;
- (3)p->next->prior=t;
- (4)p->next=t;
六、順序實現與鏈式實現的比較
線性表與鏈表的優缺點:
(1)單鏈表的每個結點包括數據域與指針域,指針域需要占用額外空間。
(2)從整體考慮,順序表要預分配存儲空間,如果預先分配得過大,將造成浪費,若分配得過小,又將發生上溢;單鏈表不需要預先分配空間,只要內存空間沒有耗盡,單鏈表中的結點個數就沒有限制。
(3)、插入、刪除操作,順序表需要移動元素,而鏈表不需要移動元素
時間性能的比較
順序表
- 讀表元 O(1)
- 定位(找x) O(n)
- 插入O(n)
- 刪除O(n)
鏈表
- 讀表元O(n)
- 定位(找x)O(n)
- 插入O(n)
- 刪除O(n)