Lists, Stacks and Queues. 2 struct Node{ double data; Node* next; }; class List { public: List(); //...

Post on 20-Dec-2015

251 views 2 download

Transcript of Lists, Stacks and Queues. 2 struct Node{ double data; Node* next; }; class List { public: List(); //...

Lists, Stacks and Queues

2

struct Node{ double data;Node* next;

};

class List {public:

List(); // constructorList(const List& list); // copy constructor~List(); // destructorList& operator=(const List& list); // assignment operator// plus other overloaded operators

bool empty() const; // boolean functionvoid add(double x); // add to the headvoid delete(); // delete the head and get the head elementdouble head() const; // get the head element

bool search(double x); // search for a given xvoid insert(double x); // insert x in a sorted listvoid delete(double x); // delete x in a sorted list

void addEnd(double x); // add to the endvoid deleteEnd(); // delete the end and get the end elementdouble end(); // get the element at the endvoid display() const; // outputint length() const; // count the number of elements

private:Node* head;

};

More complete list ADT

3

class List {public:

List(); // constructorList(const List& list); // copy constructor~List(); // destructor

bool empty() const; // boolean functiondouble head() const; // get the head elementvoid add(double x); // add to the headvoid delete(); // delete the head element

void display() const; // output

private:…

};

list ADT (a general list)

Or to define one function:

Double delete();

Which deletes and returns the head element.

4

class List {public:

List(); // constructorList(const List& list); // copy constructor~List(); // destructor

bool empty() const; // boolean functiondouble head(); const; // get the first elementvoid insert(double x); // insert x in a sorted listvoid delete(double x); // delete x in a sorted list

void display() const; // outputbool search(double x); // search for a given x

private:…

};

list ADT (a sorted list)

5

Implementation Static array Dynamic array Linked lists

with and without ‘dummy head’ tricks

Efficiency Insertion construction, composition Deletion destruction, decomposition Search application, usage

Implementation and Efficiency

6

Roughly ‘counting’ the number of operations, assuming all basis operations are of the same, unit one.

Efficiency: Algorithm Analysis

7

A Few Simple Rules Loops

at most the running time of the statements inside the for-loop (including tests) times the number of iterations.

O(N)

Nested loops

the running time of the statement multiplied by the product of the sizes of all the for-loops.

O(N2)

8

Consecutive statements These just add O(N) + O(N2) = O(N2)

Conditional: If S1 else S2 never more than the running time of the test plus the larger of

the running times of S1 and S2. O(1)

9

Our first example: search of an ordered array

Linear search and binary search Upper bound, lower bound and tight bound

10

O(N)

// Given an array of ‘size’ in increasing order, find ‘x’

int linearsearch(int* a[], int size,int x) {

int low=0, high=size-1;

for (int i=0; i<size;i++)

if (a[i]==x) return i;

return -1;

}

Linear search:

11

int bsearch(int* a[],int size,int x) {

int low=0, high=size-1;

while (low<=higt) {

int mid=(low+high)/2;

if (a[mid]<x)

low=mid+1;

else if (x<a[mid])

high=mid-1;

else return mid;

}

return -1

}

Iterative binary search:

12

int bsearch(int* a[],int size,int x) {

int low=0, high=size-1;

while (low<=higt) {

int mid=(low+high)/2;

if (a[mid]<x)

low=mid+1;

else if (x<a[mid])

high=mid-1;

else return mid;

}

return -1

}

Iterative binary search:

n=high-low n_i+1 <= n_i / 2 i.e. n_i <= (N-1)/2^{i-1} N stops at 1 or below there are at most 1+k iterations, where k is the smallest such that (N-1)/2^{k-1} <= 1 so k is at most 2+log(N-1) O(log N)

13

O(1)

T(N/2)

int bsearch(int* a[],int low, int high, int x) {

if (low>high) return -1;

else int mid=(low+high)/2;

if (x=a[mid]) return mid;

else if(a[mid]<x)

bsearch(a,mid+1,high,x);

else bsearch(a,low,mid-1);

}

O(1)

Recursive binary search:

1)2

()(

1)1(

N

TNT

T

14

With 2k = N (or asymptotically), k=log N, we have

Thus, the running time is O(log N)

NkNT log)(

kN

T

NT

NT

NTNT

k

)2

(

3)8

(

2)4

(

1)2

()(

Solving the recurrence:

15

Advantages and disadvantages of different implementations of a list

Static array

Dynamic array

Linked list

Insertion

Deletion

Search

16

Applications: Linked Implementation of Sparse Polynomials

Consider a polynomial of degree n Can be represented by a list

For a sparse polynomial this is not efficient

COMP152 16

myDegree 5

0 1 2 3 4 5 6 7 8 9

myCoeffs 5 7 0 -8 0 4 0 0 0 0

myDegree 99

0 1 2 3 4 5 6 7 8 9 … 95 96 97 98 99

myCoeffs 5 0 0 0 0 0 0 0 0 0 … 0 0 0 0 1

17

We could represent a polynomial by a list of ordered pairs{ (coef, exponent) … }

Fixed capacity of array still problematic Wasted space for sparse polynomial

COMP152 17

myDegree 5

0 1 2 3

myTerms 5 0 7 1 -8 3 4 5

myDegree 99

0 1

myTerms 5 0 1 99

18

Linked list of these ordered pairs provides an appropriate solution Now whether sparse or well populated, the polynomial is represented

efficiently Polynomial class (Polynomial.h)

Type parameter CoefType Term and Node are inner private classes for internal use and access only Used to create internal data structure of a linked node (for internal access only)

COMP152 18

0 0myTerms

5 0 7 1 -8 3 4 5

/

5myDegreedata

next

dummy/header/ sentinel

19

Stacks

20

Stack Overview

Stack ADT Basic operations of stack

Pushing, popping etc.

Implementations of stacks using array linked list

21

Stack

A stack is a list in which insertion and deletion take place at the same end This end is called top The other end is called bottom

Stacks are known as LIFO (Last In, First Out) lists. The last element inserted will be the first to be retrieved

22

Push and Pop

Primary operations: Push and Pop Push

Add an element to the top of the stack

Pop Remove the element at the top of the stack

top

empty stack

Atop

push an element

top

push another

A

Btop

pop

A

23

Implementation of Stacks

Any list implementation could be used to implement a stack Arrays (static: the size of stack is given initially) Linked lists (dynamic: never become full)

We will explore implementations based on arrays and linked list

24

class Stack {public:

Stack(); // constructorStack(const Stack& stack); // copy constructor~Stack(); // destructor

bool empty() const; double top() const; // keep the stack unchanged

void push(const double x); double pop(); // change the stack

// optionalvoid display() const; bool full() const;

private:…

};

Stack ADT

update,

‘logical’ constructor/destructor, composition/decomposition

‘physical’ constructor/destructor

Compare with List, see that it’s ‘operations’ that define the type!

‘stack’ is the same as our ‘unsorted’ list operating at the head

inspection, access

headElementaddHeaddeleteHead

25

Using Stack

int main() {Stack stack;stack.push(5.0);stack.push(6.5);stack.push(-3.0);stack.push(-8.0);stack.display();cout << "Top: " << stack.top() << endl;

stack.pop();cout << "Top: " << stack.top() << endl;while (!stack.empty()) stack.pop();stack.display();return 0;

}

result

26

struct Node{ public:

double data;Node* next;

};

class Stack {public:

Stack(); // constructorStack(const Stack& stack); // copy constructor~Stack(); // destructor

bool empty() const; double top() const; // keep the stack unchanged

void push(const double x); double pop(); // change the stack

bool full(); // unnecessary for linked lists void display() const;

private:Node* top;

};

Stack using linked lists

27

void List::addHead(int newdata){

Nodeptr newPtr = new Node;

newPtr->data = newdata;

newPtr->next = head;

head = newPtr;

}

void Stack::push(double x){

Node* newPtr = new Node;

newPtr->data = x;

newPtr->next = top;

top = newPtr;

}

From ‘addHead’ to ‘push’

Push (addHead), Pop (deleteHead)

28

Stack using arraysclass Stack {public:

Stack(int size = 10);Stack(const Stack& stack); ~Stack() { delete[] values; }

bool empty() { return (top == -1); }

double top();void push(const double x);double pop();

bool full() { return (top == size); }void display();

private:int size; // max stack size = size - 1int top; // current top of stackdouble* values; // element array

};

29

Attributes of Stack size: the max size of stack top: the index of the top element of stack values: point to an array which stores elements of stack

Operations of Stack empty: return true if stack is empty, return false otherwise full: return true if stack is full, return false otherwise top: return the element at the top of stack push: add an element to the top of stack pop: delete the element at the top of stack display: print all the data in the stack

30

Allocate a stack array of size. By default, size = 10.

Initially top is set to -1. It means the stack is empty. When the stack is full, top will have its maximum value, i.e.

size – 1.

Stack::Stack(int size /*= 10*/) {values = new double[size];top = -1;

maxTop = size - 1;}

Although the constructor dynamically allocates the stack array, the stack is still static. The size is fixed after the initialization.

Stack constructor

31

void push(const double x); Push an element onto the stack Note top always represents the index of the top

element. After pushing an element, increment top.

void Stack::push(const double x) {if (full()) // if stack is full, print error

cout << "Error: the stack is full." << endl;else

values[++top] = x;}

32

double pop() Pop and return the element at the top of the stack Don’t forgot to decrement top

double Stack::pop() {if (empty()) { //if stack is empty, print error

cout << "Error: the stack is empty." << endl;return -1;

}else {

return values[top--];}

}

33

double top() Return the top element of the stack Unlike pop, this function does not remove the top

element

double Stack::top() {if (empty()) {

cout << "Error: the stack is empty." << endl;return -1;

}else

return values[top];}

34

void print() Print all the elements

void Stack::print() {cout << "top -->";for (int i = top; i >= 0; i--)

cout << "\t|\t" << values[i] << "\t|" << endl;cout << "\t|---------------|" << endl;

}

35

A better variant:

COMP152 35

A better approach is to let position 0 be the bottom of the stack An integer to indicate the top of the stack (Stack.h)

[7] ?

[6] ?

[5] 77

[4] 121

[3] 64

[2] 234

[1] 51

[0] 64

[7] ?

[6] 95

[5] 77

[4] 121

[3] 64

[2] 234

[1] 51

[0] 29

[7] 80

[6] 95

[5] 77

[4] 121

[3] 64

[2] 234

[1] 51

[0] 29

[7] ?

[6] 95

[5] 77

[4] 121

[3] 64

[2] 234

[1] 51

[0] 29

Push 95 Push 80 Pop

top =

top =

top =

top =

36

Stack Application: base conversion

COMP152 36

Consider a program to do base conversion of a number (ten to two) 26 = (11010)2

It assumes existence of a Stack class to accomplish this Demonstrates push, pop, and top Push the remainder onto a stack and pop it

up one by one

Stack.h, Stack.cpp andBaseConversion.cpp

Can be written easily using recursion (do it yourself)

2 26

2 13 … 0

2 6 … 1

2 3 … 0

2 1 … 1

0 … 1

37

COMP152 37

Stack stack();

while (D is not zero) {

push the remainder of D

D D/2

}

while (not empty stack)

pop

38

COMP152 38

convert(D)

if D is zero, stop

else push(the remainder)

convert(D/2)

while (not empty stack)

pop

39

Stack Application: Balancing Symbols

To check that every right brace, bracket, and parentheses must correspond to its left counterpart e.g. [( )] is legal, but [( ] ) is illegal

How? Need to memorize Use a counter, several counters, each for a type of

parenthesis …

40

Balancing Symbols using a stack

Algorithm(1)   Make an empty stack.(2)   Read characters until end of file

i.    If the character is an opening symbol, push it onto the stackii.   If it is a closing symbol, then if the stack is empty, report an erroriii.  Otherwise, pop the stack. If the symbol popped is not the corresponding opening symbol, then report an error

(3)   At end of file, if the stack is not empty, report an error

(paren.cpp)

41

Stack Application: postfix, infix expressions and

calculator Evaluating Postfix expressions

a b c * + d e * f + g * + Operands are in a stack

Converting infix to postfix a+b*c+(d*e+f)*g a b c * + d e * f + g * + Operators are in a stack

Calculator Adding more operators …

42

Infix, prefix, and postfix

COMP152 42

Consider the arithmetic statement in the assignment statement:x = a * b + c

This is "infix" notation: the operators are between the operands

Compiler must generate machine instructions

1. LOAD a

2. MULT b

3. ADD c

4. STORE x

43

Examples

COMP152 43

Infix RPN (Postfix) Prefix

A + B A B + + A B

A * B + C A B * C + + * A B C

A * (B + C) A B C + * * A + B C

A - (B - (C - D)) A B C D--- -A-B-C D

A - B - C - D A B-C-D- ---A B C D

Prefix : Operators come before the

operands

44

RPN or Postfix Notation

COMP152 44

Reverse Polish Notation (RPN) = Postfix notation Most compilers convert an expression in infix notation to

postfix The operators are written after the operands

So “a * b + c” becomes “a b * c +” Easier for compiler to work on loading and operation of variables

Advantage: expressions can be written without parentheses

45

Evaluating RPN Expressions (Similar to Compiler Operations)

COMP152 45

Example:

2 3 4 + 5 6 - - * 2 3 4 + 5 6 - - * 2 7 5 6 - - * 2 7 5 6 - - * 2 7 -1 - * 2 7 -1 - * 2 8 * 2 8 * 16

46

COMP152 46

while (not the end of the expression) do {

get the current ‘token’

if it is operand, store it … a stack

if it is operator,

get back operands

Evaluate

store the result

move to the next

}

Use a Stack to store ‘operands’ a stack!

An expression is a list of ‘characters’ or more generally ‘tokens’ or ‘strings

47

COMP152 47

while (not the end of the expression) {

get the current ‘token’

if it is operand,

push;

else if it is operator,

pop;

pop;

evaluate;

push;

move to the next

}

48

COMP152 48

list expression

stack empty

while (notempty(list)) do {

c = head(list);

if (c == ‘operand’) push(c,stack)

else if (c == ‘operator)

operand2 = pop(stack);

operand1 = pop(stack);

res=evaluate(c,operand1,operand2);

push(res,stack);

list delete(list)

}

Further refine:

- operators: +, -, *, /

- operands: …

- evaluate: …

49

COMP152 49

List list(expression);

Stack stack();

while (list.notempty) do {

c = list.head();

if (c == ‘operand’) stack.push(c)

else if (c == ‘operator)

operand2 = stack.pop;

operand1 = stack.pop;

res=evaluate(c,operand1,operand2);

stack.push;

list.delete();

}

Further refine:

- operators: +, -, *, /

- operands: …

- evaluate: …

More object-oriented:

50

COMP152 50

2 4 * 9 5 + -

4 * 9 5 + -

* 9 5 + -

5 + -

+ -

(end of strings)

-

8

42

2

598

98

9 5 + -

148

-6

-6

Push 2 onto the stack

Value of expression is on top of the stack

Push 4 onto the stack

Pop 4 and 2 from the stack , multiply, and push the result 8 back

Push 9 onto the stack

Push 5 onto the stack

Pop 5 and 9 from the stack, add, and push the result 14 back

Pop 14 and 8 from the stack, subtract, and push the result -6 back

51

RPN Conversion

COMP152 51

1. Given a fully parenthesized infix expression

2. Replace each right parenthesis by the corresponding operator

3. Erase all left parentheses

A * (B + C)

(A (B C + * A B C + *

(A * (B + C) )A * B + C

((A B * C + A B * C +

((A * B) + C)

52

COMP152 52

while (not end of expression)

c = the current ‘token’if c is ‘operator’

store it somewhere … (a stack!)

else if c is ‘operand’,

display it (or store them in a new expression),

A stack for operators, not operands!

53

COMP152 53

while (not end of expression) {c = the current ‘token’

If c is ‘(‘

else if c is ‘)’

else if c is ‘operator’

push

else if c is ‘operand’,

pop

}

while (not end of the stack) {

pop

}

54

COMP152 54

while (not end of expression)c = the current ‘token’

If c is ‘(’push

else if c is ‘)’

while (the top is not ‘(‘ )

pop and display

else if c is ‘operator’,

while (the top has higher priority than c,

and is not ‘(‘ )

pop and display

push

else if c is ‘operand’

pop and display

while (notempty stack)

pop an display

postfix.cpp

55

Stack Application: function calls and recursion

Take the example of factorial! And run it.

#include <iostream>using namespace std;

int fac(int n){int product;if(n <= 1) product = 1;else product = n * fac(n-1);return product;

}

void main(){int number;cout << "Enter a positive integer : " << endl;;cin >> number;cout << fac(number) << endl;

}

56

Take the example of factorial! And run it.

#include <iostream>using namespace std;

int fac(int n){int product;if(n <= 1) product = 1;else product = n * fac(n-1);return product;

}

void main(){int number;cout << "Enter a positive integer : " << endl;;cin >> number;cout << fac(number) << endl;

}

57

Assume the number typed is 3. fac(3): has the final returned value 6

3<=1 ? No.

product3 = 3*fac(2) product3=3*2=6, return 6,

fac(2):2<=1 ? No.

product2 = 2*fac(1) product2=2*1=2, return 2,

fac(1):1<=1 ? Yes.return 1

Tracing the program …

58

fac(3) prod3=3*fac(2)

prod2=2*fac(1)fac(2)

fac(1) prod1=1

Call is to ‘push’ and return is to ‘pop’!

top

59

COMP152 59

Stack stack();

while (D is not zero) {

push the remainder of D

D D/2

}

while (not empty stack)

pop

Let the system do the ‘stack’ for you!

convert(D)

if D is zero, stop

else push(the remainder)

convert(D/2)

while (not empty stack)

pop and display

convert(D)

if D is zero, stop

else convert(D/2)

display the remainder of D

60

Static and dynamic objects

‘static variables’ are from a Stack ‘dynamic variables’ are from a heap (seen

later …)

61

Array versus linked list implementations

push, pop, top are all constant-time operations in both array and linked list implementation For array implementation, the operations are

performed in very fast constant time

62

Queues

COMP152 62

A queue is a waiting line – seen in daily life A line of people waiting for a bank teller A line of cars at a toll both "This is the captain, we're 5th in line for takeoff"

63

Queue Overview

Queue ADT Basic operations of queue

Enqueuing, dequeuing etc.

Implementation of queue Linked list Array

64

Queue

A queue is also a list. However, insertion is done at one end, while deletion is performed at the other end.

It is “First In, First Out (FIFO)” order. Like customers standing in a check-out line in a

store, the first customer in is the first customer served.

65

Enqueue and Dequeue

Primary queue operations: Enqueue and Dequeue Like check-out lines in a store, a queue has a front

and a rear. Enqueue – insert an element at the rear of the

queue Dequeue – remove an element from the front of

the queue

Insert (Enqueue)

Remove(Dequeue) rearfront

66

Implementation of Queue

Just as stacks can be implemented as arrays or linked lists, so with queues.

Dynamic queues have the same advantages over static queues as dynamic stacks have over static stacks

67

class Queue {public:

Queue();Queue(const Queue& queue);~Queue();

bool empty();double front(); // optional: front inspection (no queue change)void enqueue(double x);double dequeue();

// optionalvoid display(void);bool full();

private:…

};

Queue ADT

‘physical’ constructor/destructor

‘logical’ constructor/destructor

68

Using Queueint main(void) {

Queue queue;cout << "Enqueue 5 items." << endl;for (int x = 0; x < 5; x++)

queue.enqueue(x);cout << "Now attempting to enqueue again..." << endl;queue.enqueue(5);queue.print();double value;value=queue.dequeue();cout << "Retrieved element = " << value << endl;queue.print();queue.enqueue(7);queue.print();return 0;

}

69

Struct Node {double data;Node* next;

}

class Queue {public:

Queue();Queue(const Queue& queue);~Queue();

bool empty();void enqueue(double x);double dequeue();

// bool full(); // optionalvoid print(void);

private:Node* front; // pointer to front nodeNode* rear; // pointer to last nodeint counter; // number of elements

};

Queue using linked lists

70

class Queue {public:

Queue() { // constructorfront = rear = NULL;counter = 0;

}~Queue() { // destructor

double value;while (!empty()) dequeue(value);

}bool empty() {

if (counter) return false;else return true;

}void enqueue(double x);double dequeue();

// bool full() {return false;};void print(void);

private:Node* front; // pointer to front nodeNode* rear; // pointer to last nodeint counter; // number of elements, not compulsary

};

Implementation of some online member functions …

71

Enqueue (addEnd)void Queue::enqueue(double x) {

Node* newNode = new Node;newNode->data = x;newNode->next = NULL;

if (empty()) {front = newNode;

}else {

rear->next = newNode;}

rear = newNode;counter++;

}

8

rear

rear

newNode

5

58

72

Dequeue (deleteHead)double Queue::dequeue() {

double x;if (empty()) {

cout << "Error: the queue is empty." << endl;exit(1); // return false;

}else {

x = front->data;Node* nextNode = front->next;delete front;front = nextNode;counter--;

}return x;

}

front

583

8 5

front

73

Printing all the elements

void Queue::print() {cout << "front -->";Node* currNode = front;for (int i = 0; i < counter; i++) {

if (i == 0) cout << "\t";else cout << "\t\t"; cout << currNode->data;if (i != counter - 1)

cout << endl;else

cout << "\t<-- rear" << endl;currNode = currNode->next;

}}

74

Queue using Arrays There are several different algorithms to

implement Enqueue and Dequeue Naïve way

When enqueuing, the front index is always fixed and the rear index moves forward in the array.

front

rear

Enqueue(3)

3

front

rear

Enqueue(6)

3 6

front

rear

Enqueue(9)

3 6 9

75

Naïve way (cont’d) When dequeuing, the front index is fixed, and the

element at the front the queue is removed. Move all the elements after it by one position. (Inefficient!!!)

Dequeue()

front

rear

6 9

Dequeue() Dequeue()

front

rear

9

rear = -1

front

76

A better way When enqueued, the rear index moves forward. When dequeued, the front index also moves forward

by one element

XXXXOOOOO (rear) OXXXXOOOO (after 1 dequeue, and 1 enqueue)OOXXXXXOO (after another dequeue, and 2 enqueues)OOOOXXXXX (after 2 more dequeues, and 2 enqueues)

(front)

The problem here is that the rear index cannot move beyond the last element in the array.

77

Using Circular Arrays

Using a circular array When an element moves past the end of a circular

array, it wraps around to the beginning, e.g. OOOOO7963 4OOOO7963 (after Enqueue(4))

How to detect an empty or full queue, using a circular array algorithm? Use a counter of the number of elements in the queue.

78

class Queue {public:

Queue(int size = 10); // constructorQueue(const Queue& queue); // not necessary!

~Queue() { delete[] values; } // destructor

bool empty(void);void enqueue(double x); // or bool enqueue();double dequeue();

bool full();void print(void);

private:int front; // front indexint rear; // rear indexint counter; // number of elementsint maxSize; // size of array queuedouble* values; // element array

};

full() is not essential, can be embedded

79

Attributes of Queue front/rear: front/rear index counter: number of elements in the queue maxSize: capacity of the queue values: point to an array which stores elements of the queue

Operations of Queue empty: return true if queue is empty, return false otherwise full: return true if queue is full, return false otherwise enqueue: add an element to the rear of queue dequeue: delete the element at the front of queue print: print all the data

80

Queue constructor

Queue(int size = 10) Allocate a queue array of size. By default, size = 10. front is set to 0, pointing to the first element of the

array rear is set to -1. The queue is empty initially.

Queue::Queue(int size /* = 10 */) {values = new double[size];maxSize = size;front = 0;rear = -1;counter = 0;

}

81

Empty & Full Since we keep track of the number of elements

that are actually in the queue: counter, it is easy to check if the queue is empty or full.

bool Queue::empty() {if (counter==0) return true;else return false;

}bool Queue::full() {

if (counter < maxSize) return false;else return true;

}

82

Enqueue

void Queue::enqueue(double x) {if (full()) {

cout << "Error: the queue is full." << endl;exit(1); // return false;

}else {

// calculate the new rear position (circular)rear = (rear + 1) % maxSize; // insert new itemvalues[rear] = x;// update countercounter++;// return true;

}}

Or ‘bool’ if you want

83

Dequeue

double Queue::dequeue() {double x;if (empty()) {

cout << "Error: the queue is empty." << endl;exit(1); // return false;

}else {

// retrieve the front itemx = values[front];// move front front = (front + 1) % maxSize;// update countercounter--;// return true;

}return x;

}

84

Printing the elements

void Queue::print() {cout << "front -->";for (int i = 0; i < counter; i++) {

if (i == 0) cout << "\t";else cout << "\t\t"; cout << values[(front + i) % maxSize];if (i != counter - 1)

cout << endl;else

cout << "\t<-- rear" << endl;}

}

85

Using Queueint main(void) {

Queue queue;cout << "Enqueue 5 items." << endl;for (int x = 0; x < 5; x++)

queue.enqueue(x);cout << "Now attempting to enqueue again..." << endl;queue.enqueue(5);queue.print();double value;value=queue.dequeue();cout << "Retrieved element = " << value << endl;queue.print();queue.enqueue(7);queue.print();return 0;

}

86

Results

Queue implemented using linked list will be never full!

based on array based on linked list

87

Queue applications

When jobs are sent to a printer, in order of arrival, a queue.

Customers at ticket counters …

88

Queue application: Counting Sort

Assume N integers are to be sorted, each is in the range 1 to M. Define an array B[1..M], initialize all to 0 O(M) Scan through the input list A[i], insert A[i] into B[A[i]] O(N) Scan B once, read out the nonzero integers O(M)

Total time: O(M + N) if M is O(N), then total time is O(N) Can be bad if range is very big, e.g. M=O(N2)

N=7, M = 9,

Want to sort 8 1 9 5 2 6 3

1 2 5 8 9

Output: 1 2 3 5 6 8 9

3 6

89

What if we have duplicates? B is an array of pointers. Each position in the array has 2 pointers: head

and tail. Tail points to the end of a linked list, and head points to the beginning.

A[j] is inserted at the end of the list B[A[j]] Again, Array B is sequentially traversed and

each nonempty list is printed out. Time: O(M + N)

90

M = 9,

Wish to sort 8 5 1 5 9 5 6 2 7

1 2 5 6 7 8 9

Output: 1 2 5 5 5 6 7 8 9

5

5

91

Queue Application: Bin (or Bucket) Sort (generalization of

counting sort) The nodes are placed into bins, each bin contains nodes with the

same score Then we combine the bins to create a sorted chain Note that it does not change the relative order of nodes that have

the same score, the so-called stable sort.

COMP152 91

92

Number of Steps in binsort

m integers, r array size

Sort m integers For example, sort m=1,000 integers in the range of 0 to r=106

We use binsort with range r: Initialization of array takes r steps; putting items into the array takes m steps; and reading out from the array takes another m+r steps The total sort complexity is then (2m + 2r) , which can be much

larger than m if r is large

COMP152 92

93

Queue application: Radix Sort

Extra information: every integer can be represented by at most k digits d1d2…dk where di are digits in base r

d1: most significant digit

dk: least significant digit

94

Radix Sort

Algorithm sort by the least significant digit first (counting sort)

=> Numbers with the same digit go to same bin reorder all the numbers: the numbers in bin 0

precede the numbers in bin 1, which precede the numbers in bin 2, and so on

sort by the next least significant digit continue this process until the numbers have been

sorted on all k digits

95

Radix Sort

Least-significant-digit-first

Example: 275, 087, 426, 061, 509, 170, 677, 503

170 061 503 275 426 087 677 509

96

170 061 503 275 426 087 677 509

503 509 426 061 170 275 677 087

061 087 170 275 426 503 509 677

97

Radix Sort Does it work?

Clearly, if the most significant digit of a and b are different and a < b, then finally a comes before b

If the most significant digit of a and b are the same, and the second most significant digit of b is less than that of a, then b comes before a.

98

Radix(A[],n,d)

// an array of queues as bins

Queue Q[9]();

k=0;

D=1;

while (k <= d)

get k-th digit t of A[i]

enqueue(A[i],Q[t])

k=k+1;

// out put Q

p=0;

j=0;

While (p<=9)

While (not empty Q[j])

A[j]=dequeue(Q(p));

j=j+1;

p=p+1;

99

COMP152 99

Finding digit Di From Key We want to find the ith digit in our key A

A = DdDd-1.. Di…D2D1

mod and div are integer operators

Let D = 10i

Then Di = (A mod D) div (D/10)

Get Digit

Example. A=30487 we want D3

i =3, D = 1000A mod 1000 = 487 (first)487 div (D/10) (second)487 div (100) = 4 result!

100

// base 10

// d times of counting sort

// re-order back to original array

// scan A[i], put into correct slot

// FIFO

A=input array, n=|numbers to be sorted|,

d=# of digits, k=the digit being sorted, j=array index

101

Radix Sort

Increasing the base r decreases the number of passes Running time

k passes over the numbers (i.e. k counting sorts, with range being 0..r)

each pass takes 2N total: O(2Nk)=O(Nk) r and k are constants: O(N)

Note: radix sort is not based on comparisons; the values are used as

array indices If all N input values are distinct, then k = (log N) (e.g., in

binary digits, to represent 8 different numbers, we need at least 3 digits). Thus the running time of Radix Sort also become (N log N).

102

Radix Sort

Example 2: sorting cards 2 digits for each card: d1d2

d1 = : base 4

d2 = A, 2, 3, ...J, Q, K: base 13 A 2 3 ... J Q K

2 2 5 K