Predicting Employee Churn: A Data-Driven Approach Project Presentation
introduction_dst.pptx
1. AL 1
Data Structures
By
Dr Salman Naseer Adil
Department of IT
University of the Punjab
Gujranwala Campus
2. AL 2
Data Structures
Prepares the students for (and is a
prerequisite for) the more advanced
material students will encounter in later
courses.
Cover well-known data structures such as
dynamic arrays, linked lists, stacks,
queues, tree and graphs.
Implement data structures in C++
3. AL 3
Need for Data Structures
Data structures organize data more
efficient programs.
More powerful computers more
complex applications.
More complex applications demand more
calculations.
4. AL 4
Organizing Data
Any organization for a collection of records
that can be searched, processed in any
order, or modified.
The choice of data structure and algorithm
can make the difference between a
program running in a few seconds or many
days.
5. AL 5
Efficiency
A solution is said to be efficient if it solves
the problem within its resource constraints.
– Space
– Time
The cost of a solution is the amount of
resources that the solution consumes.
6. AL 6
Selecting a Data Structure
Select a data structure as follows:
1. Analyze the problem to determine the
resource constraints a solution must
meet.
2. Determine the basic operations that must
be supported. Quantify the resource
constraints for each operation.
3. Select the data structure that best meets
these requirements.
7. AL 7
Some Questions to Ask
• Are all data inserted into the data structure
at the beginning, or are insertions
interspersed with other operations?
• Can data be deleted?
• Are all data processed in some well-
defined order, or is random access
allowed?
8. AL 8
Data Structure Philosophy
Each data structure has costs and
benefits.
Rarely is one data structure better than
another in all situations.
A data structure requires:
– space for each data item it stores,
– time to perform each basic operation,
– programming effort.
9. AL 9
Goals of this Course
1. Reinforce the concept that costs and benefits
exist for every data structure.
2. Learn the commonly used data structures.
– These form a programmer's basic data structure
“toolkit”.
3. Understand how to measure the cost of a data
structure or program.
– These techniques also allow you to judge the merits
of new data structures that you or others might
invent.
10. AL 10
Arrays
Elementary data structure that exists as built-in
in most programming languages.
main( int argc, char** argv )
{
int x[6];
int j;
for(j=0; j < 6; j++)
x[j] = 2*j;
}
11. AL 11
Arrays
Array declaration: int x[6];
An array is collection of cells of the same type.
The collection has the name ‘x’.
The cells are numbered with consecutive
integers.
To access a cell, use the array name and an
index:
x[0], x[1], x[2], x[3], x[4], x[5]
13. AL 13
What is Array Name?
‘x’ is an array name but there is no variable x. ‘x’ is not an lvalue.
For example, if we have the code
int a, b;
then we can write
b = 2;
a = b;
a = 5;
But we cannot write
2 = a;
14. AL 14
Array Name
‘x’ is not an lvalue
int x[6];
int n;
x[0] = 5;
x[1] = 2;
x = 3; // not allowed
x = a + b; // not allowed
x = &n; // not allowed
15. AL 15
Dynamic Arrays
You would like to use an array data structure
but you do not know the size of the array at
compile time.
You find out when the program executes that
you need an integer array of size n=20.
Allocate an array using the new operator:
int* y = new int[20]; // or int* y = new int[n]
y[0] = 10;
y[1] = 15; // use is the same
16. AL 16
Dynamic Arrays
‘y’ is a lvalue; it is a pointer that holds the
address of 20 consecutive cells in memory.
It can be assigned a value. The new operator
returns as address that is stored in y.
We can write:
y = &x[0];
y = x; // x can appear on the right
// y gets the address of the
// first cell of the x array
17. AL 17
Dynamic Arrays
We must free the memory we got using the
new operator once we are done with the y
array.
delete[ ] y;
We would not do this to the x array because we
did not use new to create it.
18. AL 18
The LIST Data Structure
The List is among the most generic of data
structures.
Real life:
a. shopping list,
b. groceries list,
c. list of people to invite to dinner
d. List of presents to get
19. AL 19
Lists
A list is collection of items that are all of the
same type (grocery items, integers, names)
The items, or elements of the list, are stored in
some particular order
It is possible to insert new elements into
various positions in the list and remove any
element of the list
20. AL 20
Lists
List is a set of elements in a linear order.
For example, data values a1, a2, a3, a4 can be
arranged in a list:
(a3, a1, a2, a4)
In this list, a3, is the first element, a1 is the
second element, and so on
The order is important here; this is not just a
random collection of elements, it is an ordered
collection
21. AL 21
List Operations
Useful operations
• createList(): create a new list (presumably empty)
• copy(): set one list to be a copy of another
• clear(); clear a list (remove all elments)
• insert(X, ?): Insert element X at a particular position
in the list
• remove(?): Remove element at some position in
the list
• get(?): Get element at a given position
• update(X, ?): replace the element at a given position
with X
• find(X): determine if the element X is in the list
• length(): return the length of the list.
22. AL 22
List Operations
We need to decide what is meant by “particular
position”; we have used “?” for this.
There are two possibilities:
1. Use the actual index of element: insert after element
3, get element number 6. This approach is taken by
arrays
2. Use a “current” marker or pointer to refer to a
particular position in the list.
23. AL 23
List Operations
If we use the “current” marker, the following
four methods would be useful:
start(): moves to “current” pointer to the very first
element.
tail(): moves to “current” pointer to the very last
element.
next(): move the current position forward one
element
back(): move the current position backward one
element
24. AL 24
Implementing Lists
We have designed the interface for the List; we
now must consider how to implement that
interface.
Implementing Lists using an array: for example,
the list of integers (2, 6, 8, 7, 1) could be
represented as:
A 6 8 7 1
1 2 3 4 5
2
current
3
size
5
25. AL 25
List Implementation
add(9); current position is 3. The new list would thus
be: (2, 6, 8, 9, 7, 1)
We will need to shift everything to the right of 8 one
place to the right to make place for the new element ‘9’.
current
3
size
5
step 1: A 6 8 7 1
1 2 3 4 5
2
6
current
4
size
6
step 2: A 6 8 7 1
1 2 3 4 5
2
6
9
notice: current points
to new element
26. AL 26
Implementing Lists
next():
current
4
size
6
A 6 8 7 1
1 2 3 4 5
2
6
9
5
There are special cases for positioning the
current pointer:
a. past the last array cell
b. before the first cell
We will have to worry about these when we
write the actual code.
27. AL 27
Implementing Lists
remove(): removes the element at the current
index
We fill the blank spot left by the removal of 7 by
shifting the values to the right of position 5 over
to the left one space.
current
5
size
5
A 6 8 1
1 2 3 4 5
2 9
Step 2:
current
5
size
6
A 6 8 1
1 2 3 4 5
2
6
9
5
Step 1:
28. AL 28
Implementing Lists
find(X): traverse the array until X is located.
int find(int X)
{
int j;
for(j=1; j < size+1; j++ )
if( A[j] == X ) break;
if( j < size+1 ) { // found X
current = j; // current points to where X found
return 1; // 1 for true
}
return 0; // 0 (false) indicates not found
}
29. AL 29
Implementing Lists
Other operations:
get() return A[current];
update(X) A[current] = X;
length() return size;
back() current--;
start() current = 1;
end() current = size;
30. AL 30
Analysis of Array Lists
add
we have to move every element to the right of
current to make space for the new element.
Worst-case is when we insert at the beginning; we
have to move every element right one place.
Average-case: on average we may have to move
half of the elements
31. AL 31
Analysis of Array Lists
remove
Worst-case: remove at the beginning, must shift all
remaining elements to the left.
Average-case: expect to move half of the elements.
find
Worst-case: may have to search the entire array
Average-case: search at most half the array.
Other operations are one-step.
32. List Using Linked Memory
Various cells of memory are not allocated
consecutively in memory.
32
33. List Using Linked Memory
Various cells of memory are not allocated
consecutively in memory.
Not enough to store the elements of the list.
33
34. List Using Linked Memory
Various cells of memory are not allocated
consecutively in memory.
Not enough to store the elements of the list.
With arrays, the second element was right next
to the first element.
34
35. List Using Linked Memory
Various cells of memory are not allocated
consecutively in memory.
Not enough to store the elements of the list.
With arrays, the second element was right next
to the first element.
Now the first element must explicitly tell us
where to look for the second element.
35
36. List Using Linked Memory
Various cells of memory are not allocated
consecutively in memory.
Not enough to store the elements of the list.
With arrays, the second element was right next
to the first element.
Now the first element must explicitly tell us
where to look for the second element.
Do this by holding the memory address of the
second element
36
37. Linked List
Create a structure called a Node.
object next
The object field will hold the actual list element.
The next field in the structure will hold the
starting location of the next node.
Chain the nodes together to form a linked list.
37
38. Linked List
Picture of our list (2, 6, 7, 8, 1) stored as a
linked list:
2 6 8 7 1
head
current
size=5
38
39. Linked List
Note some features of the list:
Need a head to point to the first node of the list.
Otherwise we won’t know where the start of the
list is.
39
40. Linked List
Note some features of the list:
Need a head to point to the first node of the list.
Otherwise we won’t know where the start of the
list is.
The current here is a pointer, not an index.
40
41. Linked List
Note some features of the list:
Need a head to point to the first node of the list.
Otherwise we won’t know where the start of the
list is.
The current here is a pointer, not an index.
The next field in the last node points to nothing.
We will place the memory address NULL which
is guaranteed to be inaccessible.
41
42. Linked List
Actual picture in memory:
1051
1052
1055
1059
1060
1061
1062
1063
1064
1056
1057
1058
1053
1054 2
6
8
7
1
1051
1063
1057
1060
0
head 1054
1063
current
2 6 8 7 1
head
current
1065
42
43. Linked List
Actual picture in memory:
1051
1052
1055
1059
1060
1061
1062
1063
1064
1056
1057
1058
1053
1054 2
6
8
7
1
1051
1063
1057
1060
0
head 1054
1063
current
2 6 8 7 1
head
current
1065
43
44. Linked List Operations
add(9): Create a new node in memory to hold ‘9’
Node* newNode = new Node(9); 9
newNod
e
44
45. Linked List Operations
add(9): Create a new node in memory to hold ‘9’
Node* newNode = new Node(9);
Link the new node into the list
9
newNod
e
2 6 8 7 1
head
current
size=5 6
9
newNod
e
1
3
2
45
46. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
46
47. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
47
48. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
48
49. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
49
50. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
50
51. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
51
52. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
52
53. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
53
54. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
54
55. C++ Code for Linked List
The Node class
class Node {
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node *getNext() { return nextNode; };
void setNext(Node *nextNode)
{ this->nextNode = nextNode; };
private:
int object;
Node *nextNode;
};
55
56. #include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
56
57. #include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
57
58.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
58
59.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
59
60.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
60
61.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
61
62.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
62
63.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
63
64.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
64
65.
#include <stdlib.h>
#include "Node.cpp"
class List {
public:
// Constructor
List() {
headNode = new Node();
headNode->setNext(NULL);
currentNode = NULL;
size = 0;
};
C++ Code for Linked List
65
83. Building a Linked List
headNode
2
headNode
currentNode
size=1
lastcurrentNode
size=0
List list;
list.add(2);
83
84. Building a Linked List
headNode
2
headNode
currentNode
size=1
lastcurrentNode
2 6
headNode
currentNode
size=2
lastcurrentNode
size=0
List list;
list.add(2);
list.add(6);
84
85. Building a Linked List
List.add(8); list.add(7); list.add(1);
2 6 7 1
headNode
currentNode
size=5
lastcurrentNode
8
85
86. C++ Code for Linked List
int get() {
if (currentNode != NULL)
return currentNode->get();
};
86
87. C++ Code for Linked List
bool next() {
if (currentNode == NULL) return false;
lastCurrentNode = currentNode;
currentNode = currentNode->getNext();
if (currentNode == NULL || size == 0)
return false;
else
return true;
};
87
88. C++ Code for Linked List
// position current before the first
// list element
void start() {
lastCurrentNode = headNode;
currentNode = headNode;
};
88
90. C++ Code for Linked List
int length()
{
return size;
};
private:
int size;
Node *headNode;
Node *currentNode, *lastCurrentNode;
90
91. Example of List Usage
#include <iostream>
#include <stdlib.h>
#include "List.cpp"
int main(int argc, char *argv[])
{
List list;
list.add(5); list.add(13); list.add(4);
list.add(8); list.add(24); list.add(48);
list.add(12);
list.start();
while (list.next())
cout << "List Element: "<< list.get()<<endl;
}
91
92. Analysis of Linked List
add
• we simply insert the new node after the current
node. So add is a one-step operation.
remove
remove is also a one-step operation
find
worst-case: may have to search the entire list
back
moving the current pointer back one node requires
traversing the list from the start until the node whose
next pointer points to current node.
92
93. Doubly-linked List
Moving forward in a singly-linked list is easy;
moving backwards is not so easy.
To move back one node, we have to start at the
head of the singly-linked list and move forward
until the node before the current.
To avoid this we can use two pointers in a
node: one to point to next node and another to
point to the previous node:
element next
prev
93
95. Doubly-linked List
Need to be more careful when adding or
removing a node.
Consider add: the order in which pointers are
reorganized is important:
size=5
2 6 8 7 1
head
current
95
96. Doubly-linked List
1. newNode->setNext( current->getNext() );
2. newNode->setprev( current );
3. (current->getNext())->setPrev(newNode);
4. current->setNext( newNode );
size=5
2 6 8 7
head
current
1
9
newNode 1
2 3
4
96
97. Doubly-linked List
1. newNode->setNext( current->getNext() );
2. newNode->setprev( current );
3. (current->getNext())->setPrev(newNode);
4. current->setNext( newNode );
5. current = newNode;
6. size++;
size=6
2 6 8 7
head
current
1
9
newNode 1
2 3
4
97
98. Circularly-linked lists
The next field in the last node in a singly-linked
list is set to NULL.
Moving along a singly-linked list has to be done
in a watchful manner.
Doubly-linked lists have two NULL pointers:
prev in the first node and next in the last node.
A way around this potential hazard is to link the
last node with the first node in the list to create
a circularly-linked list.
98
99. Cicularly Linked List
Two views of a circularly linked list:
2 6 8 7 1
head
current
size=5
2
8
7
1
head
current
size=5
6
99
100. Josephus Problem
A case where circularly linked list comes in
handy is the solution of the Josephus Problem.
Consider there are 10 persons. They would like
to choose a leader.
The way they decide is that all 10 sit in a circle.
They start a count with person 1 and go in
clockwise direction and skip 3. Person 4
reached is eliminated.
The count starts with the fifth and the next
person to go is the fourth in count.
Eventually, a single person remains.
100
102.
Josephus Problem
#include "CList.cpp"
void main(int argc, char *argv[])
{
CList list;
int i, N=10, M=3;
for(i=1; i <= N; i++ ) list.add(i);
list.start();
while( list.length() > 1 ) {
for(i=1; i <= M; i++ ) list.next();
cout << "remove: " << list.get() << endl;
list.remove();
}
cout << "leader is: " << list.get() << endl;
}
102
103. Abstract Data Type
We have looked at four different
implementations of the List data structures:
Using arrays
Singly linked list
Doubly linked list
Circularly linked list.
103
104. Abstract Data Type
We have looked at four different
implementations of the List data structures:
Using arrays
Singly linked list
Doubly linked list
Circularly linked list.
The interface to the List stayed the same, i.e.,
add(), get(), next(), start(), remove() etc.
104
105. Abstract Data Type
We have looked at four different
implementations of the List data structures:
Using arrays
Singly linked list
Doubly linked list
Circularly linked list.
The interface to the List stayed the same, i.e.,
add(), get(), next(), start(), remove() etc.
The list is thus an abstract data type; we use it
without being concerned with how it is
implemented.
105
106. Abstract Data Type
What we care about is the methods that are
available for use with the List ADT.
106
107. Abstract Data Type
What we care about is the methods that are
available for use with the List ADT.
We will follow this theme when we develop
other ADT.
107
108. Abstract Data Type
What we care about is the methods that are
available for use with the List ADT.
We will follow this theme when we develop
other ADT.
We will publish the interface and keep the
freedom to change the implementation of ADT
without effecting users of the ADT.
108
109. Abstract Data Type
What we care about is the methods that are
available for use with the List ADT.
We will follow this theme when we develop
other ADT.
We will publish the interface and keep the
freedom to change the implementation of ADT
without effecting users of the ADT.
The C++ classes provide us the ability to create
such ADTs.
109
110. Stacks
• Stacks in real life: stack of books, stack of
plates
• Add new items at the top
• Remove an item at the top
• Stack data structure similar to real life:
collection of elements arranged in a linear
order.
• Can only access element at the top
110
111. Stack Operations
• Push(X) – insert X as the top element of
the stack
• Pop() – remove the top element of the
stack and return it.
• Top() – return the top element without
removing it from the stack.
111
113. Stack Operation
• The last element to go into the stack is the
first to come out: LIFO – Last In First Out.
• What happens if we call pop() and there is
no element?
• Have IsEmpty() boolean function that
returns true if stack is empty, false
otherwise.
• Throw StackEmpty exception: advanced
C++ concept.
113
114. Stack Implementation: Array
• Worst case for insertion and deletion from
an array when insert and delete from the
beginning: shift elements to the left.
• Best case for insert and delete is at the
end of the array – no need to shift any
elements.
• Implement push() and pop() by inserting
and deleting at the end of an array.
114
115. Stack using an Array
top
2
5
7
1
2 5 7 1
0 1 3
2 4
top = 3
115
116. Stack using an Array
• In case of an array, it is possible that the
array may “fill-up” if we push enough
elements.
• Have a boolean function IsFull() which
returns true is stack (array) is full, false
otherwise.
• We would call this function before calling
push(x).
116
117. Stack Operations with Array
int pop()
{
return A[current--];
}
void push(int x)
{
A[++current] = x;
}
117
118. Stack Operations with Array
int top()
{
return A[current];
}
int IsEmpty()
{
return ( current == -1 );
}
int IsFull()
{
return ( current == size-1);
}
• A quick examination shows that all five
operations take constant time.
118
119. Stack Using Linked List
• We can avoid the size limitation of a stack
implemented with an array by using a
linked list to hold the stack elements.
• As with array, however, we need to decide
where to insert elements in the list and
where to delete them so that push and pop
will run the fastest.
119
120. Stack Using Linked List
• We can avoid the size limitation of a stack
implemented with an array by using a
linked list to hold the stack elements.
• As with array, however, we need to decide
where to insert elements in the list and
where to delete them so that push and pop
will run the fastest.
120
121. Stack Using Linked List
• For a singly-linked list, insert at start or end
takes constant time using the head and current
pointers respectively.
• Removing an element at the start is constant
time but removal at the end required traversing
the list to the node one before the last.
• Make sense to place stack elements at the start
of the list because insert and removal are
constant time.
121
122. Stack Using Linked List
• No need for the current pointer; head is enough.
top
2
5
7
1
1 7 5 2
head
122
123. Stack Operation: List
int pop()
{
int x = head->get();
Node* p = head;
head = head->getNext();
delete p;
return x;
}
top
2
5
7
1 7 5 2
head
123
124. Stack Operation: List
void push(int x)
{
Node* newNode = new Node();
newNode->set(x);
newNode->setNext(head);
head = newNode;
}
top
2
5
7
9
7 5 2
head
push(9)
9
newNode
124
125. Stack Operation: List
int top()
{
return head->get();
}
int IsEmpty()
{
return ( head == NULL );
}
• All four operations take constant time.
125
126. Stack: Array or List
• Since both implementations support stack
operations in constant time, any reason to
choose one over the other?
• Allocating and deallocating memory for list
nodes does take more time than preallocated
array.
• List uses only as much memory as required by
the nodes; array requires allocation ahead of
time.
• List pointers (head, next) require extra memory.
• Array has an upper limit; List is limited by
dynamic memory allocation.
126
127. Use of Stack
• Example of use: prefix, infix, postfix
expressions.
• Consider the expression A+B: we think of
applying the operator “+” to the operands
A and B.
• “+” is termed a binary operator: it takes
two operands.
• Writing the sum as A+B is called the infix
form of the expression.
127
128. Prefix, Infix, Postfix
• Two other ways of writing the expression
are
+ A B prefix
A B + postfix
• The prefixes “pre” and “post” refer to the
position of the operator with respect to the
two operands.
128
129. Prefix, Infix, Postfix
• Consider the infix expression
A + B * C
• We “know” that multiplication is done
before addition.
• The expression is interpreted as
A + ( B * C )
• Multiplication has precedence over
addition.
129
131. Prefix, Infix, Postfix
• Conversion to postfix
A + ( B * C ) infix form
A + ( B C * ) convert multiplication
131
132. Prefix, Infix, Postfix
• Conversion to postfix
A + ( B * C ) infix form
A + ( B C * ) convert multiplication
A ( B C * ) + convert addition
132
133. Prefix, Infix, Postfix
• Conversion to postfix
A + ( B * C ) infix form
A + ( B C * ) convert multiplication
A ( B C * ) + convert addition
A B C * + postfix form
133
135. Prefix, Infix, Postfix
• Conversion to postfix
(A + B ) * C infix form
( A B + ) * C convert addition
135
136. Prefix, Infix, Postfix
• Conversion to postfix
(A + B ) * C infix form
( A B + ) * C convert addition
( A B + ) C * convert multiplication
136
137. Prefix, Infix, Postfix
• Conversion to postfix
(A + B ) * C infix form
( A B + ) * C convert addition
( A B + ) C * convert multiplication
A B + C * postfix form
137
138. Precedence of Operators
• The five binary operators are: addition,
subtraction, multiplication, division and
exponentiation.
• The order of precedence is (highest to
lowest)
• Exponentiation
• Multiplication/division *, /
• Addition/subtraction +, -
138
139. Precedence of Operators
• For operators of same precedence, the
left-to-right rule applies:
A+B+C means (A+B)+C.
• For exponentiation, the right-to-left rule
applies
A B C means A ( B C )
139
140. Infix to Postfix
Infix Postfix
A + B A B +
12 + 60 – 23 12 60 + 23 –
(A + B)*(C – D ) A B + C D – *
A B * C – D + E/F A B C*D – E F/+
140
141. Infix to Postfix
Infix Postfix
A + B A B +
12 + 60 – 23 12 60 + 23 –
(A + B)*(C – D ) A B + C D – *
A B * C – D + E/F A B C*D – E F/+
141
142. Infix to Postfix
• Note that the postfix form an expression
does not require parenthesis.
• Consider ‘4+3*5’ and ‘(4+3)*5’. The
parenthesis are not needed in the first but
they are necessary in the second.
• The postfix forms are:
4+3*5 435*+
(4+3)*5 43+5*
142
143. Evaluating Postfix
• Each operator in a postfix expression
refers to the previous two operands.
• Each time we read an operand, we push it
on a stack.
• When we reach an operator, we pop the
two operands from the top of the stack,
apply the operator and push the result
back on the stack.
143
144. Evaluating Postfix
Stack s;
while( not end of input ) {
e = get next element of input
if( e is an operand )
s.push( e );
else {
op2 = s.pop();
op1 = s.pop();
value = result of applying operator ‘e’ to op1 and op2;
s.push( value );
}
}
finalresult = s.pop();
144
161. Converting Infix to Postfix
• Consider the infix expressions ‘A+B*C’
and ‘ (A+B)*C’.
• The postfix versions are ‘ABC*+’ and
‘AB+C*’.
• The order of operands in postfix is the
same as the infix.
• In scanning from left to right, the operand
‘A’ can be inserted into postfix expression.
161
162. Converting Infix to Postfix
• The ‘+’ cannot be inserted until its second
operand has been scanned and inserted.
• The ‘+’ has to be stored away until its
proper position is found.
• When ‘B’ is seen, it is immediately inserted
into the postfix expression.
• Can the ‘+’ be inserted now? In the case of
‘A+B*C’ cannot because * has
precedence.
162
163. Converting Infix to Postfix
• In case of ‘(A+B)*C’, the closing
parenthesis indicates that ‘+’ must be
performed first.
• Assume the existence of a function
‘prcd(op1,op2)’ where op1 and op2 are
two operators.
• Prcd(op1,op2) returns TRUE if op1 has
precedence over op2, FASLE otherwise.
163
164. Converting Infix to Postfix
• prcd(‘*’,’+’) is TRUE
• prcd(‘+’,’+’) is TRUE
• prcd(‘+’,’*’) is FALSE
• Here is the algorithm that converts infix
expression to its postfix form.
• The infix expression is without
parenthesis.
164
165. Converting Infix to Postfix
1. Stack s;
2. While( not end of input ) {
3. c = next input character;
4. if( c is an operand )
5. add c to postfix string;
6. else {
7. while( !s.empty() && prcd(s.top(),c) ){
8. op = s.pop();
9. add op to the postfix string;
10. }
11. s.push( c );
12. }
13. while( !s.empty() ) {
14. op = s.pop();
15. add op to postfix string;
16. }
165
166. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
166
167. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
+ A +
167
168. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
+ A +
B AB +
168
169. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
+ A +
B AB +
* AB + *
169
170. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
+ A +
B AB +
* AB + *
C ABC + *
170
171. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
+ A +
B AB +
* AB + *
C ABC + *
ABC * +
171
172. Converting Infix to Postfix
• Example: A + B * C
symb postfix stack
A A
+ A +
B AB +
* AB + *
C ABC + *
ABC * +
ABC * +
172
173. Converting Infix to Postfix
• Handling parenthesis
• When an open parenthesis ‘(‘ is read, it
must be pushed on the stack.
• This can be done by setting prcd(op,‘(‘ ) to
be FALSE.
• Also, prcd( ‘(‘,op ) == FALSE which
ensures that an operator after ‘(‘ is pushed
on the stack.
173
174. Converting Infix to Postfix
• When a ‘)’ is read, all operators up to the
first ‘(‘ must be popped and placed in the
postfix string.
• To do this, prcd( op,’)’ ) == TRUE.
• Both the ‘(‘ and the ‘)’ must be discarded:
prcd( ‘(‘,’)’ ) == FALSE.
• Need to change line 11 of the algorithm.
174
175. Converting Infix to Postfix
if( s.empty() || symb != ‘)’ )
s.push( c );
else
s.pop(); // discard the ‘(‘
prcd( ‘(‘, op ) = FALSE for any operator
prcd( op, ‘)’ ) = FALSE for any operator
other than ‘)’
prcd( op, ‘)’ ) = TRUE for any operator
other than ‘(‘
prcd( ‘)’, op ) = error for any operator.
175
176. Converting Infix to Postfix
• Example: (A + B) * C
symb postfix stack
( (
A A (
+ A ( +
B AB ( +
) AB +
* AB + *
C AB + C *
AB + C *
176
177. C++ Templates
• We need a stack of operands and a stack
of operators.
• Operands can be integers and floating
point numbers, even variables.
• Operators are single characters.
• We would have to create classes
FloatStack and CharStack.
• Yet the internal workings of both classes is
the same.
177
178. C++ Templates
• We can use C++ Templates to create a
“template” of a stack class.
• Instantiate float stack, char stack, or stack
for any type of element we want.
178
179. Stack using templates
Stack.h:
template <class T>
class Stack {
public:
Stack();
int empty(void); // 1=true, 0=false
int push(T &); // 1=successful,0=stack overflow
T pop(void);
T peek(void);
~Stack();
private:
int top;
T* nodes;
};
179
180. Stack using templates
Stack.cpp
#include <iostream.h>
#include <stdlib.h>
#include "Stack.cpp"
#define MAXSTACKSIZE 50
template <class T>
Stack<T>::Stack()
{
top = -1;
nodes = new T[MAXSTACKSIZE];
}
180
181. Stack using templates
Stack.cpp
template <class T>
Stack<T>::~Stack()
{
delete nodes;
}
template <class T>
int Stack<T>::empty(void)
{
if( top < 0 ) return 1;
return 0;
}
181
182. Stack using templates
Stack.cpp
template <class T>
int Stack<T>::push(T& x)
{
if( top < MAXSTACKSIZE ) {
nodes[++top] = x;
return 1;
}
cout << "stack overflow in push.n";
return 0;
}
182
183. Stack using templates
Stack.cpp
template <class T>
T Stack<T>::pop(void)
{
T x;
if( !empty() ) {
x = nodes[top--];
return x;
}
cout << "stack underflow in pop.n";
return x;
}
183
185. Memory Organization
• When a program
(.exe) is run, it is
loaded in memory. It
becomes a process.
• The process is given
a block of memory.
• [Control-Alt-DEL]
Process 1
(browser)
Process 3
(word)
Process 4
(excel)
Windows OS
Process 2
(dev-c++)
185
188. Memory Organization
• When a program
(.exe) is run, it is
loaded in memory. It
becomes a process.
• The process is given
a block of memory.
• [Control-Alt-DEL]
Process 1
(browser)
Process 3
(word)
Process 4
(excel)
Windows OS
Process 2
(dev-c++)
188
192. Stack Layout during a call
Here is stack layout when function F calls
function G:
Parameters(F)
Local variables(F)
Return address(F)
Parameters(G)
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Local variables(F)
Return address(F)
Parameters(G)
Local variables(G)
Return address(G)
During execution of G After call
At point of call
sp
sp
sp
192
193. Queues
A stack is LIFO (Last-In First Out)
structure.
In contrast, a queue is a FIFO (First-In
First-Out ) structure.
A queue is a linear structure for which
items can be only inserted at one end and
removed at another end.
193
194. Queue Operations
Enqueue(X) – place X at the rear of the
queue.
Dequeue() -- remove the front element and
return it.
Front() -- return front element without
removing it.
IsEmpty() -- return TRUE if queue is
empty, FALSE otherwise
194
195. Implementing Queue
Using linked List: Recall
Insert works in constant time for either end
of a linked list.
Remove works in constant time only.
Seems best that head of the linked list be
the front of the queue so that all removes
will be from the front.
Inserts will be at the end of the list.
195
201. Queue using Array
If we use an array to hold queue elements,
both insertions and removal at the front
(start) of the array are expensive.
This is because we may have to shift up to
“n” elements.
For the stack, we needed only one end; for
queue we need both.
To get around this, we will not shift upon
removal of an element.
201
208. Queue using Array
We have inserts and removal running in
constant time but we created a new
problem.
Cannot insert new elements even though
there are two places available at the start
of the array.
Solution: allow the queue to “wrap
around”.
208
209. Queue using Array
Basic idea is to picture the array as a
circular array.
front
2
5
rear
2
front
7
rear
6 8 9 12
6
5
7
0 1
3
2
4
5
2
6
8
9
12
209
212. Queue using Array
int dequeue()
{
int x = array[front];
front = (front+1)%size;
noElements = noElements-1;
return x;
}
front rear
4
front
1
rear
6 8 9 12
6
5
7
0 1
3
2
4
6
8
9
12
dequeue()
21
21
8
size
6
noElements
7
7
212
213. Use of Queues
Out of the numerous uses of the queues,
one of the most useful is simulation.
A simulation program attempts to model a
real-world phenomenon.
Many popular video games are
simulations, e.g., SimCity, FlightSimulator
Each object and action in the simulation
has a counterpart in real world.
213
214. Uses of Queues
If the simulation is accurate, the result of
the program should mirror the results of
the real-world event.
Thus it is possible to understand what
occurs in the real-world without actually
observing its occurrence.
Let us look at an example. Suppose there
is a bank with four tellers.
214
215. Simulation of a Bank
A customer enters the bank at a specific
time (t1) desiring to conduct a transaction.
Any one of the four tellers can attend to
the customer.
The transaction (withdraw, deposit) will
take a certain period of time (t2).
If a teller is free, the teller can process the
customer’s transaction immediately and
the customer leaves the bank at t1+t2.
215
216. Simulation of a Bank
A customer enters the bank at a specific
time (t1) desiring to conduct a transaction.
Any one of the four tellers can attend to
the customer.
The transaction (withdraw, deposit) will
take a certain period of time (t2).
If a teller is free, the teller can process the
customer’s transaction immediately and
the customer leaves the bank at t1+t2.
216
217. Simulation of a Bank
It is possible that none of the four tellers is
free in which case there is a line of
customers are each teller.
An arriving customer proceeds to the back
of the shortest line and waits for his turn.
The customer leaves the bank at t2 time
units after reaching the front of the line.
The time spent at the bank is t2 plus time
waiting in line.
217
218. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
218
219. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
219
220. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
220
221. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
221
222. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
222
223. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
223
224. Simulation of a Bank
teller 2
teller 1 teller 3 teller 4
224
225. Simulation Models
Two common models of simulation are
time-based simulation and event-based
simulation.
In time-based simulation, we maintain a
timeline or a clock.
The clock ticks. Things happen when the
time reaches the moment of an event.
225
226. Timeline based Simulation
Consider the bank example. All tellers are free.
Customer C1 comes in at time 2 minutes after
bank opens.
His transaction (withdraw money) will require 4
minutes.
Customer C2 arrives 4 minutes after the bank
opens. Will need 6 minutes for transaction.
Customer C3 arrives 12 minutes after the bank
opens and needs 10 minutes.
226
227. Timeline based Simulation
Events along the timeline:
1
0 11
10
8
7
6
5
4
3
2 15
14
13
12
C2 in
C1 in C1 out
C2 out
C3 in
Time (minutes)
227
228. Timeline based Simulation
We could write a main clock loop as follows:
clock = 0;
while( clock <= 24*60 ) { // one day
read new customer;
if customer.arrivaltime == clock
insert into shortest queue;
check the customer at head of all four queues.
if transaction is over, remove from queue.
clock = clock + 1;
}
228
229. Event based Simulation
Don’t wait for the clock to tic until the next
event.
Compute the time of next event and
maintain a list of events in increasing order
of time.
Remove a event from the list in a loop and
process it.
229
230. Event based Simulation
Events
1
0 11
10
8
7
6
5
4
3
2 15
14
13
12
C2 in
C1 in C1 out
C2 out
C3 in
Time (minutes)
Event 1: 2 mins C1 in
Event 2: 4 mins C2 in
Event 3: 6 mins C1 out
Event 4: 10 mins C2 out
Event 5: 12 mins C3 in
230
231. Event based Simulation
Maintain a queue of events.
Remove the event with the earliest time
from the queue and process it.
As new events are created, insert them in
the queue.
A queue where the dequeue operation
depends not on FIFO, is called a priority
queue.
231
232. Event based Bank Simulation
Development of the C++ code to carry out
the simulation.
We will need the queue data structure.
We will need the priority queue.
Information about arriving customers will
be placed in an input file.
Each line of the file contains the items
(arrival time,transaction duration)
232
233. Arriving Customers’ File
Here are a few lines from the input file.
00 30 10 <- customer 1
00 35 05 <- customer 2
00 40 08
00 45 02
00 50 05
00 55 12
01 00 13
01 01 09
“00 30 10” means Customer 1 arrives 30 minutes after bank opens
and will need 10 minutes for his transaction.
“01 01 09” means customer arrives one hour and one minute after
bank opens and transaction will take 9 minutes.
233
234. Simulation Procedure
The first event to occur is the arrival of the
first customer.
This event placed in the priority queue.
Initially, the four teller queues are empty.
The simulation proceeds are follows:
When an arrival event is removed from the
priority queue, a node representing the
customer is placed on the shortest teller
queue.
234
235. Simulation Procedure
If that customer is the only one on a teller
queue, a event for his departure is placed
on the priority queue.
At the same time, the next input line is
read and an arrival event is placed in the
priority queue.
When a departure event is removed from
the event priority queue, the customer
node is removed from the teller queue.
235
236. Simulation Procedure
The total time spent by the customer is
computed: it is the time spent in the queue
waiting and the time taken for the transaction.
This time is added to the total time spent by all
customers.
At the end of the simulation, this total time
divided by the total customers served will be
average time spent by customers.
The next customer in the queue is now served
by the teller.
A departure event is placed on the event queue.
236
237. Code for Simulation
#include <iostream>
#include <string>
#include <strstream.h>
#include "Customer.cpp"
#include "Queue.h"
#include "PriorityQueue.cpp"
#include "Event.cpp"
Queue q[4]; // teller queues
PriorityQueue pq; //eventList;
int totalTime;
int count = 0;
int customerNo = 0;
237
238. Code for Simulation
main (int argc, char *argv[])
{
Customer* c;
Event* nextEvent;
// open customer arrival file
ifstream data("customer.dat", ios::in);
// initialize with the first arriving
// customer.
readNewCustomer(data);
238
239. Code for Simulation
while( pq.length() > 0 )
{
nextEvent = pq.remove();
c = nextEvent->getCustomer();
if( c->getStatus() == -1 ){ // arrival event
int arrTime = nextEvent->getEventTime();
int duration = c->getTransactionDuration();
int customerNo = c->getCustomerNumber();
processArrival(data, customerNo,
arrTime, duration , nextEvent);
}
else { // departure event
int qindex = c->getStatus();
int departTime = nextEvent->getEventTime();
processDeparture(qindex, departTime, nextEvent);
}
}
239
240. Code for Simulation
void readNewCustomer(ifstream& data)
{
int hour,min,duration;
if (data >> hour >> min >> duration) {
customerNo++;
Customer* c = new Customer(customerNo,
hour*60+min, duration);
c->setStatus( -1 ); // new arrival
Event* e = new Event(c, hour*60+min );
pq.insert( e ); // insert the arrival event
}
else {
data.close(); // close customer file
}
}
240
241. Code for Simulation
int processArrival(ifstream &data, int customerNo,
int arrTime, int duration,
Event* event)
{
int i, small, j = 0;
// find smallest teller queue
small = q[0].length();
for(i=1; i < 4; i++ )
if( q[i].length() < small ){
small = q[i].length(); j = i;
}
// put arriving customer in smallest queue
Customer* c = new Customer(customerNo, arrTime,
duration );
c->setStatus(j); // remember which queue the customer goes in
q[j].enqueue(c);
241
242. Code for Simulation
// check if this is the only customer in the.
// queue. If so, the customer must be marked for
// departure by placing him on the event queue.
if( q[j].length() == 1 ) {
c->setDepartureTime( arrTime+duration);
Event* e = new Event(c, arrTime+duration );
pq.insert(e);
}
// get another customer from the input
readNewCustomer(data);
}
242
243. Code for Simulation
int processDeparture( int qindex, int departTime,
Event* event)
{
Customer* cinq = q[qindex].dequeue();
int waitTime = departTime - cinq->getArrivalTime();
totalTime = totalTime + waitTime;
count = count + 1;
// if there are any more customers on the queue, mark the
// next customer at the head of the queue for departure
// and place him on the eventList.
if( q[qindex].length() > 0 ) {
cinq = q[qindex].front();
int etime = departTime + cinq->getTransactionDuration();
Event* e = new Event( cinq, etime);
pq.insert( e );
}
}
243
248. Priority Queue
int insert(Event* e)
{
if( !full() ) {
rear = rear+1;
nodes[rear] = e;
size = size + 1;
sortElements(); // in ascending order
return 1;
}
cout << "insert queue is full." << endl;
return 0;
};
int length() { return size; };
};
248
249. Tree Data Structures
• There are a number of applications where
linear data structures are not appropriate.
• Consider a genealogy tree of a family.
Mohammad Aslam Khan
Sohail Aslam Javed Aslam Yasmeen Aslam
Saad
Haaris Qasim Asim Fahd Ahmad Sara Omer
249
250. Tree Data Structure
• A linear linked list will not be able to
capture the tree-like relationship with
ease.
• Shortly, we will see that for applications
that require searching, linear data
structures are not suitable.
• We will focus our attention on binary trees.
250
251. Binary Tree
• A binary tree is a finite set of elements that is
either empty or is partitioned into three disjoint
subsets.
• The first subset contains a single element called
the root of the tree.
• The other two subsets are themselves binary
trees called the left and right subtrees.
• Each element of a binary tree is called a node of
the tree.
251
263. Binary Tree
• If every non-leaf node in a binary tree has non-empty left and right
subtrees, the tree is termed a strictly binary tree.
A
B
D
H
C
E F
G I
J
K
263
264. Level of a Binary Tree Node
• The level of a node in a binary tree is
defined as follows:
Root has level 0,
Level of any other node is one more than the
level its parent (father).
• The depth of a binary tree is the maximum
level of any leaf in the tree.
264
265. Level of a Binary Tree Node
A
B
D
H
C
E F
G I
1
0
1
2 2 2
3 3 3
Level 0
Level 1
Level 2
Level 3
265
266. Complete Binary Tree
• A complete binary tree of depth d is the strictly
binary all of whose leaves are at level d.
A
B
N
C
G
O
1
0
1
2
3 3
L
F
M
2
3 3
H
D
I
2
3 J
E
K
2
3
266
267. Complete Binary Tree
A
B
Level 0: 20 nodes
H
D
I
E
J K
C
L
F
M
G
N O
Level 1: 21 nodes
Level 2: 22 nodes
Level 3: 23 nodes
267
268. Complete Binary Tree
• At level k, there are 2k nodes.
• Total number of nodes in the tree of depth
d:
20+ 21+ 22 + ………. + 2d = 2j = 2d+1 – 1
• In a complete binary tree, there are 2d leaf
nodes and (2d - 1) non-leaf (inner) nodes.
j=0
d
268
269. Complete Binary Tree
• If the tree is built out of ‘n’ nodes then
n = 2d+1 – 1
or log2(n+1) = d+1
or d = log2(n+1) – 1
• I.e., the depth of the complete binary tree built
using ‘n’ nodes will be log2(n+1) – 1.
• For example, for n=100,000, log2(100001) is
less than 20; the tree would be 20 levels deep.
• The significance of this shallowness will become
evident later.
269
270. Operations on Binary Tree
• There are a number of operations that can
be defined for a binary tree.
• If p is pointing to a node in an existing tree
then
left(p) returns pointer to the left subtree
right(p) returns pointer to right subtree
parent(p) returns the father of p
brother(p) returns brother of p.
info(p) returns content of the node.
270
271. Operations on Binary Tree
• There are a number of operations that can
be defined for a binary tree.
• If p is pointing to a node in an existing tree
then
left(p) returns pointer to the left subtree
right(p) returns pointer to right subtree
parent(p) returns the father of p
brother(p) returns brother of p.
info(p) returns content of the node.
271
272. Operations on Binary Tree
• In order to construct a binary tree, the
following can be useful:
• setLeft(p,x) creates the left child node of p.
The child node contains the info ‘x’.
• setRight(p,x) creates the right child node
of p. The child node contains the info ‘x’.
272
273. Applications of Binary Trees
• A binary tree is a useful data structure
when two-way decisions must be made at
each point in a process.
• For example, suppose we wanted to find
all duplicates in a list of numbers:
14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5
273
274. Applications of Binary Trees
• One way of finding duplicates is to
compare each number with all those that
precede it.
14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5
14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5
274
275. Searching for Duplicates
• If the list of numbers is large and is
growing, this procedure involves a large
number of comparisons.
• A linked list could handle the growth but
the comparisons would still be large.
• The number of comparisons can be
drastically reduced by using a binary tree.
• The tree grows dynamically like the linked
list.
275
276. Searching for Duplicates
• The binary tree is built in a special way.
• The first number in the list is placed in a
node that is designated as the root of a
binary tree.
• Initially, both left and right subtrees of the
root are empty.
• We take the next number and compare it
with the number placed in the root.
• If it is the same then we have a duplicate.
276
277. Searching for Duplicates
• Otherwise, we create a new tree node and
put the new number in it.
• The new node is made the left child of the
root node if the second number is less
than the one in the root.
• The new node is made the right child if the
number is greater than the one in the root.
277
318. Cost of Search
• Given that a binary tree is level d deep.
How long does it take to find out whether a
number is already present?
• Consider the insert(17) in the example
tree.
• Each time around the while loop, we did
one comparison.
• After the comparison, we moved a level
down.
318
319. Cost of Search
• With the binary tree in place, we can write
a routine find(x) that returns true if the
number x is present in the tree, false
otherwise.
• How many comparison are needed to find
out if x is present in the tree?
• We do one comparison at each level of the
tree until either x is found or q becomes
NULL.
319
320. Cost of Search
• If the binary tree is built out of n numbers,
how many comparisons are needed to find
out if a number x is in the tree?
• Recall that the depth of the complete
binary tree built using ‘n’ nodes will be
log2(n+1) – 1.
• For example, for n=100,000, log2(100001)
is less than 20; the tree would be 20 levels
deep.
320
321. Cost of Search
• If the tree is complete binary or nearly
complete, searching through 100,000
numbers will require a maximum of 20
comparisons.
• Or in general, approximately log2(n).
• Compare this with a linked list of 100,000
numbers. The comparisons required could
be a maximum of n.
321
322. Binary Search Tree
• A binary tree with the property that items in
the left subtree are smaller than the root
and items are larger or equal in the right
subtree is called a binary search tree
(BST).
• The tree we built for searching for
duplicate numbers was a binary search
tree.
• BST and its variations play an important
role in searching algorithms.
322
323. Traversing a Binary Tree
• Suppose we have a binary tree, ordered
(BST) or unordered.
• We want to print all the values stored in
the nodes of the tree.
• In what order should we print them?
323
324. Traversing a Binary Tree
• Ways to print a 3 node tree:
14
15
4
(4, 14, 15), (4,15,14)
(14,4,15), (14,15,4)
(15,4,14), (15,14,4)
324
325. Traversing a Binary Tree
• In case of the general binary tree:
node
(L,N,R), (L,R,N)
(N,L,R), (N,R,L)
(R,L,N), (R,N,L)
left
subtree
right
subtree
L
N
R
325
326. Traversing a Binary Tree
• Three common ways
node
Preorder: (N,L,R)
Inorder: (L,N,R)
Postorder: (L,R,N)
left
subtree
right
subtree
L
N
R
326
334. Recursive Call
• Recall that a stack is used during function
calls.
• The caller function places the arguments
on the stack and passes control to the
called function.
• Local variables are allocated storage on
the call stack.
• Calling a function itself makes no
difference as far as the call stack is
concerned.
334
335. Stack Layout during a call
• Here is stack layout when function F calls
function F (recursively):
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Local variables(F)
Return address(F)
During execution of F After call
At point of call
sp
sp
sp
335
336. Recursive Call
• Recall that a stack is used during function
calls.
• The caller function places the arguments
on the stack and passes control to the
called function.
• Local variables are allocated storage on
the call stack.
• Calling a function itself makes no
difference as far as the call stack is
concerned.
336
337. Stack Layout during a call
• Here is stack layout when function F calls
function F (recursively):
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Local variables(F)
Return address(F)
Parameters(F)
Local variables(F)
Return address(F)
During execution of F After call
At point of call
sp
sp
sp
337
342. Non Recursive Traversal
• We can implement non-recursive versions
of the preorder, inorder and postorder
traversal by using an explicit stack.
• The stack will be used to store the tree
nodes in the appropriate order.
• Here, for example, is the routine for
inorder traversal that uses a stack.
342
343.
Non Recursive Traversal
void inorder(TreeNode<int>* root)
{
Stack<TreeNode<int>* > stack;
TreeNode<int>* p;
p = root;
do
{
while( p != NULL )
{
stack.push( p );
p = p->getLeft();
}
// at this point, left tree is empty
343
344.
Non Recursive Traversal
void inorder(TreeNode<int>* root)
{
Stack<TreeNode<int>* > stack;
TreeNode<int>* p;
p = root;
do
{
while( p != NULL )
{
stack.push( p );
p = p->getLeft();
}
// at this point, left tree is empty
344
345.
Non Recursive Traversal
void inorder(TreeNode<int>* root)
{
Stack<TreeNode<int>* > stack;
TreeNode<int>* p;
p = root;
do
{
while( p != NULL )
{
stack.push( p );
p = p->getLeft();
}
// at this point, left tree is empty
345
346.
Non Recursive Traversal
if( !stack.empty() )
{
p = stack.pop();
cout << *(p->getInfo()) << " ";
// go back & traverse right subtree
p = p->getRight();
}
} while ( !stack.empty() || p != NULL );
}
346
347.
Non Recursive Traversal
if( !stack.empty() )
{
p = stack.pop();
cout << *(p->getInfo()) << " ";
// go back & traverse right subtree
p = p->getRight();
}
} while ( !stack.empty() || p != NULL );
}
347
348.
Non Recursive Traversal
if( !stack.empty() )
{
p = stack.pop();
cout << *(p->getInfo()) << " ";
// go back & traverse right subtree
p = p->getRight();
}
} while ( !stack.empty() || p != NULL );
}
348
349.
Non Recursive Traversal
if( !stack.empty() )
{
p = stack.pop();
cout << *(p->getInfo()) << " ";
// go back & traverse right subtree
p = p->getRight();
}
} while ( !stack.empty() || p != NULL );
}
349
355. Level-order Traversal
• There is yet another way of traversing a
binary tree that is not related to recursive
traversal procedures discussed previously.
• In level-order traversal, we visit the nodes
at each level before proceeding to the next
level.
• At each level, we visit the nodes in a left-
to-right order.
355
357. Level-order Traversal
• There is yet another way of traversing a
binary tree that is not related to recursive
traversal procedures discussed previously.
• In level-order traversal, we visit the nodes
at each level before proceeding to the next
level.
• At each level, we visit the nodes in a left-
to-right order.
357
359. Level-order Traversal
• How do we do level-order traversal?
• Surprisingly, if we use a queue instead of
a stack, we can visit the nodes in level-
order.
• Here is the code for level-order traversal:
359
380. Storing other Type of Data
• The examples of binary trees so far have
been storing integer data in the tree node.
• This is surely not a requirement. Any type
of data can be stored in a tree node.
• Here, for example, is the C++ code to
build a tree with character strings.
380