第 4 章 鏈結串列(Linked Lists)

59
4 4 第第第第第第第第Linked Linked Lists Lists 4-1 4-1 動動動動 動動 動動動動 動動 4-2 4-2 動動動動動動動 動動動動動動動 4-3 4-3 動動動動動動 動動動動動動 4-4 4-4 動動動動動動 動動動動動動 4-5 4-5 動動動動動動 動動動動動動 4-6 4-6 動動動動動動動 動動動動動動動 - - 動動動動動動 動動動動動動

description

第 4 章 鏈結串列(Linked Lists). 4-1 動態記憶體配置 4-2 鏈結串列的基礎 4-3 單向鏈結串列 4-4 環狀鏈結串列 4-5 雙向鏈結串列 4-6 鏈結串列的應用 - 多項式表示法. 4-1 動態記憶體配置 - 說明. 動態記憶體配置不同於陣列的靜態記憶體配置是在編譯階段就配置記憶體空間, 動態記憶體配置 是等到 執行階段,才向作業系統要求配置所需的記憶體空間 ,可以讓程式設計者靈活運用程式所需的記憶體空間。 - PowerPoint PPT Presentation

Transcript of 第 4 章 鏈結串列(Linked Lists)

Page 1: 第 4 章   鏈結串列(Linked Lists)

第第 44 章 章 鏈結串列(鏈結串列( Linked Linked ListsLists))

• 4-1 4-1 動態記憶體配置動態記憶體配置• 4-2 4-2 鏈結串列的基礎鏈結串列的基礎• 4-3 4-3 單向鏈結串列單向鏈結串列• 4-4 4-4 環狀鏈結串列環狀鏈結串列• 4-5 4-5 雙向鏈結串列雙向鏈結串列• 4-6 4-6 鏈結串列的應用 鏈結串列的應用 - - 多項式表示法多項式表示法

Page 2: 第 4 章   鏈結串列(Linked Lists)

4-1 4-1 動態記憶體配置動態記憶體配置 -- 說明說明• 動態記憶體配置不同於陣列的靜態記憶體動態記憶體配置不同於陣列的靜態記憶體

配置是在編譯階段就配置記憶體空間,配置是在編譯階段就配置記憶體空間,動動態記憶體配置態記憶體配置是等到是等到執行階段,才向作業執行階段,才向作業系統要求配置所需的記憶體空間系統要求配置所需的記憶體空間,可以讓,可以讓程式設計者靈活運用程式所需的記憶體空程式設計者靈活運用程式所需的記憶體空間。間。

• 在在 CC 語言語言 <stdlib.h><stdlib.h> 標頭檔的標準函式標頭檔的標準函式庫提供兩個函數:庫提供兩個函數: malloc()malloc()和和 free()free() ,可,可以配置和釋放程式所需的記憶體空間以配置和釋放程式所需的記憶體空間。。

Page 3: 第 4 章   鏈結串列(Linked Lists)

4-1 4-1 動態記憶體配置動態記憶體配置 --malloc()malloc()

malloc()malloc() 函數:配置記憶體空間函數:配置記憶體空間• CC 語言的程式碼可以呼叫語言的程式碼可以呼叫 malloc()malloc() 函數向作業系函數向作業系

統取得一塊可用的記憶體空間統取得一塊可用的記憶體空間,函數的語法,如,函數的語法,如下所示:下所示:fp = (fp = ( 資料型態資料型態 **) malloc(sizeof() malloc(sizeof( 資料型態資料型態 ));));

• 上述語法因為函數傳回上述語法因為函數傳回 voidvoid 通用型指標,所以需通用型指標,所以需要加上型態迫換,要加上型態迫換,將函數傳回的指標轉換成指定將函數傳回的指標轉換成指定資料型態的資料型態的指標指標,, sizeofsizeof 運算子可以計算指定資運算子可以計算指定資料型態的大小。例如:配置一個浮點數變數的記料型態的大小。例如:配置一個浮點數變數的記憶空間,如下所示:憶空間,如下所示:fp = (float *) malloc(sizeof(float));fp = (float *) malloc(sizeof(float));struct test *score;struct test *score;score=(struct test *) malloc(num*sizeof(struct score=(struct test *) malloc(num*sizeof(struct

test));test));

Page 4: 第 4 章   鏈結串列(Linked Lists)

4-1 4-1 動態記憶體配置動態記憶體配置 -free()-free()

free()free() 函數函數::釋放配置的記憶體空間釋放配置的記憶體空間• free()free() 函數可以釋放函數可以釋放 malloc()malloc() 函數配置的函數配置的

記憶體空間,例如:記憶體空間,例如:指標指標 fpfp 是一個指向是一個指向malloc()malloc() 函數傳回的浮點數記憶體空間的函數傳回的浮點數記憶體空間的指標指標,呼叫,呼叫 free()free() 函數釋放這塊記憶體,函數釋放這塊記憶體,如下所示:如下所示:free(fp);free(fp);

• 上述程式碼的指標上述程式碼的指標 fpfp 可以是可以是 floatfloat 浮點數浮點數指標,也可以是指標,也可以是 malloc()malloc() 函數傳回的其它函數傳回的其它資料型態指標、陣列或結構指標。資料型態指標、陣列或結構指標。

Page 5: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 說明說明• 「「有序串列有序串列」(」( Ordered ListOrdered List )或稱為)或稱為

