Transcript Chap.4

第四章—
鏈結串列
1
單一鏈結串列與鏈
4.1
鏈結串列畫出時如一連串節點,其中箭頭表示指標鏈結(圖4.1)。指向串列第一個
節點的指標之名稱也是串列的名稱。亦即,圖4.1中的串列稱為prt。
ptr
bat
cat
sat
wat
NULL
圖4.1:畫出鏈結串列常用的方法
要在cat和sat之間插入mat,我們必須:
1.
2.
取得一個目前未使用的節點;令其位址為paddr。
將此節點的資料欄位設定為mat。
2
3. 將paddr的鏈結欄位設定為包含cat的節點之鏈結欄位中找到的位址。
4. 設定包含cat的節點之鏈結欄位,使其指向paddr。
圖4.2表示在插入mat以後串列的改變。從包含cat的結點出來的虛線為舊的鏈結,實線為新的鏈結。
ptr
bat
cat
sat
wat
NULL
mat
圖4.2:在cat之後插入mat
假設我們想要自串列中刪除mat。只要找到在mat之前的元素,即cat,設定其鏈結欄位,使其指
向mat的鏈結欄位(圖4.3)。
3
ptr
bat
cat
mat
sat
vat
NULL
圖4.3;從串列刪除mat
4
函數create2建立了有兩個結點的鏈結函數。
函數create2傳回first,為指向串列開始的指標。
程式:建立有兩個節點的串列
void Chain::Create2()
{
// 建立並設定第二個節點的欄位
ChainNode* second = new ChainNode(20,0);
// 建立並設定第一個節點的欄位
first = new ChainNode(10,second);
}
5
ptr
10
20
NULL
圖:有兩個節點的串列
程式 :在串列之前的簡易插入
void Chain::Insert50(ChainNode* x)
{
if ( first )
// 插入於x後
x→link = new ChainNode(50, x→link);
else
// 插入到空串列
first = new ChainNode(50);
}
6
因為第二個指標node的位址不會改變,我們不需要將它的位址當作參數來傳送。典型
的函數呼叫為insert (&ptr, node);其中ptr指向串列的開始,而node指向新的節點。
對於空的串列,設定temp的鏈結點為NULL,並將ptr之值改成temp的位址。對於非空的
串列,將節點temp插入node與其鏈結欄所指的節點之間。
ptr
node
10
20
NULL
50
temp
圖4.6:具有兩個節點的串列,在呼叫函數insert(&ptr, ptr);以後的串列
7
圖4.7中刪除的結點試試串列的第一個節點。這表示我們必須確實的改變起始位址ptr。
在圖4.8中,node不是第一個節點,我們只要改變trial的鏈結欄,使其指向node之鏈結
欄所指的節點即可
ptr node
10
trail = NULL
50
20
NULL
20
NULL
(a)刪除前
ptr
50
(b)刪除後
圖4.7:呼叫函數delete( &per, NULL, ptr );以後的串列
8
ptr trial
10
node
50
20
NULL
20
NULL
(a) 刪除前
ptr
50
(b) 刪除後
呼叫函數delete( &ptr, ptr, ptr-> link );以後的串列
9
函數delete從鏈結串列中刪除任意一個節點。除了改變鏈結欄,或*ptr之值以外,
delete也會將配置給所刪除的節點之空間環給系統記憶體。要完成這件工作,使
用free函數。
程式:自串列中刪除
void Chain::Delete(ChainNode* x, ChainNode *y)
{
if(x = = first) first = first→link;
else y→link = x→link;
delete x;
}
10
4.6
鏈結堆疊與佇列
程式:在鏈結的堆疊中加入元素
template <class T>
void LinkedStack <T>::Push(const T& e) {
top = new ChainNode <T>(e, top);
}
11
程式:自鏈結的堆疊中刪除元素
template <class T>
void LinkStack <T>::Pop( )
{// 刪除堆疊的頂端節點
if (IsEmpty()) throw “Stack is empty. Cannot delete.”;
ChainNode <T> *delNode = top;
top = top→link; // 移除頂端節點
delete delNode; // 釋回此節點
}
12
程式:在鏈結佇列的後端加入元素
template <class T>
void LinkedQueue <T>:: Push(const T& e)
{
if (IsEmpty( )) front = rear = new ChainNode(e,0); //空佇列
else rear = rear→link = new ChainNode(e,0); // 連接節點並且更新rear
}
13
程式:自鏈結佇列的前端刪除元素
template <class T>
void LinkedQueue <T>:: Pop()
{// 刪除佇列的第一個元素
if (IsEmpty()) throw “Queue is empty. Cannot delete.”;
ChainNode<T> *delNode = front;
front = front→link; // 移除鏈的第一個節點
delete delNode;
// 釋回此節點
}
14
4.7
多項式
以單項鏈結串列來表示多項式
我們可將多項式的每一項以一個節點表示,其中包含係數欄和指數欄,以及一個指向
下一項的指標。假設係數均為整數,則其型態宣告為:
struct Term
{// 所有Term的成員都內定為公用的
int coef; // 係數
int exp; // 指數
Term Set(int c,int e) {coef = c; exp = e; return *this;};
};
class Polynomial {
public:
// 在這裡定義公用函式
private:
Chain<Term> poly;
};
將Poly_node圖示如下:
15
coef
expon
圖4.11表示如何儲存多項式a
link
 3x14  2 x 8  1和 b  8x14  3x10  10x 6
