## Full text

(1)

Prof. Michael Tsai 2017/3/14

(2)

### 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

(3)

### Complexity for the array implementation

Array Dynamic Array

(Expand to twice of the original space when full)

(What we are learning today)

Indexing

(Get a particular element)

O(1) O(1) ??

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) ??

(4)

• How do we arrange the data, such

1. We can arbitrarily change their order, 2. But we still keep a record of their order?

• 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]

(5)

### 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

(6)

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

(7)

### Remove an existing element?

index [0] [1] [2] [3] [4] [5]

4 5 1 -1 3 0

4 5 1 -1 3 4

Null

(8)

### 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));

(9)

### 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?

• (*new).data

• Or,

• new->data

• (*new).next

• 或者,

• new->next

(10)

### 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

1 struct ListNode { 2 int data;

3 struct ListNode *next;

4 };

(11)

### Create two nodes

342 551

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

11 tmp=(struct ListNode*)malloc(sizeof(struct ListNode));

12

13 tmp->data=342;

15

(12)

### 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;

(13)

### Deleting a node

• Two possible conditions: x is/is not the head node

trail x

551

342

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

6 free(x);

(14)

(15)

### 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 }

(16)

### Comparison of complexity

Array Dynamic Array

(Expand to twice of the original space when full)

Indexing

(Take a particular element)

O(1) O(1) O(n)

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)

(17)

### Discussion

• When should we use array?

• When should we use linked list?

• Explain why.

(18)

### Example: Stacks & Queues

• 如果是一塊記憶體要放很多stack或queue

• 就很難做到很efficient

• 例如如果某一stack滿了, 就要把一堆資料往後擠

• 就不是O(1)了 T_T

(19)

### Stack

• 要怎麼拿來當stack呢? (想想怎麼做主要的operation)

• push & pop

• 請一位同學來講解J

• 例: push(“學”)

• 怎麼寫code?

• 那pop呢?

Null

(20)

### Queue

struct ListNode* tmp;

tmp=front;

tmp_data=tmp->data;

free(tmp);

return tmp_data;

Null

front

rear

(21)

### Queue

• 那怎麼放?

• 假設new是指到新的node

• rear->next=new;

• new->next=NULL;

• rear=new;

front rear

new

(22)

• 反過來: 把

• 變成

• 怎麼弄?

3 14 2 8 1 0

a

1 0 2 8 3 14

b

(23)

### 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

Space for two pointers (instead of one) (see: http://goo.gl/qifrq2)

3 14 2 8 1 0

3 14 2 8 1 0

(24)

### 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

(25)

### 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

2 8 1 0

(26)

### Let’s review!

• The types of linked lists that we introduced today:

Circular

Non-circular (chain)

Circular

Non-circular (chain)

(27)

### (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.

Updating...

## References

Related subjects :