「「線性串列線性串列」(」( Linear ListLinear List ))是一種元是一種元素間擁有順序的集合素間擁有順序的集合,如下所示:,如下所示:(a0, a1, a2, …, an)(a0, a1, a2, …, an),, aiai,, 0 <= i <= n0 <= i <= n

• 上述集合是一個線性串列,如果是上述集合是一個線性串列,如果是空的線空的線性串列性串列,,表示串列中沒有任何元素表示串列中沒有任何元素,是,是使使用用 ( )( ) 空括號表示空括號表示。。

Page 6: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 範例範例• 一些線性串列的一些線性串列的範例範例,如下所示:,如下所示:

– 英文的月份:英文的月份: ( Jan, Feb, March, …, Oct, ( Jan, Feb, March, …, Oct, Nov, Dec )Nov, Dec ) 。。

– 英文的星期:英文的星期: ( Mon, Tue, Wed, Thu, Fri, ( Mon, Tue, Wed, Thu, Fri, Sat, Sun )Sat, Sun ) 。。

– 撲克牌的點數:撲克牌的點數: ( A, 1, 2, 3, 4, 5, 6, 7, 8, 9, ( A, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K )10, J, Q, K ) 。。

– 樓層:樓層: ( B2, B1, 1, 2, 3, 4, 5, 6 )( B2, B1, 1, 2, 3, 4, 5, 6 ) 。。– 生肖:生肖: ( ( 鼠鼠 , , 牛牛 , , 虎虎 , …… , , …… , 狗狗 , , 猪 猪 )) 。。

Page 7: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 運算運算• 線性串列的線性串列的相關運算相關運算,如下所示:,如下所示:

– length()length() ::取得線性串列的長度。取得線性串列的長度。– get()get() ::存取線性串列的第存取線性串列的第 ii 個元素。個元素。– search()search() ::從左到右,或從右到左走訪線性從左到右,或從右到左走訪線性

串列。串列。– delete()delete() ::在線性串列第在線性串列第 ii 個元素刪除元素。個元素刪除元素。– insert()insert() ::在線性串列第在線性串列第 ii 個元素插入元素。個元素插入元素。

Page 8: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 使用陣列使用陣列實作線性串列實作線性串列

Page 9: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 使用陣列使用陣列實作實作線性串列線性串列 (( 問題問題 ))

• 複雜的新增與刪除運算複雜的新增與刪除運算::在在新增或刪除新增或刪除名單時,名單時,因為陣列儲存的是循序且連續因為陣列儲存的是循序且連續資料資料,所以在陣列,所以在陣列中中需要搬移大量元素需要搬移大量元素,才能滿足同縣巿位在同一,才能滿足同縣巿位在同一區段。例如:在桃園巿新增江小魚,則王小美、區段。例如:在桃園巿新增江小魚,則王小美、李光明和周星星都需要依序往後搬移李光明和周星星都需要依序往後搬移 11 個元素,個元素,才能將江小魚插入,同理,刪除王大毛時,之後才能將江小魚插入,同理,刪除王大毛時,之後的所有元素也需要往前搬移。的所有元素也需要往前搬移。

• 浪費記憶體空間浪費記憶體空間::因為並不知道名單有多少位,因為並不知道名單有多少位,所以所以需要宣告一個很大的結構陣列來儲存名單需要宣告一個很大的結構陣列來儲存名單,,如果最後只使用到幾個元素,就會造成大量記憶如果最後只使用到幾個元素,就會造成大量記憶體空間的閒置體空間的閒置。。

Page 10: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 使用鏈結使用鏈結串列實作線性串列串列實作線性串列

• 「「鏈結串列鏈結串列」(」( Linked ListsLinked Lists )是一種實作線性)是一種實作線性串列的資料結構。在現實生活中,鏈結串列串列的資料結構。在現實生活中,鏈結串列如同如同火車掛車廂以線性方式將車廂連結起來,每個車火車掛車廂以線性方式將車廂連結起來,每個車廂是鏈結串列的廂是鏈結串列的節點節點(( NodesNodes ),儲存線性串列),儲存線性串列的資料,車廂和車廂之間的鏈結,就是節點間的的資料,車廂和車廂之間的鏈結,就是節點間的鏈結鏈結(( LinkLink )。)。如下圖所示:如下圖所示:

Page 11: 第 4 章   鏈結串列(Linked Lists)

4-2 4-2 鏈結串列的基礎鏈結串列的基礎 -- 使用鏈結使用鏈結串列實作線性串列串列實作線性串列 (( 實作實作 ))

• 在在 CC 語言建立鏈結串列是語言建立鏈結串列是宣告一個結構作為節點宣告一個結構作為節點,,內含指標內含指標的成員變數的成員變數來鏈結其它節點來鏈結其它節點,使用動態,使用動態記憶體配置在執行階段配置節點所需的記憶體空記憶體配置在執行階段配置節點所需的記憶體空間,間,即可解決結構陣列實作上浪費記憶體的問題即可解決結構陣列實作上浪費記憶體的問題。。

• 例如:使用鏈結串列建立的郵寄名單,筆者僅以例如:使用鏈結串列建立的郵寄名單,筆者僅以編號(從大到小)代表名單的節點資料,郵寄名編號(從大到小)代表名單的節點資料,郵寄名單的鏈結串列,如下圖所示:單的鏈結串列,如下圖所示:

