Chapter 4 Queues and Lists 4 1 Queue

  • Slides: 69
Download presentation
Chapter 4 Queues and Lists 4 -1

Chapter 4 Queues and Lists 4 -1

Queue n First-in first-out (FIFO) n First come first serve (FCFS) n 2 ends:

Queue n First-in first-out (FIFO) n First come first serve (FCFS) n 2 ends: Data are inserted to one end (rear) and removed from the other end (front). 4 -2

Linear queue (和課本稍不同) initial insert(A) insert(B) B remove rear front A rear A front

Linear queue (和課本稍不同) initial insert(A) insert(B) B remove rear front A rear A front Insert(C) rear front someday E rear D C B n rear front B front insert(F): overflow, but there are still some empty locations in the lower part. 4 -3

Abstract data type--queue abstract typedef <<eltpye>> QUEUE(eltype); abstract empty(que) QUEUE(eltype) que; postcondition empty ==

Abstract data type--queue abstract typedef <<eltpye>> QUEUE(eltype); abstract empty(que) QUEUE(eltype) que; postcondition empty == (len(que) == 0); abstract eltype remove(que) QUEUE(eltype) que; precondition empty(que) == FALSE; postcondition remove == first(que’); que == sub(que’, 1, len(que’) – 1); abstract insert(que, elt) QUEUE(eltype) que; eltype elt; postcondition que == que’ + <elt>; 4 -4

Circular queue initial 4 front rear 3 empty queue 之條件: front = rear 2

Circular queue initial 4 front rear 3 empty queue 之條件: front = rear 2 1 0 que. items 4 E 3 2 que. items que. rear = 4 4 E D 3 D C 2 C que. front = 1 1 0 0 (a) que. front = 1 1 F (b) que. rear = 0 4 -5

Full circular queue que. items 4 E 3 D 2 C 1 G 0

Full circular queue que. items 4 E 3 D 2 C 1 G 0 F que. front = que. rear = 1 (c) 此時分不清是 full 或是 empty 故若有 n 個記憶容量, 則只用其中 n-1 個 4 -6

Implementation of circular queues #define MAXQUEUE 100 struct queue{ int items[MAXQUEUE]; int front, rear;

Implementation of circular queues #define MAXQUEUE 100 struct queue{ int items[MAXQUEUE]; int front, rear; }; struct queue que; // initialization que. front = que. rear = MAXQUEUE-1; 4 -7