a
3
14
2
8
1
0
NULL
10
10
6
NULL
(a)
b
8
14
-3
(b)
圖4.11:多項式表示法
16
多項式相加
要將兩個多項式相加,先從a和b所指的節點開始檢查他們的項次:
 如果兩個項次的指數是相等的,則將係數相加,並為相加結果的多項式產生一
個新的項目。
 如果在a中目前處理的項目之指數小於b中的,則複製b中的項目,並將其附
加到結果多項式d中,而後將指標移到b的下一項。
 若a
expon > b
3
14
expon,則在a上採用類似的運算。
2
8
1
0
NULL
a
17
8
14
-3
10
10
6
NULL
2
8
1
0
NULL
-3
10
10
6
NULL
b
-3
10
b
11
14
NULL
d
(a)
a->expon == b-> expon
3
14
a
8
11
14
14
d
NULL
18
(b) a -> expon < b -> expon
3
14
2
8
1
0
NULL
6
NULL
a
8
11
14
14
-3
10
10
-3
10
2
8
b NULL
d
(c) a -> expon > b -> expon
圖4.12:產生d=a+b結果的前三項
19
每當 產生一個新的項目,我們要設定它的coef和expon欄位,並將他附加在d之後。為了避免每次加入的
節點時必須找尋d的最後一個節點,我們使用一個指標rear來指向目前d中最後的一個節點。
程式:兩個多項式相加
Polynomial Polynomial::operator+(const Polynomial& b) const
2 {// 相加多項式 *this(a)與b並且回傳它們的和
3
Term temp;
4
Chain <Term>::ChainIterator ai = poly.begin(),
5
bi =b. poly.begin();
6
Polynomial c;
7
while (ai&&bi) { // 目前的節點不是空的
8
if (ai→exp = = bi→exp) {
9
int sum = ai→coef + bi→coef;
10
if (sum) c.poly.InsetBack (temp.Set(sum, ai→exp));
11
ai++; bi++; // 前進至下一個項目
12
}
13
else if (ai→exp < bi→exp) {
14
c.poly.InsertBack(temp.Set(bi→coef, bi→exp)) ;
15
bi++; // b的下一個項目
16
}
20
17
else {
18
c.poly.InsertBack(temp.Set(ai→coef , ai→exp)) ;
19
ai++; // a的下一個項目
20
}
21
}
22
while (ai) { // 複製a剩下的部份
23
c.poly.InsertBack(temp.Set(ai→coef,ai→exp)) ;
24
ai++;
25
}
26
while (bi) { // 複製b剩下的部份
27
28
c.poly.InsertBack (temp.Set(bi→coef,bi→exp)) ;
bi++ ;
29 }
29
30 }
return c;
21
刪除多項式
如果我們希望讀取多項式a(x), b(x), d(x),而後計算e(x)=a(x)*b(x)+d(x),他可能需
要編寫許多的主函數,
22
當我們需要計算更多的多項式時,回收用來儲存temp(x)的節點是很有幫助的。將
temp(x)的節點釋回,我們也許會用到她們來儲存其他的多項式。
以環狀鏈結串列表示法表示多項式
如果我們修改串列的結構,使的最後一個節點的鏈結欄指向串列的第一個節點(如
圖4.13),我們即可更有效率的釋回一個多項式的所有節點。我們稱其為環狀串列
(circular list) 。單向鍊結串列的最後一個節點有虛鏈結時稱為鏈( chain ) 。
3
ptr
圖4.13:
14
2
8
1
0
ptr  3x14  2x8  1
的環狀表示法
23
4.8
等價類
定義:在集合S上的關係, ≡稱為在S上的等價關係(equivalence relation),若且
惟若他在S上具有對稱性,反身性,和遞移性。
舉例而言:
如果有12個多邊形,編號為0到11,且下列各組重複:
0 ≡ 4, 3 ≡ 1, 6 ≡ 10, 8 ≡ 9, 7 ≡ 4, 6 ≡ 8, 3 ≡ 5, 2 ≡ 11, 11 ≡ 0
我們可將這些分割成下列的等價類:
{ 0,2,4,7,11 };{ 1,3,5 };{ 6,8,9,10 }
24
判斷等價的演算法有兩個階段。在第一個階段中,我們讀取並儲存等價序對
j >。
< i,
在第二個階段中,由0開始找出所有形式為< 0, j >的序對。持續以這種方法工作,
直到找出,標記,並印出整個也含0的等價類為止。而後繼續找出別的等價類。
如果說有個陣列如:pairs[ n ][ m ]。這種方法可能會浪費許多的時間,因為只會用
到少數的元素。而且這可能需要使用大量的時間將新的序對< i, k >插入列i。
25
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
data
11
link
3
11
0
0
5
7
3
8
0
4
6
0
8
6
0
0
0
data
4
1
0
10
9
2
link
0
0
0
0
0
0
圖4.18:在序對輸入以後的串列
分析等價程式:seq和out的設置需時O(n)。在第一階段輸入等價序對時,每一個序對需
要一個常數時間。因此,這階段一共需要O(m+n)時間。
26
在第二階段,需要O(m+n)時間。所以,全部的計算為O(m+n)。
27
4.9
稀疏矩陣
在資料表示法中,稀疏矩陣的每一行以具有標頭節點的環狀鏈結串列表示。稀疏
矩陣的每一列也有類似的表示法。
每一個節點有一個標示欄位,他用來區別標頭節點與資料節點。
每個標頭節點有3個欄位:down, right, next
每個資料節點載標示欄位外還有5個欄位:row, col, down, righ, value
如果ai j ≠ 0,
就有一個節點的標示欄為entry, value = aij, row = i, col = j
每一個標頭節點出現在三個串列中;列串列,行串列,以及標頭節點串列。
28
down head right
next
(a) 標頭節點
down head row col right
value
(b)資料節點
entry i
j
(c)設定aij
圖4.19:稀疏矩陣節點構造
 0 0 11 0 