Page 12: 第 4 章   鏈結串列(Linked Lists)

4-3 4-3 單向鏈結串列單向鏈結串列

• 4-3-1 4-3-1 建立和走訪單向鏈結串列建立和走訪單向鏈結串列• 4-3-2 4-3-2 刪除單向鏈結串列的節點刪除單向鏈結串列的節點• 4-3-3 4-3-3 插入單向鏈結串列的節點插入單向鏈結串列的節點

Page 13: 第 4 章   鏈結串列(Linked Lists)

4-3 4-3 單向鏈結串列單向鏈結串列 -- 說明說明• 單向鏈結串列單向鏈結串列是最簡單的一種鏈結串列,是最簡單的一種鏈結串列,

因為因為節點指標節點指標都是都是指向同一個方向指向同一個方向,依序,依序從前一個節點指向下一個節點從前一個節點指向下一個節點,然後,然後最後最後 11個節點指向個節點指向 NULLNULL ,所以稱為單向鏈結串,所以稱為單向鏈結串列,如下圖所示:列,如下圖所示:

Page 14: 第 4 章   鏈結串列(Linked Lists)

4-3 4-3 單向鏈結串列單向鏈結串列 -- 標頭檔標頭檔01: /* 01: /* 程式範例程式範例 : Ch4-3.h */: Ch4-3.h */02: struct Node { /* Node02: struct Node { /* Node 節點結構 節點結構 **//03: int data; /* 03: int data; /* 結構變數宣告 結構變數宣告 **/ / 04: struct Node *next; /* 04: struct Node *next; /* 指向下一個節點 指向下一個節點 **//05: };05: };06: typedef struct Node LNode; /* 06: typedef struct Node LNode; /* 串列節點的新型態 串列節點的新型態 **//07: typedef LNode *List; /* 07: typedef LNode *List; /* 串列的新型態 串列的新型態 **//08: List 08: List firstfirst = NULL; /* = NULL; /* 串列的開頭指標 串列的開頭指標 **//09: /* 09: /* 抽象資料型態的操作函數宣告 抽象資料型態的操作函數宣告 **//10: extern void creatList(int len, int *array);10: extern void creatList(int len, int *array);11: extern int isListEmpty();11: extern int isListEmpty();12: extern void printList();12: extern void printList();13: extern List searchNode(int d);13: extern List searchNode(int d);14: extern int deleteNode(List ptr);14: extern int deleteNode(List ptr);15: extern void insertNode(List ptr, int d);15: extern void insertNode(List ptr, int d);

Page 15: 第 4 章   鏈結串列(Linked Lists)

4-3-1 4-3-1 建立和走訪單向鏈結串建立和走訪單向鏈結串列列 -- 建立建立 (( 說明說明 ))

建立單向鏈結串列建立單向鏈結串列• 在在 createList()createList() 函數函數是是使用使用 forfor迴圈將取得的陣迴圈將取得的陣

列值建立成串列節點列值建立成串列節點,每執行一次迴圈,就在串,每執行一次迴圈,就在串列開頭插入一個新節點,如下所示:列開頭插入一個新節點,如下所示:for ( i = 0; i < len; i++ ) {for ( i = 0; i < len; i++ ) {

newnode = (List) malloc(sizeof(LNode));newnode = (List) malloc(sizeof(LNode));

newnode->data = array[i];newnode->data = array[i];

newnode->next = first;newnode->next = first;

first = newnode;first = newnode;

}}

Page 16: 第 4 章   鏈結串列(Linked Lists)

4-3-1 4-3-1 建立和走訪單向鏈結串建立和走訪單向鏈結串列列 -- 建立建立 (( 圖例圖例 ))

Page 17: 第 4 章   鏈結串列(Linked Lists)

4-3-1 4-3-1 建立和走訪單向鏈結串建立和走訪單向鏈結串列列 -- 走訪走訪 (( 說明說明 ))

單向鏈結串列的走訪單向鏈結串列的走訪• 單向鏈結串列的「走訪」(單向鏈結串列的「走訪」( TraverseTraverse ))

和一維陣列的走訪十分相似,其差異在於和一維陣列的走訪十分相似,其差異在於陣列是遞增索引值來走訪陣列,陣列是遞增索引值來走訪陣列,串列是使串列是使用指標運算來處理節點的走訪用指標運算來處理節點的走訪,如下所示:,如下所示:List current = first;List current = first;while ( current != NULL ) {while ( current != NULL ) { ………… ………….... current = current->next;current = current->next;}}

Page 18: 第 4 章   鏈結串列(Linked Lists)

4-3-1 4-3-1 建立和走訪單向鏈結串建立和走訪單向鏈結串列列 -- 走訪走訪 (( 圖例圖例 ))

Page 19: 第 4 章   鏈結串列(Linked Lists)

4-3-2 4-3-2 刪除單向鏈結串列的節刪除單向鏈結串列的節點點 -- 情況情況 11

• 刪除串列的第刪除串列的第 11 個節點個節點::只需將串列指標只需將串列指標firstfirst 指向下一個節點,如下圖所示:指向下一個節點,如下圖所示:

first = first->next;first = first->next;

Page 20: 第 4 章   鏈結串列(Linked Lists)

4-3-2 4-3-2 刪除單向鏈結串列的節刪除單向鏈結串列的節點點 -- 情況情況 22

