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
Top Related