Linked Lists
Prof. Michael Tsai 2017/3/14
What’s wrong with Arrays?
• Inserting a new element
• Deleting an existing element
• Time complexity= O(??)
1 3 4 2 5 Empty
1 3 New 4 2 5
1 3 4 2 5
1 3 2 5
Complexity for the array implementation
Array Dynamic Array
(Expand to twice of the original space when full)
Linked List
(What we are learning today)
Indexing
(Get a particular element)
O(1) O(1) ??
Insert/Delete at the head
O(n), only feasible if not full
O(n) ??
Insert/Delete at the tail
O(1), only feasible if not full
O(1), if not full O(n), if full
??
Insert/Delete in the middle
O(n), only feasible if not full
O(n) ??
Wasted space 0 O(n) ??
New friend: Linked List
• How do we arrange the data, such
1. We can arbitrarily change their order, 2. But we still keep a record of their order?
• Answer:
• The order of the elements can be arbitrary,
• But, we store “which is the next” in addition to the data.
ㄇ ㄆ ㄅ ㄉ ㄈ
4 0 1 -1 3
data
Which is the next
index [0] [1] [2] [3] [4]
Conceptually, it looks like this:
4 0 1 -1 3
data
head 2 Which is the next
index [0] [1] [2] [3] [4]
ㄇ ㄆ
ㄅ ㄈ ㄉ Null
Actual implementation
Start
ㄇ ㄆ ㄅ ㄉ ㄈ
Add an additional element?
ㄐ
ㄇ ㄆ ㄅ ㄉ ㄈ ㄐ
4 0 1 -1 3
data
head 2 Which is the next
index [0] [1] [2] [3] [4] [5]
4 0 1 -1 3 0
4 5 1 -1 3 0
ㄆ ㄇ
ㄅ ㄈ ㄉ Null
Start
Remove an existing element?
資料
開始 2
下一個是誰
index [0] [1] [2] [3] [4] [5]
4 5 1 -1 3 0
4 5 1 -1 3 4
ㄐ ㄆ ㄇ
ㄅ ㄈ ㄉ Null
開始
ㄇ ㄆ ㄅ ㄉ ㄈ ㄐ
Code segments:
Struct and create a new node.
1 //Structure declaration for the list node 2 struct ListNode {
3 int data;
4 struct ListNode *next;
5 };
6
7 //Create a new node 8 struct ListNode *new;
9 new=(struct ListNode*)malloc(sizeof(struct listNode));
Code segments:
accessing the structure members
• new is a pointer , pointing at a variable of type struct listNode.
• How do we obtain the member data in this variable?
• Answer: by
• (*new).data
• Or,
• new->data
• How about next?
• (*new).next
• 或者,
• new->next
Code segments:
accessing the next node
• Assume head points at the first node
• How do I get the value of next in the “551 node”?
551 342
head
1 struct ListNode { 2 int data;
3 struct ListNode *next;
4 };
Create two nodes
(Insert from the head)
342 551head
1 struct ListNode *head, *tmp;
2
3 tmp=(struct ListNode*)malloc(sizeof(struct ListNode));
4 if (tmp==NULL)
5 exit(-1); // exit program on error 6
7 tmp->data=551;
8 tmp->next=NULL;
9
10 head=tmp;
11 tmp=(struct ListNode*)malloc(sizeof(struct ListNode));
12
13 tmp->data=342;
14 tmp->next=head;
15
16 head=tmp;
Insert a new node after a certain node
Do we process new->next first or x->next first?
551 342
x
342
123
new
1 struct ListNode *x;
2 //Pointing at the node before the location to 3 //be inserted
4
5 struct ListNode *new;
6
7 new=(struct ListNode*)malloc(sizeof(struct ListNode));
8 new->data=123;
1 new->next=x->next;
2 x->next=new;
Deleting a node
• Two possible conditions: x is/is not the head node
trail x
551
342
head x
1 struct ListNode *head; //Pointing at the head node 2 struct ListNode *x;
3 //Pointing at the node to be deleted 4 struct ListNode *trail;
5 //Pointing at the node before the node to be //deleted
1 if (trail)
2 //x is not the first node 3 trail->next=x->next;
4 else
5 head=x->next;
6 free(x);
Examples: Traverse and Print
• Traverse (and print) linked list
1 struct ListNode *tmp;
2 for(tmp=head; tmp!=NULL; tmp=tmp->next) { 3 printf("%d", tmp->data);
4 // you can do other processing here too
5 }
Correct the code below: Find
• Find the location before a node with a particular data value
• This code segment would crash in certain conditions.
Correct it!
1 int a=123; //123 is the data to look for 2 struct ListNode *tmp;
3 for(tmp=head; tmp!=NULL; tmp=tmp->next) { 4 if (tmp->next->data==a)
5 break;
6 //when breaking, tmp is what we are looking for
7 }
8 }
Comparison of complexity
Array Dynamic Array
(Expand to twice of the original space when full)
Linked List
Indexing
(Take a particular element)
O(1) O(1) O(n)
Insert/Delete at the head
O(n), only feasible if not full
O(n) O(1)
Insert/Delete at the tail
O(1), only feasible if not full
O(1), if not full O(n), if full
O(n) find the tail O(1) insert/delete Insert/Delete in
the middle
O(n), only feasible if not full
O(n) O(n) find the loc.
O(1) insert/delete Wasted space 0 (when full) O(n)
(up to half of the space empty)
O(n)
(accounting for the next field)
Discussion
• When should we use array?
• When should we use linked list?
• Explain why.
Example: Stacks & Queues
• 如果是一塊記憶體要放很多stack或queue
• 就很難做到很efficient
• 例如如果某一stack滿了, 就要把一堆資料往後擠
• 就不是O(1)了 T_T
• 解決: 跟Linked List當朋友
Stack
• 要怎麼拿來當stack呢? (想想怎麼做主要的operation)
• push & pop
• 請一位同學來講解J
• 例: push(“學”)
• head當作stack top
• 怎麼寫code?
• 那pop呢?
訊 工
資 程 系 Null
head
Queue
• 類似stack的作法
• 不過頭尾都要有一個指標
• 從頭拿, 從尾放
• 怎麼拿? (DeQueue)
struct ListNode* tmp;
tmp=front;
front=front->link;
tmp_data=tmp->data;
free(tmp);
return tmp_data;
資 訊 工 程 Null
front
rear
Queue
• 那怎麼放?
• 假設new是指到新的node
• rear->next=new;
• new->next=NULL;
• rear=new;
資 訊 工 程
front rear
new
系
練習題2: 把linked list反過來
• 反過來: 把
• 變成
• 怎麼弄?
3 14 2 8 1 0
a
1 0 2 8 3 14
b
答案
Singly v.s. doubly linked list
• When do you need to use doubly linked list?
• Singly linked list: can only traverse forward, not backward
• (go all the way back to the head)
• When we need to frequently traverse backward: use doubly linked list
• Trade-offs:
• Space for two pointers (instead of one) (see: http://goo.gl/qifrq2)
3 14 2 8 1 0
head
Singly linked list:
3 14 2 8 1 0
head
Doubly linked list:
Recycling
• Return the memory occupied by the nodes to the system when done. (Why?)
• O(n) time to return all the nodes
• Alternative: recycling! Collect all “deleted nodes”, and use them when necessary.
• Goal: O(1) time for both delete and new (from recycled nodes)
• How
• Key: slow to find the tail (obviously, not O(1) time operation)
• Can we avoid using the tail pointer?
3 14
a 2 8 1 0
recycled_head
Sol: Circular List
• head pointer points at the tail.
• The tail node’s next pointer points to the head node (instead of setting it as NULL).
• Easy to connect the entire list with another list!
Place the entire list to the recycled list=O(1) !!
• We can also have doubly circular linked list!
3 14
head
2 8 1 0
recycled_head temp
Let’s review!
• The types of linked lists that we introduced today:
• Singly linked list
• Circular
• Non-circular (chain)
• Doubly linked list
• Circular
• Non-circular (chain)
(If time permits) Practice Problems
• Given a (singly) linked list of unknown length, design an algorithm to find the n-th node from the tail of the linked list. Your algorithm is allowed to traverse the linked list only once.
• Reverse a given singly linked list using the original link nodes.