• 刪除串列的最後刪除串列的最後 11 個節點個節點::只需只需將最後將最後 11 個節點個節點ptrptr 的前一個節點指標指向的前一個節點指標指向 NULLNULL ,如下圖所示:,如下圖所示:

while (current->next!=ptr)while (current->next!=ptr)

current = current->next;current = current->next;

current->next = NULL;current->next = NULL;

Page 21: 第 4 章   鏈結串列(Linked Lists)

4-3-2 4-3-2 刪除單向鏈結串列的節刪除單向鏈結串列的節點點 -- 情況情況 3(1)3(1)

• 刪除串列的中間節點刪除串列的中間節點::將刪除節點前一個將刪除節點前一個節點的節點的 nextnext 指標,指向刪除節點下一個節指標,指向刪除節點下一個節點點,例如:刪除節點,例如:刪除節點 33 ,如下圖所示:,如下圖所示:

Page 22: 第 4 章   鏈結串列(Linked Lists)

4-3-2 4-3-2 刪除單向鏈結串列的節刪除單向鏈結串列的節點點 -- 情況情況 3(2)3(2)

• 在執行刪除節點在執行刪除節點 33 操作後的串列圖形,如下所示:操作後的串列圖形,如下所示:

while (current->next!=ptr)while (current->next!=ptr) current = current->next;current = current->next;current->next = ptr->next;current->next = ptr->next;

Page 23: 第 4 章   鏈結串列(Linked Lists)

4-3-3 4-3-3 插入單向鏈結串列的節插入單向鏈結串列的節點點 -- 情況情況 11

• 將節點插入串列第將節點插入串列第 11 個節點之前個節點之前::只需只需將新節點將新節點newnodenewnode 的指標指向串列的第的指標指向串列的第 11 個節點個節點 firstfirst ,,新節點就成為串列的第新節點就成為串列的第 11 個節點,如下圖所示:個節點,如下圖所示:

• newnode->next = first;newnode->next = first;

first = newnode;first = newnode;

Page 24: 第 4 章   鏈結串列(Linked Lists)

4-3-3 4-3-3 插入單向鏈結串列的節插入單向鏈結串列的節點點 -- 情況情況 22

• 將節點插在串列的最後將節點插在串列的最後 11 個節點之後個節點之後::只需只需將原將原來串列最後來串列最後 11 個節點的指標指向新節點個節點的指標指向新節點newnodenewnode ,新節點指向,新節點指向 NULLNULL ,如下圖所示:,如下圖所示:

ptr->next = newnode;ptr->next = newnode;

newnode->next = NULL;newnode->next = NULL;

Page 25: 第 4 章   鏈結串列(Linked Lists)

4-3-3 4-3-3 插入單向鏈結串列的節插入單向鏈結串列的節點點 -- 情況情況 3(1)3(1)

• 將節點插在串列的中間位置將節點插在串列的中間位置::假設節點是假設節點是插在插在 pp和和 qq 兩個節點之間兩個節點之間,, pp是是 qq 的前一的前一個節點,如下圖所示:個節點,如下圖所示:

Page 26: 第 4 章   鏈結串列(Linked Lists)

4-3-3 4-3-3 插入單向鏈結串列的節插入單向鏈結串列的節點點 -- 情況情況 3(2)3(2)

• 只需只需將將 pp 指標指向新節點指標指向新節點 newnodenewnode ,然後將新,然後將新節點指標指向節點指標指向 qq ,就可以插入新節點,如下圖所,就可以插入新節點,如下圖所示:示:

newnode->next=ptr->next;newnode->next=ptr->next;

ptr->next = newnode;ptr->next = newnode;

Page 27: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 -- 說明說明• 如果如果將最後一個節點的指標改為指向單向將最後一個節點的指標改為指向單向

鏈結串列開始的第鏈結串列開始的第 11 個節點個節點,這種串列稱,這種串列稱為「為「環狀鏈結串列」(環狀鏈結串列」( Circular ListsCircular Lists )。)。

Page 28: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 --建立與走訪建立與走訪• 環狀鏈結串列的建立只需將最後環狀鏈結串列的建立只需將最後 11 個節點的個節點的 lastlast

指標指向第指標指向第 11 個節點,即可完成環狀鏈結串列的個節點,即可完成環狀鏈結串列的建立,如下所示:建立,如下所示:last->next = first;last->next = first;

• 環狀鏈結串列的走訪環狀鏈結串列的走訪檢查是否到串列結束的條件檢查是否到串列結束的條件是是 current->next == firstcurrent->next == first ,如下所示:,如下所示:CList current = first;CList current = first;do {do { ……… ……… current = current->next;current = current->next;} while ( current != first );} while ( current != first );

Page 29: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 --插入節插入節點點(( 情況情況 1-1- 步驟步驟 ))

• 將將節點插入第節點插入第 11 個節點之前個節點之前成為串列開始,可以成為串列開始,可以分成分成三個步驟三個步驟,如下所示:,如下所示:– Step 1Step 1 : : 將新節點將新節點 newnodenewnode的的 nextnext 指標指向串列指標指向串列

的第的第 11 個節點個節點。。newnode->next = first;newnode->next = first;

– Step 2Step 2 : 然後: 然後找到最後找到最後 11 個節點個節點 previousprevious 且且將其指將其指標指向新節點標指向新節點。。

