1、基礎知識
1.1 定義
線性表鏈式存儲結構的特點是:用一組任意的存儲單元存儲線性表的數據元素(這組存儲單元可以是連續的,也可以不連續)。
根據線性表練市存儲的特點可知,數據表示包括2部分:數據本身+指示其直接后繼的信息;即節點=數據域+指針域。
n個節點鏈接成一個鏈表(又稱線性鏈表或單鏈表),即為線性表(a1,a2,....,an)的鏈式存儲結構。
1.2 單鏈表的邏輯狀態
圖1 單鏈表的邏輯狀態
說明:(1)鏈表的存取必須從頭指針開始進行。頭指針指向鏈表中的第一個節點(首元節點)
(2)最后一個數據元素無后繼,故指針為null。
2 單鏈表的基本操作
2.1 初始化
初始化即構造一個如上圖1所示的空表。包含步驟如下:
(1)生成新節點的頭結點,用頭指針L指向頭結點
(2)頭節點的指針域為null
Status InitList(LinkList &L){ L =new LNode; L->next=null; return ok; }
2.2 取值
Status getElem(LinkList &L, int i, ElemType &e){ //在帶頭節點的單鏈表L中根據序號i獲取元素的值,用e返回L中第i個數據元素的值 //初始化 p=L->next; j=1; while(p && j<1){ p=p->next; j++; } if(!p || j>i) return error; e=p->data; return ok; }
2.3 查找
LNode *LocalElem(LinkList L, ElemType e){ //在帶頭結點的單鏈表L中查找值為e的元素 p=L->next; while(p && p->data !=e) p=p->next; return p; }
2.4 新增
///將值為e的節點插入到單鏈表中 ///具體步驟:(1)找到鏈表中第i個位置的元素;(2)修改ai的后繼,以及ai+1的前驅 Status ListInsert(LinkList &L, int i, ElemType e){ p=L;//頭結點 j=0; while(p && (j<i-1)){ p=p->next; ++j; } if(!p || j>i-1) return errot; s =new LNode; s->data=e; s->next=p->next; p->next =s; return ok; }
2.5 刪除
Status ListInsert(LinkList &L, int i){ p=L;//頭結點 j=0; while(p && (j<i-1)){ p=p->next; ++j; } if(!(p->next) || (j>i-1)) return error; q=p->next; p->next=q->next; delete q; return ok; }
2.6 創建單鏈表
由於鏈表是一種動態結構,所占用的空間不需要預先分配划定,由系統自動生成,因此,線性表的鏈式存儲結構的建立是一個動態過程。即從空表的初始狀態起,依次建立各元素節點,並逐個插入列表。
(1)前插法
- 創建一個只有頭結點的空鏈表
- 根據待創建鏈表包括的元素個數n, 循環n次執行以下操作:
-
- 生成一個新節點*p;
- 輸入元素值賦給新節點*p的數據域;
- 將新節點*p插入到頭結點之后
void CreateList_H(LinkList &L, int n){ L=new LNode; L->next =null; for(int i=0;i<n;i++){ p=new LNode; cin>>p->data; p->next = L->next; L->next =p; } }
(2) 后插法
算法步驟:
- 創建一個只有頭結點的空鏈表
- 尾指針r初始化,指向頭結點;
- 根據待創建鏈表包括的元素個數n, 循環n次執行以下操作:
-
- 生成一個新節點*p;
- 輸入元素值賦給新節點*p的數據域;
- 將新節點*p插入到尾結點*r之后
- 尾指針r指向新的尾節點*p.
除單向鏈表外,還有循環鏈表,其特點為最后一個節點指針指向頭結點。而對其操作與單鏈表基本一致。差別為判別條件的不同,需要將p!=null 或 p->next!=null 改為 p!=L 或 p->next !=L.
3. 雙向鏈表