大话数据结构:线性表(3)
1.單鏈表的整表創(chuàng)建
順序存儲(chǔ)結(jié)構(gòu)的創(chuàng)建,其實(shí)就是一個(gè)數(shù)組的初始化,即聲明一個(gè)類型和大小的數(shù)組并賦值的過程。而單鏈表和順序存儲(chǔ)結(jié)構(gòu)就不一樣,他不像順序存儲(chǔ)結(jié)構(gòu)那么集中,他可以很分散,是一種動(dòng)態(tài)結(jié)構(gòu)。對(duì)于每個(gè)鏈表來說,它所占用空間的大小和位置是不需要預(yù)先分配劃定的,可以根據(jù)系統(tǒng)的情況和實(shí)際的需求即時(shí)生成。
所以,創(chuàng)建單鏈表的過程就是一個(gè)動(dòng)態(tài)生成鏈表的過程。即從“空表”的初始狀態(tài)起,一次建立各元素結(jié)點(diǎn),并逐個(gè)插入鏈表。
單鏈表整表創(chuàng)建的算法思路:
(1)聲明一節(jié)點(diǎn)p和計(jì)數(shù)器變量i;
(2)初始化一空鏈表L;
(3)讓L的頭結(jié)點(diǎn)的指針指向NULL,即建立一個(gè)帶頭結(jié)點(diǎn)的單鏈表;
(4)循環(huán):生成一新結(jié)點(diǎn)賦值給P; 隨機(jī)生成一數(shù)字賦值給p的數(shù)據(jù)域p->data; 將p插入到頭結(jié)點(diǎn)與前一個(gè)新節(jié)點(diǎn)之間(頭插法)。
頭插法實(shí)現(xiàn)代碼算法:
事實(shí)上,我們也可以不這樣做。為什么不把新節(jié)點(diǎn)都放在最后呢?這種應(yīng)該說才是排隊(duì)的正常思維,及先來后到。這種方法又稱為“尾插法”。
實(shí)現(xiàn)代碼算法如下:
void CteateListTail( LinkList* L, int n)
{
LinkList p,r;
int i;
srand( time(0) );
*L = (LinkList) malloc ( sizeof(Node) );
r = *L;
for (i=0; i<n; i++)
{
p = (Node*)malloc( sizeof (Node) );
p->data = rand()%100+1;
r->next = p;
r = p; //保證r代表最后的結(jié)點(diǎn)
}
r->next = NULL;
}
2.單鏈表的整表刪除
當(dāng)我們不打算使用這個(gè)單鏈表時(shí),我們需要把它銷毀,其實(shí)也就是在內(nèi)存中將他釋放掉,以便于留出空間給其他程序或軟件使用。
單鏈表整表刪除的算法思路如下:
(1)聲明一結(jié)點(diǎn)p和q;
(2)將第一個(gè)結(jié)點(diǎn)賦值給p;
(3)循環(huán):將下一個(gè)結(jié)點(diǎn)賦值給q,釋放p,將q賦值給p。
實(shí)現(xiàn)代碼算法如下:
3.單鏈表結(jié)構(gòu)與順序存儲(chǔ)結(jié)構(gòu)優(yōu)缺點(diǎn)
| | 單鏈表結(jié)構(gòu) | 順序存儲(chǔ)結(jié)構(gòu) |
| 存儲(chǔ)分配方式 | 采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),用一組任意的存儲(chǔ)單元存放線性表元素 | 用一段連續(xù)的存儲(chǔ)單元一次存儲(chǔ)線性表的數(shù)據(jù)元素 |
| 時(shí)間性能 | 查找:O(n) | 查找:O(1) |
| 空間性能 | 不需要分配存儲(chǔ)空間,只要有就可以分配,元素個(gè)數(shù)也不受限制 | 需要預(yù)分配存儲(chǔ)空間,分配大了,浪費(fèi),分配小了,易發(fā)生上溢 |
經(jīng)驗(yàn)性的結(jié)論:
(1)當(dāng)線性表需要頻繁查找,很少進(jìn)行插入和刪除操作時(shí),宜采用順序存儲(chǔ)結(jié)構(gòu)。若需要頻繁插入和刪除操作時(shí),宜采用單鏈表結(jié)構(gòu)。比如說,游戲開發(fā)中,對(duì)于用戶注冊的個(gè)人信心,除了注冊時(shí)插入數(shù)據(jù)外,絕大多數(shù)情況都是讀取,所以應(yīng)該老呂用順序存儲(chǔ)結(jié)構(gòu)。而游戲的玩家的武器或者裝備列表,隨著玩家的游戲過程中,可能會(huì)隨時(shí)增加或刪除,此時(shí)再用順序存儲(chǔ)就不太合適,應(yīng)該偏向使用單鏈表結(jié)構(gòu)。 (2)當(dāng)線性表中的元素個(gè)數(shù)變化較大或者根本不知道有多大時(shí),最好用單鏈表結(jié)構(gòu),這樣可以不需要考慮存儲(chǔ)空間的大小問題。而如果事先知道線性表的大致長度,比如一年12個(gè)月,一周就是星期一至星期日共七天,這種用順序存儲(chǔ)結(jié)構(gòu)效率會(huì)高很多。
4.循環(huán)鏈表
對(duì)于單鏈表,由于每個(gè)結(jié)點(diǎn)只存儲(chǔ)向后的指針,到了尾標(biāo)志就停止了向后的操作。這樣,當(dāng)中某一節(jié)點(diǎn)就無法找到它的前驅(qū)結(jié)點(diǎn),難以查閱前方數(shù)據(jù)。
將單鏈表中終端結(jié)點(diǎn)的指針端由空指針改為指向頭結(jié)點(diǎn),就使整個(gè)鏈表形成一個(gè)環(huán),這種頭尾項(xiàng)鏈的單鏈表稱為單循環(huán)鏈表,簡稱循環(huán)鏈表。
其實(shí),循環(huán)鏈表和單鏈表的主要差異就在于循環(huán)的判斷條件上,原來是判斷p->next = NULL??,現(xiàn)在則是判斷p->next是不是等于頭結(jié)點(diǎn),若不等于,則循環(huán)未結(jié)束。
在單鏈表中,我們有了頭結(jié)點(diǎn)時(shí),我們可以用O(1)的時(shí)間訪問第一個(gè)結(jié)點(diǎn),但是對(duì)于要訪問的最后一個(gè)結(jié)點(diǎn),卻要用O(n)時(shí)間,因?yàn)槲覀冃枰獙捂湵砣繏呙枰槐椤?/span>
有沒有可能用O(1)的時(shí)間由鏈表指針訪問到最后一個(gè)結(jié)點(diǎn)呢?當(dāng)然可以,不過我們需要改造一下這個(gè)循環(huán)鏈表,不用頭指針,而是用指向終端結(jié)點(diǎn)的尾指針來表示循環(huán)鏈表。
此時(shí),查找開始結(jié)點(diǎn)和終端結(jié)點(diǎn)就很方便了。如果終端結(jié)點(diǎn)用尾指針rear指示,則查找終端節(jié)點(diǎn)是O(1),而開始結(jié)點(diǎn),其實(shí)就是rear->next->next,其時(shí)間復(fù)雜度也為O(1)。
5.雙向鏈表
在單鏈表中,有了next指針,這就使得我們要查找下一節(jié)點(diǎn)的時(shí)間復(fù)雜度為O(1)。可是,如果我們要查找的是上一節(jié)點(diǎn)的話,那最壞的時(shí)間復(fù)雜度就是O(n),因?yàn)槲覀兠看味家獜念^開始遍歷查找。
為了克服鏈表單向性這一弊端,相關(guān)研究人員設(shè)計(jì)了雙向鏈表。雙向鏈表是在單鏈表的每個(gè)節(jié)點(diǎn)中,在設(shè)置一個(gè)指向其前驅(qū)結(jié)點(diǎn)的指針域。所以,在雙向鏈表中的結(jié)點(diǎn)都有兩個(gè)指針域,一個(gè)是指向直接后繼,一個(gè)是指向直接前驅(qū)。
總結(jié)
以上是生活随笔為你收集整理的大话数据结构:线性表(3)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [OS复习]文件管理2
- 下一篇: 昨天飞鸽传书可能是因为太累了