previous = first;previous = first;while ( previous->next != first )while ( previous->next != first ) previous = previous->next;previous = previous->next;previous->next = newnode;previous->next = newnode;

– Step 3Step 3 : : 將串列的開始指向新節點將串列的開始指向新節點,新節點成為串列,新節點成為串列的第的第 11 個節點。個節點。

first = newnode;first = newnode;

Page 30: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 --插入節插入節點點(( 情況情況 1-1- 圖例圖例 ))

Page 31: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 --插入節插入節點點(( 情況情況 2-2- 步驟步驟 ))

• 將節點插在串列中指定節點之後將節點插在串列中指定節點之後,例如:將節點插在,例如:將節點插在節點節點 ptrptr 之後,分成之後,分成二個步驟二個步驟,如下所示:,如下所示:– Step 1Step 1 ::將新節點將新節點 newnodenewnode的的 nextnext 指標指向節指標指向節點點 ptrptr 的下一個節點的下一個節點。。

newnode->next = ptr->next;newnode->next = ptr->next;

– Step 2Step 2 ::將節點將節點 ptrptr 的指標指向新節點的指標指向新節點newnodenewnode 。。

ptr->next = newnode;ptr->next = newnode;

Page 32: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 --插入節插入節點點(( 情況情況 2-2- 圖例圖例 ))

Page 33: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 -- 刪刪除節點除節點(( 情況情況 1-1- 步驟步驟 ))

• 刪除環狀串列的第刪除環狀串列的第 11 個節點個節點可以分成可以分成二個二個步驟步驟,如下所示:,如下所示:– Step 1Step 1 : : 將串列開始的將串列開始的 firstfirst 指標移至第指標移至第 22 個個

節點節點。。first = first->next;first = first->next;

– Step 2Step 2 : : 將最後將最後 11 個節點的個節點的 previousprevious 指標指標指向第指向第 22 個節點個節點。。

previous->next = ptr->next;previous->next = ptr->next;

Page 34: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 -- 刪刪除節點除節點(( 情況情況 1-1- 圖例圖例 ))

Page 35: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 -- 刪刪除節點除節點(( 情況情況 2-2- 步驟步驟 ))

• 刪除環狀串列的中間節點刪除環狀串列的中間節點,例如:,例如:刪除節點刪除節點ptrptr 分成分成二個步驟二個步驟,如下所示:,如下所示:– Step 1Step 1 ::先找到節點先找到節點 ptrptr 的前一個節點的前一個節點 previousprevious 。。

while ( previous->next != ptr )while ( previous->next != ptr )

previous = previous->next;previous = previous->next;

– Step 2Step 2 ::將將前節點前節點的指標指向節點的指標指向節點 ptrptr 的的下節點下節點。。previous->next = ptr->next;previous->next = ptr->next;

Page 36: 第 4 章   鏈結串列(Linked Lists)

4-4 4-4 環狀鏈結串列環狀鏈結串列 -- 刪刪除節點除節點(( 情況情況 2-2- 圖例圖例 ))

Page 37: 第 4 章   鏈結串列(Linked Lists)

4-5 4-5 雙向鏈結串列雙向鏈結串列

• 4-5-1 4-5-1 雙向鏈結串列的建立與走訪雙向鏈結串列的建立與走訪• 4-5-2 4-5-2 雙向鏈結串列內節點的插入雙向鏈結串列內節點的插入• 4-5-3 4-5-3 雙向鏈結串列內節點的刪除雙向鏈結串列內節點的刪除

Page 38: 第 4 章   鏈結串列(Linked Lists)

4-5 4-5 雙向鏈結串列雙向鏈結串列 -- 說明說明• 「「雙向鏈結串列雙向鏈結串列」(」( Doubly Linked ListsDoubly Linked Lists )是)是另一種常見的鏈結串列結構,這另一種常見的鏈結串列結構,這是一種允許無方是一種允許無方向性走訪的鏈結串列向性走訪的鏈結串列。。

• 所以,我們可以所以,我們可以將兩個方向相反的單向鏈結串列將兩個方向相反的單向鏈結串列結合起來,建立一種無方向性的鏈結串列結合起來,建立一種無方向性的鏈結串列,這,這就就是雙向鏈結串列是雙向鏈結串列,如下圖所示:,如下圖所示:

Page 39: 第 4 章   鏈結串列(Linked Lists)

4-5 4-5 雙向鏈結串列雙向鏈結串列 -- 標頭檔標頭檔01: /* 01: /* 程式範例程式範例 : Ch4-5.h */: Ch4-5.h */02: struct Node { /* Node02: struct Node { /* Node 節點結構 節點結構 **//03: int data; /* 03: int data; /* 結構變數宣告 結構變數宣告 **/ / 04: struct Node *next; /* 04: struct Node *next; /* 指向下一個節點 指向下一個節點 **//05: struct Node *previous; /* 05: struct Node *previous; /* 指向前一個節點 指向前一個節點 **/ / 06: };06: };07: typedef struct Node DNode; /* 07: typedef struct Node DNode; /* 雙向串列節點的新型態 雙向串列節點的新型態 **//08: typedef DNode *DList; /* 08: typedef DNode *DList; /* 雙向串列的新型態 雙向串列的新型態 **//09: DList first = NULL; /* 09: DList first = NULL; /* 雙向串列的開頭指標 雙向串列的開頭指標 **//10: DList now = NULL; /* 10: DList now = NULL; /* 雙向串列目前節點指標 雙向串列目前節點指標 **/ / 11: /* 11: /* 抽象資料型態的操作函數宣告 抽象資料型態的操作函數宣告 **//12: extern void creatDList(int len, int *array);12: extern void creatDList(int len, int *array);13: extern void printDList();13: extern void printDList();14: extern void nextNode();14: extern void nextNode();15: extern void previousNode();15: extern void previousNode();16: extern void resetNode();16: extern void resetNode();17: extern DList readNode();17: extern DList readNode();18: extern void insertDNode(DList ptr, int d);18: extern void insertDNode(DList ptr, int d);19: extern void deleteDNode(DList ptr);19: extern void deleteDNode(DList ptr);