Checking if empty int empty(struct queue *pq) { return ((pq->front == pq->rear) ? TRUE

Checking if empty int empty(struct queue *pq) { return ((pq->front == pq->rear) ? TRUE : FALSE); } /* end empty */ 4 -8

Removing the front node int remove(struct queue *pq) { if (empty(pq)){ printf(“queue underflow”); exit(1);

Removing the front node int remove(struct queue *pq) { if (empty(pq)){ printf(“queue underflow”); exit(1); } /* end if */ if (pq->front == MAXQUEUE – 1) pq->front = 0; else (pq->front)++; return (pq->items[pq->front]); } /* end remove */ 4 -9

Appending a node void insert(struct queue *pq, int x) { /* make room for

Appending a node void insert(struct queue *pq, int x) { /* make room for new element */ if (pq->rear == MAXQUEUE – 1) pq->rear = 0; else (pq->rear)++; /* check for overflow */ if (pq->rear == pq->front){ printf(“queue overflow”); exit(1); } /* end if */ pq->items[pq->rear] = x; return; } /* end insert */ 4 -10

Priority queue n n n We can insert new elements to a priority queue

Priority queue n n n We can insert new elements to a priority queue quickly. Ascending priority queue: easy to remove the smallest item Descending priority queue : easy to remove the largest item 最好使用 heap 做為 priority queue. 每個 stack 或 queue 個別使用固定的 array, 浪 費空間 多個 stack 或 queue 共用一個 array, 較節省空 間 4 -11

Linear linked list 0 1 2 D -1 3 5 6 A B C

Linear linked list 0 1 2 D -1 3 5 6 A B C 5 6 1 list = 2 2 4 7 8 information next address(pointer) 以-1代表結尾 (null pointer) header, external pointer 5 6 1 null list node ** info next 4 -12

Operation on the first node list A B C null (1) adding ‘F’ to

Operation on the first node list A B C null (1) adding ‘F’ to the front of the list F A B C null p = getnode(); info(p) = ‘F’; next(p) = list; list = p; (2) removing the first node of the list B C null ** 4 -13

Linked implementation of stacks s A (top) B C null push(s, x): similar to

Linked implementation of stacks s A (top) B C null push(s, x): similar to adding an element to the front ** 4 -14

x = pop(s): similar to removing the first node if (empty(s)) { printf(“stack underflow”);

x = pop(s): similar to removing the first node if (empty(s)) { printf(“stack underflow”); exit(1); } p = list; else{ list = next(p); p = s; x = info(p); s = next(p); freenode(p); x = info(p); freenode(p); } /* end if */ 4 -15

Available lists avail . . . null p = getnode(): freenode(p): if (avail ==

Available lists avail . . . null p = getnode(): freenode(p): if (avail == null){ rintf(“overflow”); exit(1); } p = avail; avail = next(avail); next(p) = avail; avail = p; 4 -16

Linked implementation of queues front A B C empty queue: front = rear =

Linked implementation of queues front A B C empty queue: front = rear = null D null rear x = remove(que): if (empty(que)){ printf(“queue underflow”); exit(1); } p = que. front; x = info(p); front que. front = next(p); if (que. front == null) que. rear = null; freenode(p); return(x); 4 -17

Appending a node p = getnode(); info(p) = x; next(p) = null; if (que.

Appending a node p = getnode(); info(p) = x; next(p) = null; if (que. rear == null) // 此時 front 也是 null que. front = p; else next(que. rear) = p; que. rear = p; p x rear 4 -18

The linked list as a data structure n insafter(p, x): Insert x into a

The linked list as a data structure n insafter(p, x): Insert x into a list after a node p. A B C p A C B x q ** 4 -19

n delafter(p, x): Delete the node following p and assign its contents to x.

n delafter(p, x): Delete the node following p and assign its contents to x. p A B C p A q ** 4 -20

Examples of list operations (1) n Delete all occurrences of the number 4: q

Examples of list operations (1) n Delete all occurrences of the number 4: q = null; p = list; while (p != null){ if (info(p) == 4) if (q = null){ /* remove first node of the list */ x = pop(list); p = list; } else{ /* delete the node after q and move up p */ p = next(p); delafter(q, x); } /* end if */ 4 -21

Examples of list operations (2) else{ /* continue traversing the list */ q =

Examples of list operations (2) else{ /* continue traversing the list */ q = p; p = next(p); } /* end if */ } /* end while */ 4 -22

Insertion of a sorted list 3 5 q 9 p q 8 X=8 前面較小

Insertion of a sorted list 3 5 q 9 p q 8 X=8 前面較小 後面較大 p q = null; for (p = list; p != null p = next(p)) q = p; /* at this point, a node /* x must be inserted */ if (q == null) /* insert /*head of push(list, x); else insafter(q, x); && x > info(p); containing */ x at the */ the list */ 4 -23

Header nodes (不是一般node, 而是特殊用途的 node) (1) list 2 A C null 此 list 有

Header nodes (不是一般node, 而是特殊用途的 node) (1) list 2 A C null 此 list 有 2 個 element (2) list A 746 B 841 K 321 null machine A 746 是由 parts B 841, K 321 所組成 (3) list A C null 如果 information field 可以存放 pointer, 則可以做為 queue 之 rear. 4 -24

Array implementation of lists (1) e. g. an array of nodes containing 4 linked

Array implementation of lists (1) e. g. an array of nodes containing 4 linked lists info next 0 26 -1 13 1 11 9 14 2 5 15 15 37 23 list 4 = 3 1 19 list 1 = 16 3 20 list 2 = 4 17 0 17 5 13 1 18 32 -1 19 18 5 6 7 19 18 20 7 8 8 14 12 21 15 -1 9 4 21 22 12 -1 23 10 list 3 = 11 31 7 24 12 6 2 25 4 -25

Initialization of the available list #define NUMNODES 500 struct nodetype{ int info, next; };

Initialization of the available list #define NUMNODES 500 struct nodetype{ int info, next; }; struct nodetype node[NUMNODES]; initialization of the available list: avail = 0; for (i = 0; i < NUMNODES-1; i++) node[i]. next = i+1; node[NUMNODES-1]. next = -1; 4 -26

Allocating a node from the available list int getnode(void) { int p; if (avail

Allocating a node from the available list int getnode(void) { int p; if (avail == -1){ printf("overflown"); exit(1); } p = avail; avail = node[avail]. next; return(p); } /* end getnode */ 4 -27

Returning a node to the available list void freenode(int p) { node[p]. next =

Returning a node to the available list void freenode(int p) { node[p]. next = avail; avail = p; return; } /* end freenode */ 4 -28

insafter(p, x) n Insert an item x into a list after a node p

insafter(p, x) n Insert an item x into a list after a node p void insafter(int p, int x) { int q; if (p == -1){ printf("void insertionn"); return; p } q = getnode(); node[q]. info = x; node[q]. next = node[p]. next; node[p]. next = q; return; } /* end insafter */ x q 4 -29

delafter(p, px) n Delete the node following p and store its value in x

delafter(p, px) n Delete the node following p and store its value in x (*px). void delafter(int p, int *px) { int q; if ((p == -1) || (node[p]. next == -1)){ printf("void deletionn"); return; p } q = node[p]. next; A B C *px = node[q]. info; q node[p]. next = node[q]. next; freenode(q); return; } /* end delafter */ 4 -30

Allocating and freeing dynamic variables int *p, *q; int x; p = (int *)malloc(sizeof(int));

Allocating and freeing dynamic variables int *p, *q; int x; p = (int *)malloc(sizeof(int)); *p = 3; q = p; printf("%d %d n", *p, *q); x = 7; output: x P q 3 (a) P q 7 ** 7 (b) 4 -31

*q = x; printf("%d %d n", *p, *q); p = (int *) malloc(sizeof(int)); *p

*q = x; printf("%d %d n", *p, *q); p = (int *) malloc(sizeof(int)); *p = 5; printf("%d %d n", *p, *q); output: q p q x 7 (c) 7 ** p 5 x 7 7 (d) 4 -32

p = (int *)malloc(sizeof(int)); *p = 5; q = (int *)malloc(sizeof(int)); *q = 8;

p = (int *)malloc(sizeof(int)); *p = 5; q = (int *)malloc(sizeof(int)); *q = 8; free(p); p = q; q = (int *)malloc(sizeof(int)); *q = 6; printf("%d %d n", *p, *q); output: p 5 q 8 p q (a) p q (c) ** 8 (b) 8 q 6 p 8 (d) 4 -33

e. g. p = (int *)malloc(sizeof(int)); *p = 3; p = (int *)malloc(sizeof(int)); *p

e. g. p = (int *)malloc(sizeof(int)); *p = 3; p = (int *)malloc(sizeof(int)); *p = 7; n The first copy of *p is lost since its address was not saved. 4 -34

Linked lists with dynamic variables struct node{ int info; struct node *next; }; typedef

Linked lists with dynamic variables struct node{ int info; struct node *next; }; typedef struct node *NODEPTR; NODEPTR getnode(void) { NODEPTR p; p = (NODEPTR)malloc(sizeof(struct node)); return(p); } void freenode(NODEPTR p) { free(p); } 4 -35

Memory allocation in C getnode and freenode can be simply replaced by: NODEPTR p;

Memory allocation in C getnode and freenode can be simply replaced by: NODEPTR p; p = (NODEPTR)malloc(sizeof(struct node)); and free(p); 4 -36

insafter(p, x) n Insert an item x into a list after a node p

insafter(p, x) n Insert an item x into a list after a node p void insafter(NODEPTR p, int x) { NODEPTR q; if (p == NULL){ printf("void insertionn"); exit(1); } p q = getnode(); q->info = x; q->next = p->next; x p->next = q; q } /* end insafter */ 4 -37

delafter(p, px) n Delete the node following p and store its value in x

delafter(p, px) n Delete the node following p and store its value in x (*px) void delafter(NODEPTR p, int *px) { NODEPTR q; if ((p == NULL) || (p->next == NULL)){ printf("void deletionn"); exit(1); } q = p->next; p *px = q->info; p->next = q->next; q freenode(q); } /* end delafter */ 4 -38

A queue represented as a linear list in C null front rear Array Implementation

A queue represented as a linear list in C null front rear Array Implementation Dynamic Implementation struct queue{ int front, rear; }; struct queue que; struct queue{ NODEPTR front, rear; }; struct queue que; int empty(struct queue *pq) { return((pq->front == 1) ? TRUE : FALSE); } /* end empty */ int empty(struct queue *pq) { return((pq->front == NULL) ? TRUE : FALSE); } /* end empty */ 4 -39

Appending a node empty queue : front = rear = null p insert(q, x):

Appending a node empty queue : front = rear = null p insert(q, x): x rear void insert(struct queue *pq, int x) { int p; p = getnode(); node[p]. info = x; node[p]. next = -1; if (pq->rear == -1) pq->front = p; else node[pq->rear]. next = p; pq->rear =p; } /* end insert */ 4 -40

void insert(struct queue *pq, int x) { NODEPTR p; p = getnode(); p->info =

void insert(struct queue *pq, int x) { NODEPTR p; p = getnode(); p->info = x; p->next = NULL; if (pq->rear == NULL) pq->front = p; else (pq->rear->next = p; pq->rear =p; } /* end insert */ 4 -41

Removing the front node remove(q): front int remove(struct queue *pq) { int p, x;

Removing the front node remove(q): front int remove(struct queue *pq) { int p, x; int remove(struct queue *pq) { NODEPTR p; int x; if (empty(pq)){ printf("queue underflown"); exit(1); } } p = pq->front; x = node[p]. info; x = p->info; pq->front = node[p]. next; pq->front = p->next; if (pq->front == -1) if (pq->front == NULL) pq->rear = -1; pq->rear = NULL; freenode(p); return(x); 4 -42 } /* end remove */

Insertion of a sorted list 3 q 5 9 P q 8 p void

Insertion of a sorted list 3 q 5 9 P q 8 p void place(NODEPTR *plist, int x) { NODEPTR p, q; q = NULL; for (p = *plist; p!= NULL && x > p->info; p = p->next) q = p; if (q == NULL) /* insert x at the head of the list */ push(plist, x); else insafter(q, x); } /* end place */ 4 -43

Dynamic and array implementation of lists n n n disadvantage of dynamic: need more

Dynamic and array implementation of lists n n n disadvantage of dynamic: need more time to allocate and free storage advantage of dynamic: storage is allocated when needed no data type constraint need not compute address array: 與 dynamic 相反 4 -44

Circular lists list First Node Last Node The external pointer should point to the

Circular lists list First Node Last Node The external pointer should point to the last node of a circular list. 4 -45

Representing a stack as a circular list stack A B C int empty(NODEPTR *pstack)

Representing a stack as a circular list stack A B C int empty(NODEPTR *pstack) { return((*pstack == NULL) ? TRUE : FALSE); } /* end empty */ 4 -46

Stack pushing and poping stack A B C push(S, 'D') D A B void

Stack pushing and poping stack A B C push(S, 'D') D A B void push(NODEPTR *pstack, int x) { NODEPTR p; p = getnode(); p->info = x; if (empty(pstack) == TRUE) *pstack = p; else p->next = (*pstack)->next; (*pstack)->next = p; } /* end push */ C 4 -47

stack A B pop(s) C int pop(NODEPTR *pstack){ int x; NODEPTR p; if (empty(pstack)

stack A B pop(s) C int pop(NODEPTR *pstack){ int x; NODEPTR p; if (empty(pstack) == TRUE){ printf("stack underflown"); exit(1); } /* end if */ p = (*pstack)->next; x = p->info; if (p == *pstack) /* only one node on the stack */ *pstack = NULL; else (*pstack)->next = p->next; freenode(p); return(x); } /* end pop */ stack B C 4 -48

Representing a queue as a circular list front A rear C B q remove(q):

Representing a queue as a circular list front A rear C B q remove(q): same as pop in a stack insert(q, 'D') front A B C rear D q front B rear C q 4 -49

Node insertion in the circular list void insert(NODEPTR *pq, int x) { NODEPTR p;

Node insertion in the circular list void insert(NODEPTR *pq, int x) { NODEPTR p; p = getnode(); p->info = x; if (empty(pq) == TRUE) *pq = p; else p->next = (*pq)->next; (*pq)->next = p; *pq = p; return; } insert(&q, x) is equivalent to: push(&q, x); q = q->next; 4 -50

Delafter p q . . . void delafter(NODEPTR p, int *px) { NODEPTR q;

Delafter p q . . . void delafter(NODEPTR p, int *px) { NODEPTR q; if ((p == NULL) || (p == p->next)){ /* the list is empty or contains only a single node*/ printf("void deletionn"); return; } /* end if */ q = p->next; *px = q->info; p->next = q->next; freenode(q); return; } /* end delafter */ 4 -51

Concatenate 2 circular lists list 1 A . . . B list 2 C

Concatenate 2 circular lists list 1 A . . . B list 2 C . . . D list 1 A . . . B C . . . D 4 -52

void concat(NODEPTR *plist 1, NODEPTR *plist 2) { NODEPTR p; if (*plist 2 ==

void concat(NODEPTR *plist 1, NODEPTR *plist 2) { NODEPTR p; if (*plist 2 == NULL) return; if (*plist 1 == NULL){ *plist 1 = *plist 2; return; } p = (*plist 1)->next; (*plist 1)->next = (*plist 2)->next; (*plist 2)->next = p; *plist 1 = *plist 2; return; } /* end concat */ 4 -53

Doubly linked lists null A linear doubly linked list. A circular doubly linked list

Doubly linked lists null A linear doubly linked list. A circular doubly linked list without a header. Header node A circular doubly linked list with a header. 4 -54

Implementation with C struct node{ int info; struct node *left, *right; }; typedef struct

Implementation with C struct node{ int info; struct node *left, *right; }; typedef struct node *NODEPTR; left(right(p)) = p = right(left(p)) 4 -55

Node deletion in a doubly linked circular list void delete(NODEPTR p, int *px) {

Node deletion in a doubly linked circular list void delete(NODEPTR p, int *px) { NODEPTR q, r; if (p == NULL){ printf("void deletionn"); return; } /* end if */ p *px = p->info; A B q = p->left; q r = p->right; q->right = r; r->left = q; freenode(p); return; } /* end delete */ C r 4 -56

Node insertion to the right of node p void insertright(NODEPTR p, int x) {

Node insertion to the right of node p void insertright(NODEPTR p, int x) { NODEPTR q, r; if (p == NULL){ printf("void insertionn"); return; } /* end if */ q = getnode(); q->info = x; r = p->right; B A q r->left = q; p D q->right = r; q->left = p; p->right = q; return; } /* end insertright */ C r 4 -57

Addition of long integers with doubly linked lists Header -3 49762 21978 324 The

Addition of long integers with doubly linked lists Header -3 49762 21978 324 The integer -3242197849762 有 3 個 node 且為負數 Header 2 76941 6 The integer 676941 Header 0 The integer 0 4 -58

How to add 2 long integers ? (1)決定正負號 (2)加法運算 ** 4 -59

How to add 2 long integers ? (1)決定正負號 (2)加法運算 ** 4 -59

決定正負號 (1) int compabs(NODEPTR p, NODEPTR q) { NODEPTR r, s; /* compare the

決定正負號 (1) int compabs(NODEPTR p, NODEPTR q) { NODEPTR r, s; /* compare the counts */ if (abs(p->info) > abs(q->info)) return(1); if (abs(p->info) < abs(q->info)) return(-1); /* the counts are equal */ r = p->left; s = q->left; 4 -60

決定正負號 (2) /* traverse the list from the most significant digits */ while (r

決定正負號 (2) /* traverse the list from the most significant digits */ while (r != p){ if (r->info > s->info) return(1); if (r->info < s->info) return(-1); r = r->left; s = s->left; } /* end while */ /* the absolute value are equal */ return(0); } /* end compabs */ 4 -61

加法運算 NODEPTR addiff(NODEPTR p, NODEPTR q) { int count; NODEPTR pptr, qptr, r, s,

加法運算 NODEPTR addiff(NODEPTR p, NODEPTR q) { int count; NODEPTR pptr, qptr, r, s, zeroptr; long int hunthou = 100000 L; long int borrow, diff; int zeroflag; /* initialize variables */ count = 0; borrow = 0; zeroflag = FALSE; /* generate a header node for the sum */ r = getnode(); r->left = r; r->right = r; /* traverse the two lists */ pptr = p->right; qptr = q->right; while (qptr != q){ diff = pptr->info - borrow -qptr->info; 4 -62

if (diff >= 0) borrow = 0; else{ diff = diff + hunthou; borrow

if (diff >= 0) borrow = 0; else{ diff = diff + hunthou; borrow = 1; } /* end if */ /* generate a new node and insert it */ /* to the left of header in sum */ insertleft(r, diff); count += 1; /* test for zero node */ if (diff == 0){ if (zeroflag == FALSE) zeroptr = r->left; zeroflag = TRUE; }else zeroflag = FALSE; pptr = pptr->right; qptr = qptr->right; } /* end while */ /* traverse the remainder of the p list */ while (pptr != p){ diff = pptr->info - borrow; 4 -63

if (diff >= 0) borrow = 0; else{ diff = diff + hunthou; borrow

if (diff >= 0) borrow = 0; else{ diff = diff + hunthou; borrow = 1; } /* end if */ insertleft(r, diff); count += 1; if (diff == 0){ if (zeroflag == FALSE) zeroptr = r->left; zeroflag = TRUE; }else zeroflag = FALSE; pptr = pptr->right; } /* end while */ if (zeroflag == TRUE) /* delete leading zeros */ while (zeroptr != r){ s = zeroptr; zeroptr = zeroptr->right; delete(s, &diff); count -= 1; } /* end if. . . while */ 4 -64

/* insert count and sign into the header */ if (p->info > 0) r->info

/* insert count and sign into the header */ if (p->info > 0) r->info = count; else r->info = -count; return(r); } /* end addiff */ 主程式: NODEPTR addint(NODEPTR p, NODEPTR q) { /* check if integers are of like sign */ if (p->info * q->info > 0) return(addsame(p, q)); /* check which has a larger absolute value */ if (compabs(p, q) > 0) return(addiff(p, q)); else return(addiff(q, p)); } /* end addint */ 4 -65

Linked lists in C++ class List{ protected: struct node{ int info; struct node *next;

Linked lists in C++ class List{ protected: struct node{ int info; struct node *next; } typedef struct node *NODEPTR; NODEPTR listptr; // the pointer to the first node // of the list public: List(); ~List(); int emptylist(); void push(int newvalue); void insertafter(int oldvalue, int newvalue); int pop(); void delete(int oldvalue); } 4 -66

List: : List(){ listptr = 0; } List: : ~List(){ NODEPTR p, q; if

List: : List(){ listptr = 0; } List: : ~List(){ NODEPTR p, q; if (emptylist()) return 0; for (p=listptr, q=p->next; p!=0; p=q, q=p->next) delete p; } int List: : emptylist(){ return(listptr == 0); } List: : push(int newvalue){ NODEPTR p; p = new node; p->info = newvalue; p->next = listptr; listptr = p; } 4 -67

List: : insertafter(int oldvalue, int newvalue){ NODEPTR p, q; for (p=listptr; p!=0 && p->info!=oldvalue;

List: : insertafter(int oldvalue, int newvalue){ NODEPTR p, q; for (p=listptr; p!=0 && p->info!=oldvalue; p=p->next) ; if (p == 0); error(“ERROR: value sought is not on the list. ”); q = new node; q->info = newvalue; q->next = p->next; p->next = q; } int List: : pop(){ NODEPTR p; int x; if (emptylist()) error(“ERROR: the list is empty. ”); p = listptr; listptr = p->next; x = p->info; delete p; return x; 4 -68 }

List: : delete(int oldvalue){ NODEPTR p, q; for (q=0, p=listptr; p!=0 && p->info!=oldvalue; q=p,

List: : delete(int oldvalue){ NODEPTR p, q; for (q=0, p=listptr; p!=0 && p->info!=oldvalue; q=p, p=p->next) ; if (p == 0) error(“ERROR: value sought is not on the list. ”); if (q == 0) listptr = p->next; else q->next = p->next; delete p; } 4 -69