LINKED LISTS
Michael Tsai
2010/10/15 作業二下星期四 due
請多利用下周二三四的 office
hour
今日菜單
•
上次講得不好的 Sparse Matrix Transpose 方法•
上次未講完的迷宮問題•
Linked List•
應用•
多項式•
相等集合•
很鬆的矩陣來一個有趣的迷宮問題吧
•
迷宮 : 0 是路 , 1 是牆壁 . 每一部可以往上、下、左、右 和四個斜角方向走一步 .•
問題 : 怎麼找出一條路從 (0,0) 走到 (7,7) ? ( 不一定要 最短 )•
提示 : 跟 stack 是朋友0 1 2 3 4 5 6 70 0 1 1 1 1 0 1 1
1 0 0 0 0 0 0 0 1
2 1 1 1 1 1 1 1 0
3 1 0 0 0 0 0 0 1
4 0 1 1 1 1 1 1 1
5 0 0 0 1 1 0 1 0
6 0 1 0 1 0 1 0 1
7 0 1 1 0 1 1 1 0
走迷宮的時候 , 人要怎麼走 ?
•
最重要的時候 , 是碰到岔路的時候•
先記起來 , 選其中一條走走看•
如果碰壁了 ( 一直沒有走到終點 ), 就退回最後一次碰到 的岔路 , 換另外一條岔路•
關鍵字 : 最後一次碰到的岔路 ( 不是最先碰到的 )•
所以是先進後出使用 stack•
關鍵字 : 換另外一條岔路•
要記得上一次走過哪一條路了一些細節
•
Q: 那麼 , stack 裡面要存什麼呢 ?•
A:•
“ 岔路”的地方的•
座標 , 也就是 (row, col)•
試過那些岔路了 ( 試到八個方向的哪個方向了 )•
Q: 要怎麼預防繞圈圈 ? ( 永遠出不來 )•
A: 標示所有已經走過的地方 , 走過就不用再走了•
< 注意 > 這是因為不用找”最短”的路讓我們來寫 algorithm
• 把 (row_start, col_start, 第一個方向 ) 放入 stack
• while(stack 不是空的 ) {
• 從 stack 拿出一組岔路點 (row, col, dir)
• while( 還有別的 dir 還沒試 ) {
•
將 (row, col) 往 dir 方向移動 , 得到 (row_n, col_n, dir).•
如果 (row_n, col_n) 就是終點 , 則結束•
如果 (row_n, col_n) 不是牆壁且沒有來過 {•
標示 (row_n, col_n) 來過了•
把 (row, col, dir 的下一個方向 ) 放入 stack•
row=row_n; col=col_n; dir= 第一個方向 ;•
}• }
• }
大家來吐 Array 的槽
•
Array 有什麼不好 ?•
插入新 element•
刪除原本的 element•
Time complexity= O(??)1 3 4 2 5 空
1 3 新的 4 2 5
1 3 4 2 5
1 3 2 5
新朋友 : Linked List
•
要怎麼讓資料•
1. 可以隨便亂排•
2. 但是我們仍然知道他的順序 ?•
答案 :•
資料亂排•
但是 , 另外存“下一個是誰”子毅 林潔 立中 婷尹 予迪
4 0 1 -1 3
資料
開始 1 下一個是誰
index [0] [1] [2] [3] [4]
概念上 , 應該是長這樣
子毅 林潔 立中 婷尹 予迪
4 0 1 -1 3
資料
開始 2 下一個是誰
index [0] [1] [2] [3] [4]
林潔 子毅
立中 予迪 婷尹 Null
真正的樣子 :
開始
增加一個人 ?
林潔 子毅
立中 予迪 婷尹 Null
開始
柏廷
子毅 林潔 立中 婷尹 予迪 柏廷
4 0 1 -1 3
資料
開始 2 下一個是誰
index [0] [1] [2] [3] [4] [5]
4 0 1 -1 3 0
4 5 1 -1 3 0
刪掉一個人
林潔 子毅
立中 予迪 婷尹 Null
開始
柏廷
子毅 林潔 立中 婷尹 予迪 柏廷
資料
開始 2 下一個是誰
index [0] [1] [2] [3] [4] [5]
4 5 1 -1 3 0
4 5 1 -1 3 4
來看一些 code ( 用 malloc/free)
•
怎麼宣告一個 node 的 struct?struct listNode {
int data;
struct listNode *link;
};
•
怎麼拿一個新的 node?•
listNode *new;•
new=(struct listNode*)malloc(sizeof(struct listNode));來看一些 code
•
new 是指標 , 指到一個 struct listNode 的變數 .•
那如果要拿這個變數裡面的 data 呢 ?•
可以這樣寫 :•
(*new).data•
或者 ,•
new->data•
要拿 link 呢 ?•
(*new).link•
或者 ,•
new->link來看一些 code
•
假設 start 指到第一個 struct listNode•
那麼我要拿到 551 的下一個 listNode 的位址怎麼寫 ?•
start->link->link ( 連續技 )551 342
製造兩個 node
•
struct listNode* start, *tmp;
•
tmp=(struct listNode*)malloc(sizeof(struct l istNode));
•
tmp->data=551;
•
tmp->link=NULL;
•
start=tmp;
•
tmp=(struct listNode*)malloc(sizeof(struct l istNode));
•
tmp->data=342;
•
tmp->next=start;
•
start=tmp;
551 342
插入一個新 node 在某 node 後面
•
struct listNode *x; // 指到要插入的 node 的位置•
struct listNode *new;•
new=(struct listNode*)malloc(sizeof(struct listNode));•
new->data=123;•
下一步呢 ? 先處理 new->link 還是 x->link?•
new->link=x->link;•
x->link=new;刪除某一個 node
•
struct listNode *x; // 指到要刪除的 node 的位置•
struct listNode *trail; // 指到 x 的前一個 node 的位置•
分兩種狀況處理 : x 是頭 , 還有 x 不是頭•
if (trail) //x 不是第一個 node•
trail->link=x->link;•
else•
start=x->link;•
free(x);印出整個 list
•
struct listNode *tmp;•
for(tmp=start; tmp; tmp=tmp->next)•
printf(“%d “, tmp->data);Stack & Queue
•
上次最後提到 , 如果是一塊記憶體要放很多 stack 或 queu e•
就很難做到很 efficient•
例如如果某一 stack 滿了 , 就要把一堆資料往後擠•
就不是 O(1) 了 T_T•
解決 : 跟 Linked List 當朋友Stack
• 要怎麼拿來當 stack 呢 ? ( 想想怎麼做主要的 operation)
• push & pop
• 請一位同學上來講解
• 例 : push(“ 立中” )
• start 當作 stack top
• 怎麼寫 code?
• 那 pop 呢 ?
林潔 子毅
立中 予迪 婷尹 Null
start
Queue
• 類似 stack 的作法
• 不過頭尾都要有一個指標
• 從頭拿 , 從尾放
• 怎麼拿 ? (delete)
• struct listNode* tmp;
• tmp=front;
• front=front->link;
• tmp_data=tmp->data;
• free(tmp);
• return tmp_data;
林潔 子毅 予迪 婷尹 Null
front
rear
Queue
•
那怎麼放 ?•
假設 new 是指到新的 node•
rear->link=new;•
new->link=NULL;•
rear=new;林潔 子毅 予迪 婷尹
front rear
立中
< 動腦時間 >
•
有沒有什麼是 array 比 linked list 好的 ?•
什麼時候用 array?•
什麼時候用 linked list?多項式
•
陰魂不散多項式•
怎麼用 linked list 表示呢 ? struct polyNode {int coef;
int expon;
struct polyNode *link;
};
例 :
•
3 14 a
2 8 1 0
那麼 , 多項式加法 ?
•
挑戰 ! 直接看 code!•
Time complexity = O(??)•
那之前用 array 表示 , 有什麼不好 ?•
答案 : 用完的比較好回收•
不回收會怎樣 ?•
怎麼回收 ? 請一位同學來解釋回收很慢
•
有幾項就要 O( 幾項 ) 的時間•
懶人方法 : 丟到一個”回收桶” , 之後需要的時候再撿 出來•
希望丟 =O(1), 而且撿 =O(1)•
怎麼做 ?•
關鍵 : 找尾巴很慢 . ( 不是 O(1))3 14
a 2 8 1 0
回收桶
Circular List
•
“ 開始”的那個箭頭 , 指在尾巴•
最後一個 node 指回開頭•
有什麼好處 ?•
丟進回收桶 =O(1) !!•
請看 program 4.15 on p.169 ( 用 circular list 來做多 項式加法 )3 14
多項式 a
2 8 1 0
回收桶 temp
來練習一些動作
•
反過來 : 把•
變成•
怎麼弄 ?•
請同學上來解釋 + 用白板寫程式3 14 2 8 1 0
a
1 0 2 8 3 14
b
練習題
•
把 list b 接到 list a 後面 (chain)•
把一個新的 node 加到 circular list 的最前面•
找出長度 (circular list)Singly v.s. doubly linked list
• 有單就有雙
• 什麼時候需要用雙 ?
• Singly linked list 只能往後 , 不能往前 ( 要從最前面開始重新 找 )
• Doubly linked list 用在常常需要”倒帶”的時候
• Doubly circular linked list???? ( 請一位同學來畫 )
3 14 2 8 1 0
a
Singly linked list:
3 1
4 2 8 1 0
a
Doubly linked list:
暫停 !
•
來回想一下我們學了哪些種類的 linked list•
Singly linked list• Circular
• Non-circular (chain)
•
Doubly linked list• Circular
• Non-circular (chain)