Page 40: 第 4 章   鏈結串列(Linked Lists)

4-5-1 4-5-1 雙向鏈結串列的建立與雙向鏈結串列的建立與走訪走訪 -- 建立建立 (( 步驟步驟 ))

• 雙向鏈結串列比單向鏈結串列雙向鏈結串列比單向鏈結串列多一個指向前一個多一個指向前一個節點的指標節點的指標,, createDList()createDList() 函數函數使用使用 forfor迴圈迴圈建立雙向串列的其它節點,其作法是建立雙向串列的其它節點,其作法是將每一個新將每一個新節點都插入在雙向鏈結串列的最後節點都插入在雙向鏈結串列的最後,一共有,一共有四個四個步驟步驟,如下所示:又必須在別地方輸入再拷貝過,如下所示:又必須在別地方輸入再拷貝過來來– Step 1Step 1 :將:將新節點的新節點的 nextnext 指標指標指向指向 NULLNULL 。。– Step 2Step 2 :將:將新節點的新節點的 previousprevious 指標指標指向指向 beforebefore 指指

標。標。– Step 3Step 3 :將:將 beforebefore 指向指向節點的節點的 nextnext 指標指標指向新節點指向新節點。。– Step 4Step 4:: beforebefore 指標指標指向指向串列的串列的最後最後 11 個節點個節點 (( 新新

節點節點 )) 。。

Page 41: 第 4 章   鏈結串列(Linked Lists)

4-5-1 4-5-1 雙向鏈結串列的建立與雙向鏈結串列的建立與走訪走訪 -- 建立建立 (( 圖例圖例 ))

for ( i = 1; i < len; i++ ) { newnode = (DList) malloc(sizeof(DNode)); newnode->data = array[i]; newnode->next = NULL; newnode->previous=before; before->next=newnode; before = newnode;}

Page 42: 第 4 章   鏈結串列(Linked Lists)

4-5-1 4-5-1 雙向鏈結串列的建立與雙向鏈結串列的建立與走訪走訪 -- 走訪走訪

• 雙向鏈結串列走訪雙向鏈結串列走訪比單向鏈結串列靈活,因為比單向鏈結串列靈活,因為可可以以分別使用分別使用 nextnext和和 previousprevious 指標從兩個方向進指標從兩個方向進行走訪行走訪,模組函數,模組函數nextNode()nextNode()、、 previousNode()previousNode()和和resetNode()resetNode() 可以移動可以移動 nownow 指標來走訪雙向串指標來走訪雙向串列下一個或前一個節點。列下一個或前一個節點。

• 如果讀者學過如果讀者學過 C++C++ 語言的語言的 STLSTL(( Standard Standard Template LibraryTemplate Library )或)或 JavaJava 語言的語言的CollectionsCollections 物件,雙向串列的相關走訪函數就物件,雙向串列的相關走訪函數就是容器物件(是容器物件( ContainerContainer )的「重複指標」)的「重複指標」(( IteratorsIterators )。)。

Page 43: 第 4 章   鏈結串列(Linked Lists)

4-5-2 4-5-2 雙向鏈結串列內節點的雙向鏈結串列內節點的插入插入 -- 情況情況 1(1( 步驟步驟 ))

• 將節點插在串列中第將節點插在串列中第 11 個節點之前個節點之前::新節新節點將成為串列的第點將成為串列的第 11 個節點,其步驟如下個節點,其步驟如下所示:所示:– Step 1Step 1 :將:將新節點新節點 newnodenewnode的的 nextnext 指標指指標指

向向雙向串列的雙向串列的第第 11 個節點個節點。。newnode->next = first;newnode->next = first;

– Step 2Step 2 :將原串列:將原串列第第 11 個節點的個節點的 previousprevious 指指標指向新節點標指向新節點。。

first->previous = newnode;first->previous = newnode;

– Step 3Step 3 :將原串列的:將原串列的 firstfirst 指標指向新節點指標指向新節點,,新節點成為新節點成為環狀環狀 (???)(???) 串列的開始。串列的開始。first = newnode;first = newnode;

Page 44: 第 4 章   鏈結串列(Linked Lists)

4-5-2 4-5-2 雙向鏈結串列內節點的雙向鏈結串列內節點的插入插入 -- 情況情況 1(1( 圖例圖例 ))

Page 45: 第 4 章   鏈結串列(Linked Lists)

4-5-2 4-5-2 雙向鏈結串列內節點的雙向鏈結串列內節點的插入插入 -- 情況情況 2(2( 步驟步驟 ))

