鍊錶中的資料是以節點來表示的,每個結點的構成:元素(資料元素的映象) + 指標(指示後繼元素儲存位置),元素就是儲存資料的儲存單元,指標就是連線每個結點的位址資料。
鍊錶的結點結構
┌──┬──┐
│data│next│
└──┴──┘
data域–存放結點值的資料域
next域–存放結點的直接後繼的位址(位置)的指標域(鏈域)
以「結點的序列」表示線性表稱作線性鍊錶(單鏈表)
typedef
char datatype; //假設結點的資料域型別為字元
typedef
struct nodelistnode;
typedef listnode *linklist;
listnode *p;
linklist head;
注意:①linklist和listnode *是不同名字的同乙個指標型別(命名的不同是為了概念上更明確)
②linklist型別的指標變數head表示它是單鏈表的頭指標
③listnode *型別的指標變數p表示它是指向某一結點的指標
①生成結點變數的標準函式
p=( listnode *)malloc(sizeof(listnode));
//函式malloc分配乙個型別為listnode的結點變數的空間,並將其首位址放入指標變數p中
②釋放結點變數空間的標準函式
free(p);//釋放p所指的結點變數空間
③結點分量的訪問
利用結點變數的名字*p訪問結點分量
方法一:(*p).data和(*p).next
方法二:p-﹥data和p-﹥next
④指標變數p和結點變數*p的關係
指標變數p的值——結點位址
結點變數*p的值——結點內容
(*p).data的值——p指標所指結點的data域的值
(*p).next的值——*p後繼結點的位址
*((*p).next)——*p後繼結點
單鏈表的運算
1、建立單鏈表
假設線性表中結點的資料型別是字元,我們逐個輸入這些字元型的結點,並以換行符』\n』為輸入條件結束標誌符。動態地建立單鏈表的常用方法有如下兩種:
(1) 頭插法建表
① 演算法思路
從乙個空表開始,重複讀入資料,生成新結點,將讀入資料存放在新結點的資料域中,然後將新結點插入到當前鍊錶的表頭上,直到讀入結束標誌為止。
② 具體演算法實現
linklist creatlistf(void)
return head;
}
(2) 尾插法建表
① 演算法思路
從乙個空表開始,重複讀入資料,生成新結點,將讀入資料存放在新結點的資料域中,然後將新結點插入到當前鍊錶的表尾上,直到讀入結束標誌為止。
② 具體演算法實現
linklist creatlistr(void)
//endwhile
if (r!=
null)
r->next=
null;//對於非空表,將尾結點指標域置空head=s;
return head;
}
注意:
⒈開始結點插入的特殊處理
由於開始結點的位置是存放在頭指標(指標變數)中,而其餘結點的位置是在其前趨結點的指標域中,插入開始結點時要將頭指標指向開始結點。
⒉空表和非空表的不同處理
若讀入的第乙個字元就是結束標誌符,則鍊錶head是空表,尾指標r亦為空,結點*r不存在;否則鍊錶head非空,最後乙個尾結點*r是終端結點,應將其指標域置空。
(3) 尾插法建帶頭結點的單鏈表
①頭結點及作用
頭結點是在鍊錶的開始結點之前附加乙個結點。它具有兩個優點:
⒈由於開始結點的位置被存放在頭結點的指標域中,所以在鍊錶的第乙個位置上的操作就和在表的其它位置上操作一致,無須進行特殊處理;
⒉無論鍊錶是否為空,其頭指標都是指向頭結點的非空指標(空表中頭結點的指標域空),因此空表和非空表的處理也就統一了。
②尾插法建帶頭結點鍊錶演算法
linklist creatlistr1(void)
r->next=
null;//終端結點的指標域置空,或空表的頭結點指標域置空
return head;
}
注意:
上述演算法裡,動態申請新結點空間時未加錯誤處理,這對申請空間極少的程式而言不會出問題。但在實用程式裡,尤其是對空間需求較大的程式,凡是涉及動態申請空間,一定要加入錯誤處理以防系統無空間可供分配。
(4) 演算法時間複雜度
以上三個演算法的時間複雜度均為0(n)。
2.單鏈表的查詢運算
(1)按序號查詢
① 鍊錶不是隨機訪問結構
在鍊錶中,即使知道被訪問結點的序號i,也不能像順序表中那樣直接按序號i訪問結點,而只能從鍊錶的頭指標出發,順鏈域next逐個結點往下搜尋,直至搜尋到第i個結點為止。因此,鍊錶不是隨機訪問結構。
② 查詢的思想方法
計數器j置為0後,掃瞄指標p指標從鍊錶的頭結點開始順著鏈掃瞄。當p掃瞄下乙個結點時,計數器j相應地加1。當j=i時,指標p所指的結點就是要找的第i個結點。而當p指標指為null且j≠i時,則表示找不到第i個結點。
注意:
頭結點可看做是第0個結點。
③具體演算法實現
listnode* locatenode (linklist head,datatype key)
(2) 按值查詢
①思想方法
從開始結點出發,順著鏈逐個將結點的值和給定值key作比較,若有結點的值與key相等,則返回首次找到的其值為key的結點的儲存位置;否則返回null。
②具體演算法實現
listnode* locatenode (linklist head,datatype key)
3.插入運算(1)思想方法
插入運算是將值為x的新結點插入到表的第i個結點的位置上,即插入到ai-1與ai之間。
具體步驟:
(1)找到ai-1儲存位置p
(2)生成乙個資料域為x的新結點*s
(3)令結點*p的指標域指向新結點
(4)新結點的指標域指向結點ai。
(2)具體演算法實現
void insertlist(linklist head,datatype x,int i)
4.刪除運算
(1)思想方法
刪除運算是將表的第i個結點刪去。
具體步驟:
(1)找到ai-1的儲存位置p(因為在單鏈表中結點ai的儲存位址是在其直接前趨結點ai-1的指標域next中)
(2)令p->next指向ai的直接後繼結點(即把ai從鏈上摘下)
(3)釋放結點ai的空間,將其歸還給」儲存池」。
(2)具體演算法實現
void deletelist(linklist head,int i)
注意:
設單鏈表的長度為n,則刪去第i個結點僅當1≤i≤n時是合法的。
當i=n+1時,雖然被刪結點不存在,但其前趨結點卻存在,它是終端結點。因此被刪結點的直接前趨*p存在並不意味著被刪結點就一定存在,僅當*p存在(即p!=null)且*p不是終端結點(即p->next!=null)時,才能確定被刪結點存在。
迴圈鍊錶是另一種形式的鏈式存貯結構。它的特點是表中最後乙個結點的指標域指向頭結點,整個鍊錶形成乙個環。(迴圈鍊錶)
僅設尾指標的單迴圈鍊錶
用尾指標rear表示的單迴圈鍊錶對開始結點a1和終端結點an查詢時間都是o(1)。而表的操作常常是在表的首尾位置上進行,因此,實用中多採用尾指標表示單迴圈鍊錶。帶尾指標的單迴圈鍊錶可見下圖。
若在單鏈表或頭指標表示的單迴圈表上做這種鏈結操作,都需要遍歷第乙個鍊錶,找到結點an,然後將結點b1鏈到an的後面,其執行時間是o(n)。若在尾指標表示的單迴圈鍊錶上實現,則只需修改指標,無須遍歷,其執行時間是o(1)。
相應的演算法如下:
linklist
connect(linklist
a,linklist
b)
雙(向)鍊錶中有兩條方向不同的鏈,即每個結點中除next域存放後繼結點位址外,還增加乙個指向其直接前趨的指標域prior。typedef
struct dlistnodedlistnode;
typedef dlistnode *dlinklist;
dlinklist head;
雙向鍊錶的前插和刪除本結點操作①雙鏈表的前插操作
void dinsertbefore(dlistnode *p,datatype x)
雙鏈表上刪除結點*p自身的操作
void ddeletenode(dlistnode *p)
注意:
與單鏈表上的插入和刪除操作不同的是,在雙鏈表中插入和刪除必須同時修改兩個方向上的指標。
上述兩個演算法的時間複雜度均為o(1)。
資料結構 鍊錶
鍊錶 what 就是一張鏈式儲存的表,是一種資料結構,是基礎,所以還是不要想有什麼用。具體呢?在c中就用結構體實現物件描述,然後通過函式來實現各個基本操作 c 則用類來表述,c中的結構體就可以看成c 中的類,然後通過類封裝各個操作步驟。這些操作實現後就需要 來測試,號稱demo,就是main函式裡面...
資料結構 鍊錶
一般的建立線性鍊錶有兩種 1.正序法 需要三個指標,head作為頭指標,pre作為前乙個指標,cur作為當前指標用來建立空間 2.倒序法,利用指標的插入,只需要兩個指標,不斷的往頭指標後插入新空間,不過插入的越早,離頭指標越遠,也就越後面輸出 1.線性鍊錶的建立及查詢刪除 include inclu...
資料結構 鍊錶
ifndef link h define link h include include includeusing namespace std templatestruct linknode 鍊錶結點類定義 linknode const t item,linknode ptr null 初始化 tem...