12 0 0

0


0 4 0
0 


0
0
0

15


圖4.20:4*4稀疏矩陣a
29
Matrix
head
4 4
H0
H1
H3
0 2
11
H0
H1
H2
1 0
12
H2
H3
2 1
-4
3 3
-15
圖4.21:稀疏矩陣a的鏈結表示法
30
4.10
雙向鏈結串列
如果指標指向一個特定點的節點ptr,而我們想要找到在ptr之前的節點。必須從串
列的開頭找起,直到找到一個節點,其鏈結欄位指向ptr為止。
對於刪除運算而言,因為我們必須知道前一個節點的位置,所以最有用的方法是
使用雙向鏈結串列。
在雙向鍊結串列中的節點至少有三個欄位,一個是左鏈結欄( llink ),一個是資料
欄( item ),一個是右鍵欄位( rlink )。
圖4.23中,標頭節點就像之前所說的一樣,可以使我們實作各種運算時較為容易。
標頭節點的item欄通常不包含任何資訊。
31
Head Node
llink item rlink
圖4.23:具有標頭節點的雙向鏈結環狀串列
llink item rlink
ptr
圖4.24:具有標頭節點的空的雙向鏈結環狀串列
32
node
node
newnode
圖4.25:插入節點到空的雙向鏈結環狀串列
node
node
delete
圖4.26:從雙向鏈結環型串列中刪除
33