• 將節點插在串列的最後將節點插在串列的最後::新節點是插入成新節點是插入成為串列的最後為串列的最後 11 個節點,其步驟如下所示:個節點,其步驟如下所示:– Step 1Step 1 :將:將最後最後 11 個節點個節點 ptrptr的的 nextnext 指標指指標指

向新節點向新節點 newnodenewnode 。。ptr->next = newnode;ptr->next = newnode;

– Step 2Step 2 :將:將新節點的新節點的 previousprevious 指標指向指標指向原串原串列的列的最後最後 11 個節點個節點。。

newnode->previous=ptr;newnode->previous=ptr;

– Step 3Step 3 :將:將新節點的新節點的 nextnext 指標指標指向指向 NULLNULL 。。newnode->next = NULL;newnode->next = NULL;

Page 46: 第 4 章   鏈結串列(Linked Lists)

4-5-2 4-5-2 雙向鏈結串列內節點的雙向鏈結串列內節點的插入插入 -- 情況情況 2(2( 圖例圖例 ))

Page 47: 第 4 章   鏈結串列(Linked Lists)

4-5-2 4-5-2 雙向鏈結串列內節點的雙向鏈結串列內節點的插入插入 -- 情況情況 3(3( 步驟步驟 ))

• 將將節點插入成為串列的中間節點節點插入成為串列的中間節點::如果節點是如果節點是插插在在 ptrptr 節點之後節點之後,插入步驟如下所示:,插入步驟如下所示:– Step 1Step 1 ::將將 ptrptr 節點節點 nextnext 指向指向下一個節點下一個節點的的

previousprevious 指標指向新節點指標指向新節點。。ptr->next->previous = newnode;ptr->next->previous = newnode;

– Step 2Step 2 ::新節點的新節點的 nextnext 指標指標指向指向 ptrptr 節點節點 nextnext 指標指標的下一個節點的下一個節點。。

newnode->next = ptr->next;newnode->next = ptr->next;

– Step 3Step 3 ::新節點的新節點的 previousprevious 指標指標指向指向 ptrptr 節點節點。。newnode->previous = ptr;newnode->previous = ptr;

– Step 4Step 4 ::將將 ptrptr 節點的節點的 nextnext 指標指標指向新節點指向新節點。。ptr->next = newnode;ptr->next = newnode;

Page 48: 第 4 章   鏈結串列(Linked Lists)

4-5-2 4-5-2 雙向鏈結串列內節點的雙向鏈結串列內節點的插入插入 -- 情況情況 3(3( 圖例圖例 ))

Page 49: 第 4 章   鏈結串列(Linked Lists)

4-5-3 4-5-3 雙向鏈結串列內節點的雙向鏈結串列內節點的刪除刪除 -- 情況情況 11

• 刪除串列的第刪除串列的第 11 個節點個節點::原串列的第原串列的第 22 個個節點就成為第節點就成為第 11 個節點,其步驟如下所示:個節點,其步驟如下所示:– Step 1Step 1 :將:將 firstfirst 指標指向第指標指向第 22 個節點個節點。。

first = first->next;first = first->next;

– Step 2Step 2 :將原串列:將原串列第第 22 個節點的個節點的 previousprevious 指指標指定成標指定成 NULLNULL 。。

first->previous = NULL;first->previous = NULL;

Page 50: 第 4 章   鏈結串列(Linked Lists)

4-5-3 4-5-3 雙向鏈結串列內節點的雙向鏈結串列內節點的刪除刪除 -- 情況情況 22

• 刪除最後刪除最後 11 個節點個節點::原串列最後第原串列最後第 22 個節個節點就成為最後點就成為最後 11 個節點,其步驟如下所示:個節點,其步驟如下所示:– Step 1Step 1 :將原串列的:將原串列的最後最後 11 個節點個節點的的前一個前一個

節點節點的的 nextnext 指標指標指定成指定成 NULLNULL 。。ptr->previous->next = NULL;ptr->previous->next = NULL;

Page 51: 第 4 章   鏈結串列(Linked Lists)

4-5-3 4-5-3 雙向鏈結串列內節點的雙向鏈結串列內節點的刪除刪除 -- 情況情況 3(3( 步驟步驟 ))

• 刪除串列內的中間節點刪除串列內的中間節點::若若刪除刪除的是串列中的是串列中的的 ptrptr 節點節點,操作步驟,如下所示:,操作步驟,如下所示:– Step 1Step 1 ::將將 ptrptr 節點節點 previousprevious 指標指向的指標指向的前前

一個節點的一個節點的 nextnext 指標指標指向指向 ptrptr 節點的下一個節節點的下一個節點點。。

ptr->previous->next = ptr->next;ptr->previous->next = ptr->next;

– Step 2Step 2 ::將將 ptrptr 節點節點 nextnext 指標指向的指標指向的後一個節後一個節點的點的 previousprevious 指標指向指標指向 ptrptr 節點的節點的前一個節點前一個節點。。

ptr->next->previous = ptr->previous;ptr->next->previous = ptr->previous;

Page 52: 第 4 章   鏈結串列(Linked Lists)

4-5-3 4-5-3 雙向鏈結串列內節點的雙向鏈結串列內節點的刪除刪除 -- 情況情況 3(3( 圖例圖例 ))

Page 53: 第 4 章   鏈結串列(Linked Lists)

4-6 4-6 鏈結串列的應用 鏈結串列的應用 - - 多項式多項式表示法表示法 (( 開頭節點串列開頭節點串列 ))

• 開頭節點開頭節點的觀念是指在串列的開頭新增一的觀念是指在串列的開頭新增一個虛節點,這個節點並沒有儲存資料個虛節點,這個節點並沒有儲存資料,只,只是作為串列的第是作為串列的第 11 個節點,所有環狀串列個節點,所有環狀串列的節點都是中間節點,換句話說,刪除和的節點都是中間節點,換句話說,刪除和插入的操作就只剩下第插入的操作就只剩下第 4-44-4 節的第二種情節的第二種情況。況。

Page 54: 第 4 章   鏈結串列(Linked Lists)

4-6 4-6 鏈結串列的應用 鏈結串列的應用 - - 多項式多項式表示法表示法 (( 標頭檔標頭檔 ))

01: /* 01: /* 程式範例程式範例 : Ch4-6.h */: Ch4-6.h */02: struct Node { /* Node02: struct Node { /* Node 節點結構 節點結構 **//03: float coef; int exp; /* 03: float coef; int exp; /* 結構變數宣告 結構變數宣告 **//04: struct Node *next; /* 04: struct Node *next; /* 指向下一個節點 指向下一個節點 **//05: };05: };06: typedef struct Node PNode; 06: typedef struct Node PNode; 07: typedef PNode *PList; /* 07: typedef PNode *PList; /* 多項式串列的新型態 多項式串列的新型態 **//08: /* 08: /* 抽象資料型態的操作函數宣告 抽象資料型態的操作函數宣告 **//09: extern PList createPoly(int len, float *array);09: extern PList createPoly(int len, float *array);10: extern void printPoly(PList first);10: extern void printPoly(PList first);

Page 55: 第 4 章   鏈結串列(Linked Lists)

4-6 4-6 鏈結串列的應用 鏈結串列的應用 - - 多項式多項式表示法表示法 (( 多項式圖例多項式圖例 ))

• 使用含開頭節點的環狀串列來處理多項式,使用含開頭節點的環狀串列來處理多項式,如下所示:如下所示:A(X)=7XA(X)=7X44+3X+3X22+4+4

B(X)=6XB(X)=6X55+5X+5X44+X+X22+7X+9+7X+9

Page 56: 第 4 章   鏈結串列(Linked Lists)

本章結束

Page 57: 第 4 章   鏈結串列(Linked Lists)

複習複習 (( 一一 ))

• 1.1. 動態記憶體配置動態記憶體配置的意義為何的意義為何 ??• 2.2. 何謂何謂有序串列有序串列 ??• 3.3. 線性串列線性串列的問題為何的問題為何 ??• 4.4. 何謂「何謂「鏈結串列鏈結串列」(」( Linked ListsLinked Lists)) ??• 5.5. 何謂何謂單向鏈結串列單向鏈結串列 ??• 6.6.說明說明刪除刪除單向鏈結單向鏈結串列的串列的最後最後 11 個節點個節點演算演算法法 ??

• 7.7.說明說明刪除刪除單向鏈結單向鏈結串列的串列的中間節點中間節點演算法演算法 ? ? • 8.8.說明說明將節點將節點插入插入單向鏈結單向鏈結串列的串列的第第 11 個節點個節點

之前之前的演算法的演算法 ??

Page 58: 第 4 章   鏈結串列(Linked Lists)

複習複習 (( 二二 ))

• 9.9. 說明說明將節點將節點插入插入單向鏈結單向鏈結串列的串列的最後最後 11 個節個節點之後點之後的演算法的演算法 ??

• 10.10. 說明說明將節點將節點插入插入單向鏈結單向鏈結串列的串列的中間節點中間節點之後之後的演算法的演算法 ??

• 11.11. 何謂何謂「環狀鏈結串列」「環狀鏈結串列」 ??

• 12.12. 將節點將節點插入插入環狀鏈結環狀鏈結串列的串列的第第 11 個節點之個節點之前前的三個步驟為何的三個步驟為何 ??

• 13.13. 將節點將節點插入插入環狀鏈結環狀鏈結串列的串列的指定節點之後指定節點之後的二個步驟為何的二個步驟為何 ??

Page 59: 第 4 章   鏈結串列(Linked Lists)

複習複習 (( 三三 ))

• 14.14. 刪除刪除環狀串列的環狀串列的第第 11 個節點個節點的二個步驟為何的二個步驟為何 ??• 15.15. 刪除刪除環狀串列的環狀串列的中間節點中間節點的二個步驟為何的二個步驟為何 ??• 16.16. 何謂何謂「雙向鏈結串列」「雙向鏈結串列」 ??

• 17.17. 將節點將節點插入插入雙向鏈結雙向鏈結串列的串列的第第 11 個節點之前個節點之前的三個的三個步驟為何步驟為何 ??

• 18.18. 說明說明將節點將節點插入插入雙向雙向鏈結雙向雙向鏈結串列的串列的最後最後 11 個節點個節點之後之後的三個步驟為何的三個步驟為何 ??

• 18.18. 說明說明將節點將節點插入插入雙向雙向鏈結雙向雙向鏈結串列的串列的中間節點中間節點的四的四個步驟為何個步驟為何 ??