Algo Chap 3-5
Algo Chap 3-5
Chapter Three
1
Introduction to Linked List
Data structures can be divided into two types: static data structures
and dynamic data structures.
Static data structures cannot change their form during program
execution.
array is an example of a static data structure.
Arrays (and static data structures in general) have at least two
limitations:
their size has to be known at compile-time
the data in the array are stored in a continuous block of computer
memory
which means that inserting an item in the middle of the array
requires shifting other data in the array.
These limitations can be overcome by using dynamic data
structures.
2 A dynamic data structure can change its form during program
Linked Lists
linked list is a collection of objects called nodes, and a node
contains information and a link to the other node/nodes.
Advantages of Linked Lists
Allocation of memory is more flexible in which memory is
allocated dynamically (allocation of memory during run time)
for each element as needed.
This implies that one need not know the size of the list in advance.
Memory is efficiently utilized.
A linked list is made up of a chain of nodes. Each node
contains:
Data (information): the actual contents of the node
Link: a pointer to the next node
3
Limitation of Linked list
The memory is wasted as pointers require extra
memory for storage.
No element can be accessed randomly; it has to access
each node sequentially.
Reverse Traversing is difficult in linked list.
Applications of Linked Lists
Linked lists are used to implement stacks, queues,
graphs, etc.
Linked lists let you insert elements at the beginning and
end of the list.
In Linked Lists we don’t need to know the size in
4
advance.
Refreshment note on Structures in C++
Structures are aggregate data types built using elements of primitive data
types.
Structure are defined using the struct keyword:
E.g. struct Time{
int hour;
int minute;
int second;
};
The struct keyword creates a new user defined data type that is used to
declare variables of an aggregate data type.
Structure variables are declared like variables of other types.
Syntax: struct <structure tag> <variable name>;
E.g. struct Time timeObject,
struct Time *timeptr;
5
Accessing Members of Structure Variables
The Dot operator (.): to access data members of
structure variables.
The Arrow operator (->): to access data members
of pointer variables pointing to the structure.
E.g. Print member hour of timeObject and timeptr.
cout<<timeObject.hour;
cout<<timeptr->hour;
TIP: timeptr->hour is the same as (*timeptr).hour.
The parentheses is required since (*) has lower
precedence than (.).
6
Operations on Linked List
The primitive operations performed on the linked list
are as follows:
1. Creation
2. Insertion
3. Deletion
4. Searching
5. Traversing
7
Cont…
1. Creation operation is used to create a linked list.
Once a linked list is created with one node, insertion operation
8
Cont…
3. Deletion operation is used to delete an item (or node) from the
linked list. A node may be deleted from the:
(a) Beginning of a linked list
(b) End of a linked list
(c) Specified location of the linked list
4. Traversing is the process of going through all the nodes from
one end to another end of a linked list.
In a singly linked list we can visit from left to right, forward
traversing, nodes only.
But in doubly linked list forward and backward traversing is
possible.
9
Types of linked lists
Singly Linked Lists
Doubly Linked Lists
Circular Lists
10
Singly linked list
Singly linked list is a linked list, in which a node has
only one link which is a pointer to the next node.
Hence in a singly linked list, one can traverse through
the list in one direction only.
Creating Linked Lists in C++
A linked list is a data structure that is built from
structures and pointers.
It forms a chain of "nodes" with pointers representing
the links of the chain and holding the entire thing
together
11
Cont………
next
A singly linked list is a concrete
data structure consisting of a
sequence of nodes
Each node stores
elem node
element
link to the next node
A B C D
12
Cont.…
• All the nodes in a singly linked list are arranged sequentially by
linking with a pointer.
• A singly linked list can grow or shrink, because it is a dynamic
data structure.
13
Cont..…
The operations we can perform on singly linked lists
are insertion, deletion and traversal.
A linked list can be represented by a diagram like the
following:
This linked list has four nodes in it, each with a link to
the next node in the series.
The last node has a link to the special value NULL, to
show that it is the last link in the chain.
There is also another special pointer, called Start (also
called head), which points to the first link in the chain
14
so that we can keep track of it.
Defining the data structure for a linked list
The key part of a linked list is a structure, which holds the data for each node (the
name, address, age or whatever for the items in the list), and, most importantly, a
pointer to the next node.
Here we have given the structure of a typical node:
struct node {
char name[20];
int age;
float height;
node *nxt; // Pointer to next node
};
struct node *start_ptr = NULL;
node *nxt; - gives a pointer to the next node in the list.
We have also declared a pointer called start_ptr that will permanently point to
the start of the list.
To start with, there are no nodes in the list, which is why start_ptr is set to
NULL.
15
Cont..
16
Singly Linked List
Adding a node to the list
All the nodes in a singly linked list are arranged sequentially by
linking with a pointer.
A singly linked list can grow or shrink, because it is a dynamic
data structure.
17
Singly Linked List …
Algorithm for Inserting a Node
18
Singly Linked List …
19
Singly Linked List …
Insert a node at the end
24
Cont…
voidadd_node_at_end (){ node *temp, *temp2; //
Temporary pointers // Reserve space for new node
and fill it with datatemp = new node;cout<< "Please
enter the name of the person: ";cin>> temp-
>name;cout<< "Please enter the age of the person :
";cin>> temp->age;cout<< "Please enter the height of
the person : ";cin>> temp->height;temp->nxt =
NULL; // Set up link to this nodeif (start_ptr ==
NULL)start_ptr = temp;else{ temp2 =
start_ptr; // We know this is not NULL - list not
empty!while (temp2->nxt != NULL){ temp2 = temp2-
>nxt; // Move to next link in chain }
temp2->nxt = temp; } }
25
Cont…
temp = start_ptr;
do{
if (temp == NULL)
cout<< "End of list" <<endl;else{ // Display details for what temp points to
cout<< "Name : " << temp->name <<endl;
cout<< "Age : " << temp->age <<endl;
cout<< "Height : " << temp->height <<endl;cout<<endl; // Blank
line // Move to next node
(if present)temp = temp->nxt; } }
while (temp != NULL);
26
Deleting a node from the list
When it comes to deleting nodes, we have three choices:
Delete a node from the start of the list, delete one from the
end of the list, or delete one from somewhere in the middle.
Here is the function that deletes a node from the start:
void delete_start_node()
{
node *temp;
temp = start_ptr;
start_ptr = start_ptr->nxt;
void delete_end_node() delete temp; }
{ node *temp1, *temp2;
if (start_ptr == NULL)
cout << "The list is empty!" << endl;
else {
temp1 = start_ptr;
while (temp1->nxt != NULL) {
temp2 = temp1;
temp1 = temp1->nxt; }
delete temp1;
temp2->nxt = NULL; }
27
Singly Linked List …
28
Doubly Linked List
In a doubly linked list, each node contains two links
the first link points to the previous node and the next
link points to the next node in the sequence.
Items can be navigated forward and backward way.
29
Doubly Linked List …
LPoint will point to the node in the left side (or previous node) that is LPoint
will hold the address of the previous node. RPoint will point to the node in the
right side (or next node) that is RPoint will hold the address of the next node.
DATA will store the information of the node.
30
Cont.…..
31
elements
Creating Doubly Linked Lists
The nodes for a doubly linked list would be defined as follows:
struct node{
char name[20];
node *nxt; // Pointer to next
node *prv; // Pointer to previous node
};
node *current;
current = new node;
current->name = "Fred";
current->nxt = NULL;
current->prv = NULL;
We have also included some code to declare the first node and set its pointers
to NULL. It gives the following situation:
32
Adding a Node to a Doubly Linked List
33
Cont..
void add_node_at_end ()
{// Declare a temporary pointer and move it to the end
node *temp = current;
while (temp->nxt != NULL)
temp = temp->nxt; // Declare a new node and link it in
node *temp2;
temp2 = new node;
temp2->name = new_name; // Store the new name in the node
temp2->nxt = NULL; // This is the new start of the list
temp2->prv = temp; // Links to current list
temp->nxt = temp2; }
34
Circular Linked List
In the circular linked list the last node of the list
contains the address of the first node and forms a
circular chain.
Last item contains link of the first element as next and
first element has link to last element as prev.
35
Stack
A simple data structure, in which insertion and deletion occur at the same end, is
termed (called) a stack. It is a LIFO (Last In First Out) structure.
It means: the last element inserted is the first one to be removed
Anything added to the stack goes on the “top” of the stack
Anything removed from the stack is taken from the “top” of the stack
Dynamic Stacks
Grow in size as needed
Can be implemented with a linked list
37
Cont..
The operations of insertion and deletion are called PUSH and POP
respectively
Push - push (put) item onto stack
Pop - pop (get) item from stack
Applications
The simplest application of a stack is to reverse a word. You push a given
word to stack - letter by letter - and then pop letters from the stack.
Another application is an "undo" mechanism in text editors; this operation
is accomplished by keeping all text changes in a stack.
Real life
Pile of books
Plate trays
More applications related to computer science
Program execution stack (read more from your text)
Evaluating expressions
38
The Push Operation
Suppose we have an empty integer stack that is capable
of holding a maximum of three values. With that stack
we execute the following push operations.
The state of the stack after each of the push operations :
push(5);
push(10);
push(15);
39
The Pop Operation
40
Cont.….
Initial stack push(8) pop
8
TOS=>
4 4 4
TOS=> 1 1
TOS=>
1
3 3 3
6 6 6
41
Cont. ….
Implementation:
Stacks can be implemented both as an array
(contiguous list) and as a linked list. We want a set of
operations that will work with either type of
implementation: i.e. the method of implementation is
hidden and can be changed without affecting the
programs that use them.
42
Cont..
The Basic Operations:
Push() {
if there is room {
put an item on the top of the stack
else
give an error message
}}
Pop() { if stack not empty {
return the value of the top item
remove the top item from the stack }
else {
give an error message
}}
CreateStack() {
remove existing items from the stack
initialise the stack to empty
}
43
Array Implementation of Stacks: The
PUSH operation
Here, as you might have noticed, addition of an element is
known as the PUSH operation. So, if an array is given to you,
which is supposed to act as a STACK, you know that it has to
be a STATIC Stack; meaning, data will overflow if you cross
the upper limit of the array. So, keep this in mind.
Algorithm:
Step-1: Increment the Stack TOP by 1. Check whether it is
always less than the Upper Limit of the stack. If it is less than
the Upper Limit go to step-2 else report -"Stack Overflow"
Step-2: Put the new element at the position pointed by the
TOP
44
Cont..
Push operation involves series of steps −
Step 1 − Check if stack is full.
Step 2 − If stack is full, produce error and exit.
Step 3 − If stack is not full, increment top to point
next empty space.
Step 4 − Add data element to the stack location, where
top is pointing.
Step 5 − return success.
45
Implementation:
static int stack[UPPERLIMIT];
int top= -1; /*stack is empty*/
..
..
main()
{
..
..
push(item);
..
..
}
push(int item)
{
top = top + 1;
if(top < UPPERLIMIT)
stack[top] = item; /*step-1 & 2*/
else
cout<<"Stack Overflow";
}
Note:- In array implementation,we have taken TOP = -1 to signify the empty stack, as this
46 simplifies the implementation.
Array Implementation of Stacks: the POP operation
47
Cont. …..
Implementation:
static int stack[UPPPERLIMIT];
int top=-1;
..
..
main()
{
..
..
poped_val = pop();
..
..
}
int pop()
{
int del_val = 0;
if(top == -1)
cout<<"Stack underflow"; /*step-1*/
else
{
del_val = stack[top]; /*step-2*/
stack[top] = NULL;
top = top -1;
}
return(del_val);
}
48 Note: - Step-2:(b) signifies that the respective element has been deleted.
Linked List Implementation of Stacks: the
PUSH operation
It’s very similar to the insertion operation in a dynamic
singly linked list. The only difference is that here you'll
add the new element only at the end of the list, which
means addition can happen only from the TOP.
In Step [1] we create the new element to be pushed to the
Stack.
In Step [2] the TOP most element is made to point to our
newly created element.
In Step [3] the TOP is moved and made to point to the last
element in the stack, which is our newly added element.
49
Algorithm
Step-1: If the Stack is empty go to step-2 or else go to
step-3
Step-2: Create the new element and make your "stack"
and "top" pointers point to it and quit.
Step-3: Create the new element and make the last (top
most) element of the stack to point to it
Step-4: Make that new element your TOP most element
by making the "top" pointer point to it.
50
Cont.…
Implementation:
struct node{
int item;
struct node *next;
}
struct node *stack = NULL; /*stack is initially empty*/
struct node *top = stack;
main()
{
..
push(item);
..}
push(int item){
if(stack == NULL) {/*step-1*/
newnode = new node /*step-2*/
newnode -> item = item;
newnode -> next = NULL;
stack = newnode;
top = stack;}
else{
newnode = new node; /*step-3*/
newnode -> item = item;
newnode -> next = NULL;
top ->next = newnode;
top = newnode; /*step-4*/
}}
51
Linked List Implementation of Stacks: the POP
Operation
This is again very similar to the deletion operation in any Linked
List, but you can only delete from the end of the list and only one at
a time; and that makes it a stack. Here, we'll have a list pointer,
"target", which will be pointing to the last but one element in the
List (stack). Every time we POP, the TOP most element will be
deleted and "target" will be made as the TOP most element.
In step[1] we got the "target" pointing to the last
but one node.
In step[2] we freed the TOP most element.
In step[3] we made the "target" node as our
TOP most element.
Supposing you have only one element left in the
Stack, then we won't make use of "target" rather
we'll take help of our "bottom" pointer. See
how...
52
Cont.…
Algorithm:
Step-1: If the Stack is empty then give an alert
message "Stack Underflow" and quit; or else proceed
Step-2: If there is only one element left go to step-3 or
else step-4
Step-3: Free that element and make the "stack", "top"
and "bottom" pointers point to NULL and quit
Step-4: Make "target" point to just one element before
the TOP; free the TOP most element; make "target" as
your TOP most element
53
Implementation:
struct node{
int nodeval;
struct node *next;};
struct node *stack = NULL; /*stack is initially empty*/
struct node *top = stack;
main(){
int newvalue, delval;
..
push(newvalue);
..
delval = pop(); } /*POP returns the deleted value from the stack*/
int pop( ){
int pop_val = 0;
struct node *target = stack;
if(stack == NULL) /*step-1*/
cout<<"Stack Underflow";
else{
if(top == bottom) { /*step-2*/
pop_val = top -> nodeval; /*step-3*/
delete top;
stack = NULL;
top = bottom = stack;}
else{ /*step-4*/
while(target->next != top) target = target ->next;
pop_val = top->nodeval;
delete top;
top = target;
target ->next = NULL; }}return(pop_val);}
54
Applications of Stacks
Evaluation of Algebraic Expressions
Mathematical Calculations
What is 3 + 2 * 4? 2 * 4 + 3? 3 * 2 + 4?
Simple calculator 20 for 3+2*4
Scientific calculator 11 for 3+2*4
The precedence of operators affects the order of
operations. A mathematical expression cannot
simply be evaluated left to right.
A challenge when evaluating a program.
Lexical analysis is the process of interpreting a program.
Note: Computers solve arithmetic expressions by
restructuring them so the order of each calculation is
embedded in the expression. Once converted an
55 expression can then be solved in one pass.
Types of Expression
1.Infix the normal or human way of expressing mathematical
expressions .Example 4+5*5
2. Prefix When the operators are written before their operands, it is called
the prefix form.
Example +4*55
3. Postfix When the operators come after their operands, it is called postfix
form (suffix form or reverse polish notation)
Postfix expression does not require any precedence rules.
Example 455*+
3 2 * 1 + is postfix of 3 * 2 + 1
Note The two methods (prefix and postfix) called Polish Notation (because
this method was discovered by the Polish mathematician Jan Lukasiewicz).
56
Simple Example
Infix Expression: 3+2*4
PostFix Expression:
Operator Stack:
57
Simple Example
Infix Expression: +2*4
PostFix Expression: 3
Operator Stack:
58
Simple Example
Infix Expression: 2*4
PostFix Expression: 3
Operator Stack: +
59
Simple Example
Infix Expression: *4
PostFix Expression: 32
Operator Stack: +
60
Simple Example
Infix Expression: 4
PostFix Expression: 32
Operator Stack: +*
61
Simple Example
Infix Expression:
PostFix Expression: 324
Operator Stack: +*
62
Simple Example
Infix Expression:
PostFix Expression: 324*
Operator Stack: +
63
Simple Example
Infix Expression:
PostFix Expression: 324*+
Operator Stack:
64
Conti..
65
Cont.….…
The single value on the stack is the desired result.
Binary operators: +, -, *, /, etc.,
Unary operators: unary minus, square root, sin, cos, exp, etc.,
So for 6 5 2 3 + 8 * + 3 + *
TOS=> 3
2
5
6
The remaining items are now: + 8 * + 3 + *
So next a '+' is read (a binary operator), so 3 and 2 are popped from the stack and their sum '5' is pushed onto the stack:
TOS => 8
TOS=> 5 Next 8 is pushed and next item is TOS=> 40
5
5 the operator * 5
5
(8 ,5 poped,40 pushed) 6
6 6
66
Cont.….
Next + followed by 3
TOS=> 45 3
TOS=>
6 45
6 40, 5 popped, 45 pushed, 3 pushed
48
288
Now there are no more items and there is a single value on the stack, representing the final answer 288.
67
Exercise
evaluate the following postfix expressions and write
out a corresponding infix expression:
2324*+* 1234^*+
377*+
68
Queue
a data structure that has access to its data at the front and
rear.
A queue is a first in, first out (FIFO) data structure.
has two basic operations:
enqueue - inserting data at the rear of the queue
dequeue – removing data
dequeu enqueuat the front of the queue
e e
Front Rear
0 1 2 3 4 5 6 7
myQueue:
17 23 97 44
front = 0 rear = 3
To insert: put new element in location 4, and set rear to 4
To delete: take element from location 0, and set front to 1
69
Cont.…
example
front = 0 rear = 3
Initial queue: 17 23 97 44
front = 1 rear = 4
Notice how the array contents “crawl” to the right as elements are inserted and
deleted
This will be a problem after a while!
70
Cont.…
Example 2
Operation Content of queue
Enqueue(B) B
Enqueue(C) B, C
Dequeue() C
Enqueue(G) C, G
Enqueue (F) C, G, F
Dequeue() G, F
Enqueue(A) G, F, A
Dequeue() F, A
71
Simple array implementation of Enqueue and Dequeue opertion
const int MAX_SIZE=100;
int FRONT =-1, REAR =-1;
int QUEUESIZE = 0;
void enqueue(int x){
if(Rear<MAX_SIZE-1) {
REAR++;
Num[REAR]=x;
QUEUESIZE++;
if(FRONT = = -1)
FRONT++;}
else
cout<<"Queue Overflow";}
int dequeue(){
int x;
if(QUEUESIZE>0) {
x=Num[FRONT];
FRONT++;
QUEUESIZE--;}
else
cout<<"Queue Underflow";
return(x);}
72
Priority Queue
Priority Queue
- is a queue where each data has an associated
key that is provided at the time of insertion.
- Dequeue operation deletes data having highest
priority in the list
- One of the previously used dequeue or enqueue
operations has to be modified
Example: Consider the following queue of
persons where females have higher priority
than males (gender is the key to give priority).
73
Cont..
Dequeue()- deletes Aster
74
Application of Queues
A.Print server- maintains a queue of print jobs
Print(){
EnqueuePrintQueue(Document)
}
EndOfPrint(){
DequeuePrintQueue()
}
B.Disk Driver- maintains a queue of disk input/output requests
C.Task scheduler in multiprocessing system- maintains priority queues of
processes .
D.Telephone calls in a busy environment –maintains a queue of telephone calls
E. Simulation of waiting line- maintains a queue of persons
75
//Trees
A tree is a set of nodes and edges that connect pairs of
nodes. It is an abstract model of a hierarchical structure.
Rooted tree has the following structure:
One node distinguished as root.
Every node C except the root is connected from exactly
other node P. P is C's parent, and C is one of C's children.
There is a unique path from the root to the each node.
The number of edges in a path is the length of the path.
A tree consists of finite set of elements, called nodes, and
a finite set of directed lines called branches, that connect
the nodes.
The number of branches associated with a node is the
degree of the node.
76
Cont.….
A leaf is any node with an outdegree of zero, that is, a node
with no successors.
A node that is not a root or a leaf is known as an internal node.
A node is a parent if it has successor nodes; that is, if it has
outdegree greater than zero.
A node with a predecessor is called a child.
Two or more nodes with the same parents are called siblings.
An ancestor is any node in the path from the root to the node.
A descendant is any node in the path below the parent node;
that is, all nodes in the paths from a given node to a leaf are
descendants of that node.
77
Cont.…
A path is a sequence of nodes in which each node is
adjacent to the next node.
The level of a node is its distance from the root. The root is
at level 0, its children are at level 1, etc. …
The height of the tree is the level of the leaf in the longest
path from the root plus 1. By definition the height of any
empty tree is -1.
A subtree is any connected structure below the root. The
first node in the subtree is known is the root of the subtree.
The sum of the indegree and outdegree branches is the
degree of the node.
If the tree is not empty, the first node is called the root.
Children of the same parent are siblings.
78
Cont..
Consider the following tree
79
Cont..
Root:a node with out a parent. A
Internal node: a node with at least one child.A, B, F, I, J
External (leaf) node: a node without a child. C, D, E, H, K, L,M, G
Ancestors of a node:parent, grandparent, grand-grandparent, etc of a node.
-Ancestors of K A, F, I
Descendants of a node: children, grandchildren, grand-grandchildren etc of a node.
-Descendants of F H, I, J, K, L, M
Depth of a node: number of ancestors or length of the path from the root to the node.
-Depth of H 2
Height of a tree: depth of the deepest node . 3
Subtree: a tree consisting of a node and its descendants.
Children of the same parent are siblings.
The node with degree 0 is a leaf or terminal
node.
The degree of a node is the number of subtrees
of the node .The degree of A is 4; the degree of C is 0.
The node with degree 0 is a leaf or terminal
node.
80
Binary Tree
a tree in which each node has at most two children called left child and
right child. Any tree can be transformed into binary tree. Binary tree has
the following property
All items in the left subtree are less than the root.
All items in the right subtree are greater or equal to the root.
Each subtree is itself a binary search tree.
82
83
Binary search tree (ordered binary tree):
a binary tree that may be empty, but if it is not empty it
satisfies the following.
Every node has a key and no two elements have the same
key.
The keys in the right subtree are larger than the keys in the
root.
The keys in the left subtree are smaller than the keys in the
root.
The left and the right subtrees are also binary search trees.
84
Cont.……
85
Data Structure of a Binary Tree
struct DataModel{
Declaration of data fields
DataModel * Left, *Right;};
DataModel *RootDataModelPtr=NULL;
Insertion
When a node is inserted the definition of binary search tree should be preserved. Suppose
there is a binary search tree whose root node is pointed by RootNodePtr and we want to
insert a node (that stores 17) pointed by InsNodePtr.
17 17
86
Cont. ….
Case 2: There is data
-Search the appropriate position.
-Insert the node in that position.
87
Traversing
Binary search tree can be traversed in three ways.
A.Pre order traversal- traversing binary tree in the order of parent, left and right.
B.Inorder traversal- traversing binary tree in the order of left, parent and right.
C.Postorder traversal- traversing binary tree in the order of left, right and parent.
Example
Preorder traversal - 10, 6, 4, 8, 7, 15, 14, 12, 11, 13, 18, 16, 17, 19
Inorder traversal - 4, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
==> Used to display nodes in ascending order.
Postorder traversal- -4, 7, 8, 6, 11, 13, 12, 14, 17, 16, 19, 18, 15, 10
88
Application of binary tree traversal
Store values on leaf nodes and operators on internal nodes
Preorder traversal- used to generate mathematical expression in prefix
notation.
Inorder traversal- used to generate mathematical expression in infix
notation.
Postorder traversal- used to generate mathematical expression in
postfix notation.
89
Cont..
Function call
Preorder(RootNodePtr);
Inorder(RootNodePtr);
Function call
Postorder(RootNodePtr);
Implementation:
90
Cont….
void Postorder (Node *CurrNodePtr){
if(CurrNodePtr ! = NULL){
Postorder(CurrNodePtr->Left);
Postorder(CurrNodePtr->Right);
cout<< CurrNodePtr->Num; // or any operation on the node
}}
91
Search
To search a node (whose Num value is Number) in a binary search tree (whose root
node is pointed by RootNodePtr), one of the three traversal methods can be used.
Function call:
ElementExists = SearchBST (RootNodePtr, Number);
// ElementExists is a Boolean variable defined as: bool ElementExists = false;
Implementation:
bool SearchBST (Node *RNP, int x){
if(RNP = = NULL)
return(false);
else if(RNP->Num = = x)
return(true);
else if(RNP->Num > x)
return(SearchBST(RNP->Left, x));
else
return(SearchBST(RNP->Right, x));}
92
Cont.…..
When we search an element in a binary search tree, sometimes it may be necessary for the Search
BST function to return a pointer that points to the node containing the element searched.
Accordingly, the function has to be modified as follows.
Function call:
SearchedNodePtr = SearchBST (RootNodePtr, Number);
// SearchedNodePtr is a pointer variable defined as: Node *SearchedNodePtr=NULL;
Implementation:
93
Deletion
To delete a node (whose Num value is N) from binary search tree (whose root node
is pointed by RootNodePtr), four cases should be considered. When a node is
deleted the definition of binary search tree should be preserved.
Consider the following binary search tree.
94
Cont.…..
Case 1: Deleting a leaf node (a node having no child), e.g. 7
95
Cont..
97
Cont..
Approach 2: Deletion by copying- the following is done
Copy the node containing the largest element in the left (or the smallest element in the right) to
the node containing the element to be deleted
Delete the copied node
98
Cont.….
Case 3: Deleting a node having two children, e.g. 6
Approach 1: Deletion by merging – one of the following is done
If the deleted node is the left child of its parent, one of the following is done
The left child of the deleted node is made the left child of the parent of the deleted node,
and
The right child of the deleted node is made the right child of the node containing largest
element in the left of the deleted node
OR
The right child of the deleted node is made the left child of the parent of the deleted node, and
The left child of the deleted node is made the left child of the node containing smallest
element in the right of the deleted node
OR
The right child of the deleted node is made the right child of the parent of the deleted node, and
The left child of the deleted node is made the left child of the node containing smallest
element in the right of the deleted node
99
Cont.….
100
Cont..
101
Cont.…..
Approach 2: Deletion by copying- the following is done
Copy the node containing the largest element in the left (or the smallest element in the right) to
the node containing the element to be deleted
Delete the copied node
102
Cont.….
Cont.….
103
CaseIf the tree
4: Deleting the roothas
node, only
10 one node the root node pointer is made to point to nothing
(NULL)
If the root node has left child
104
Cont.….
105
//Graphs
A graph is a pictorial representation of a set of objects where
some pairs of objects are connected
by links. The interconnected objects are represented by points
termed as vertices, and the links that connect the vertices are
called edges.
Formally, a graph is a pair of sets V, E, where V is the set of
vertices and E is the set of edges,
connecting the pairs of vertices. Take a look at the following
graph a b
In the above graph,
c d
V = {a, b, c, d, }
E = {ab, ac, bd, cd, }
106
Cont. ….
Each edge connects two different vertices.
Edges are also called arcs and lines.
Directed edge has an orientation (u,v).
u v
Undirected edge has no orientation (u,v).
u v
Undirected graph => no oriented edge.
Directed graph => every edge has an orientation.
107
Undirected Graph
2
3
8
1 10
4
5
9
11
6
7
108
Directed Graph (Digraph)
2
3
8
1 10
4
5
9
11
6
7
109
Applications—Communication Network
2
3
8
1 10
4
5
9
11
6
7
110
Street Map
2
3
8
1 10
4
5
9
11
6
7
6 7
7
112
Cont.…
Number of edges in an undirected graph is <= n(n-1)/2.
Number of edges in a directed graph is <= n(n-1).
Vertex Degree 2
3
8
1 10
4
5
9
11
6
7
4
5
9
11
6
7
4
5
9
11
6
7
array if parts of it are already sorted. The original array is first divided into a
number of smaller subarrays, these subarrays are sorted, and then they are
combined into the overall array and this is sorted. A general outline of such a
procedure is:
Divide data into h subarrays
for (i = 1; i < h; i++)
Sort subarray i
Sort array data
How should the original array be divided into subarrays? One approach would be
to divide the array into a number of subarrays consisting of contiguous elements
(i.e. elements that are next to each other). For example, the array [abcdef] could
be divided into the subarrays [abc] and [def]. However, shell sort uses a different
approach: the subarrays are constructed by taking elements that are regularly
spaced from each other. For example, a subarray may consist of every second
element in an array, or every third element, etc. For example, dividing the array
[abcdef] into two subarrays by taking every second element results in the
subarrays [ace] and [bdf].
117
Example: Sort the following list using shell sort algorithm.
5 8 2 4 1 3 9 7 6 0
Sort (5, 3) 3 8 2 4 1 5 9 7 6 0
Sort (8, 9) 3 8 2 4 1 5 9 7 6 0
Sort (2, 7) 3 8 2 4 1 5 9 7 6 0
Sort (4, 6) 3 8 2 4 1 5 9 7 6 0
Sort (1, 0) 3 8 2 4 0 5 9 7 6 1
5- sorted list 3 8 2 4 0 5 9 7 6 1
Choose g2 =3
Sort (3, 4, 9, 1) 1 8 2 3 0 5 4 7 6 9
Sort (8, 0, 7) 1 0 2 3 7 5 4 8 6 9
Sort (2, 5, 6) 1 0 2 3 7 5 4 8 6 9
3- sorted list 1 0 2 3 7 5 4 8 6 9
118
Heap Sort
Heap is a binary tree that has two properties:
I. The value of each node is greater than or equal to the values stored in each of
its children.
II. The tree is perfectly balanced, and the leaves in the last level are all in the
leftmost positions.
A property of the heap data structure is that the largest element is always at the
root of the tree.
A common way of implementing a heap is to use an array. The heap sort works
by first rearranging the input array so that it is a heap, and then removing the
largest elements from the heap one by one. Pseudo code code for the heap sort
is given below.
HeapSort(data):
Transform data into a heap
for (i = n-1; i > 1; i--)
Swap the root with element in position i
Restore the heap property for the tree data[0] … data[i-1]
119
Example
a heap
a heap
53
44 25
15 21 13 18
3 12 5 7
120
Cont.….
an example of applying the heap sort algorithm. To begin
with, in Figure a, the array has been arranged as a heap.
The largest element, 10, is removed and swapped with
the last element. In Figure b, the last element of the array
is shaded and the corresponding tree node is surrounded
by a dotted line to indicate that it will not be considered
in the algorithm. Moving the 3 element to the root has
violated the first heap condition, so it is restored by
calling moveDown(), resulting in the tree in Figure c.
Next, the root node 9 is swapped with the last element 2,
and the heap conditions are restored again. This process
continues until only one element remains in the heap.
Then we know that the array has been sorted.
121
Cont.…
122
Sample Run
Start with unordered array of data
Array representation:
Binary tree representation:
21 15 25 3 5 12 7 19 45 2 9
21
15 25
3 5 12 7
19 45 2 9
123
Types of Heap sort
Min Heap. where the value of root node is less than or equal
to either of its children. For every node excluding the root,
value is at least that of its parent: A[parent[i]] A[i]
Smallest element is stored at the root.
In any subtree, no values are smaller than the value
stored at subtree10root
19
14
27
26 31 42
3
44 35 3
124
Max Heap
where the value of root node is greater than or equal to either
of its children. For every node excluding the root,
value is at most that of its parent: A[parent[i]] A[i]
Largest element is stored at the root.
In any subtree, no values are larger than the value
stored at subtree
44
root..
35
42
2
19 7
3 3
3 1
2
6
10
14
125
Quicksort
Quicksort was developed by C. A. R. Hoare in 1961, and is probably the most famous
and widely used of sorting algorithms.
it is more efficient to sort a number of smaller subarrays than to sort one big array.
Quick sort is a highly efficient sorting algorithm and is based on partitioning of array
of data into smaller arrays.
The quick sort partitions an array and then calls itself recursively twice to sort the
resulting two subarray. This algorithm is quite efficient for large sized
In quicksort the original array is first divided into two subarrays, the first of which
contains only elements that are less than or equal to a chosen element, called the
bound or pivot. The second subarray contains elements that are greater than or
equal to the bound.
If each of these subarrays is sorted separately they can be combined into a final sorted
array. To sort each of the subarrays, they are both subdivided again using two new
bounds, making a total of 4 subarrays.
The partitioning is repeated again for each of these subarrays, and so on until the
subarrays consist of a single element each, and do not need to be sorted.
126
operation (the partitioning) applied to successively smaller subarrays.
Cont.…
Quick sort is the fastest known algorithm. It uses divide and
conquer strategy and in the worst case its complexity is O
(n2). But its expected complexity is O(nlogn).
Algorithm:
Choose a pivot value (mostly the first element is taken as
the pivot value)
Position the pivot element and partition the list so that:
The left part has items less than or equal to the pivot value
The right part has items greater than or equal to the pivot
value
Recursively sort the left part
Recursively sort the right part
127
The following algorithm can be used to position a pivot value and create partition.
Left=0;
Right=n-1; // n is the total number of elements in the list
PivotPos=Left;
while(Left<Right){
if(PivotPos==Left){
if(Data[Left]>Data[Right]){
swap(data[Left], Data[Right]);
PivotPos=Right;
Left++;}
else
Right--;}
else{
if(Data[Left]>Data[Right]){
swap(data[Left], Data[Right]);
PivotPos=Left;
Right--; }
else
Left++;}}
128
Fig a
129
Cont.….
QuickSort Pivot Algorithm
Based on our understanding of partitioning in quicksort, we should
now try to write an algorithm
for it here.
S tep 1 − Choose the highest index value has pivot
S tep 2 − Take two variables to point left and right of the list excluding
pivot
S tep 3 − left points to the low index
S tep 4 − right points to the high
S tep 5 − while value at left is less than pivot m ove right
S tep 6 − while value at right is greater than pivot m ove left
S tep 7 − if both step 5 and step 6 does not m atch swap left and right
S tep 8 − if left ≥ right, the point where they m et is new pivot
130
Merge sort
Merge sort works by successively partitioning the array into two
subarrays, but it guarantees that the subarrays are of approximately
equal size. This is possible because in mergesort the array is
partitioned without regard to the values of their elements: it is
simply divided down the middle into two halves. Each of these
halves is recursively sorted using the same algorithm. After the two
subarrays have been sorted, they are merged back together again.
The recursion continues until the subarrays consist of a single
element, in which case they are already sorted.
Algorithm:
Divide the array in to two halves.
Recursively sort the first n/2 items.
Recursively sort the last n/2 items.
Merge sorted items (using an auxiliary array).
131
Cont.…
132
Chapter 5
Hash
133
Dictionary
Dictionary:
Dynamic-set data structure for storing items indexed using keys.
Supports operations Insert, Search, and Delete.
Applications:
Symbol table of a compiler.
Memory-management tables in operating systems.
Large-scale distributed systems.
Hash Tables:
Effective way of implementing dictionaries.
Generalization of ordinary arrays.
134
Direct-address Tables
Direct-address Tables are ordinary arrays.
Facilitate direct addressing.
Element whose key is k is obtained by indexing into the kth
position of the array.
Applicable when we can afford to allocate an array with one
position for every possible key.
i.e. when the universe of keys U is small.
Dictionary operations can be implemented to take O(1) time.
Details in Sec. 11.1.
135
Hash Tables
Notation:
U – Universe of all possible keys.
K – Set of keys actually stored in the dictionary.
|K| = n.
When U is very large,
Arrays are not practical.
|K| << |U|.
Use a table of size proportional to |K| – The hash tables.
However, we lose the direct-addressing ability.
Define functions that map keys to slots of the hash table.
136
Hashing
Hash function h: Mapping from U to the slots of a hash table
T[0..m–1].
h : U {0,1,…, m–1}
With arrays, key k maps to slot A[k].
With hash tables, key k maps or “hashes” to slot T[h[k]].
h[k] is the hash value of key k.
137
Hashing
0
U
(universe of keys) h(k1)
h(k4)
K k1 k4
(actual k2 collisio h(k2)=h(k5)
keys) k5
k3 n
h(k3)
m–1
138
Issues with Hashing
Multiple keys can hash to the same slot – collisions are
possible.
Design hash functions such that collisions are minimized.
But avoiding collisions is impossible.
Design collision-resolution techniques.
139
Methods of Resolution
Chaining: 0
k1 k4
Open Addressing:
All elements stored in hash table itself.
When collisions occur, use a systematic
(consistent) procedure to store elements in free
slots of the table.
140
Collision Resolution by Chaining
0
U
(universe of keys) h(k1)=h(k4)
X
k1
k4
K
(actual k2 k6 X
k5 h(k2)=h(k5)=h(k6)
keys)
k8 k7
k3
X h(k3)=h(k7)
h(k8)
m–1
141
Collision Resolution by Chaining
0
U
(universe of keys) k1 k4
k1
k4
K
(actual k2 k6
k5 k5 k2 k6
keys)
k8 k7
k3
k7 k3
k8
m–1
142
Hashing with Chaining
Dictionary Operations:
Chained-Hash-Insert (T, x)
Insert x at the head of list T[h(key[x])].
Worst-case complexity – O(1).
Chained-Hash-Delete (T, x)
Delete x from the list T[h(key[x])].
Worst-case complexity – proportional to length of list with
singly-linked lists. O(1) with doubly-linked lists.
Chained-Hash-Search (T, k)
Search an element with key k in list T[h(k)].
Worst-case complexity – proportional to length of list.
143
Analysis on Chained-Hash-Search
Load factor =n/m = average keys per slot.
m – number of slots.
n – number of elements stored in the hash table.
Worst-case complexity: (n) + time to compute h(k).
144
Expected Cost of an Unsuccessful Search
Theorem:
An unsuccessful search takes expected time Θ(1+α).
Proof:
Any key not already in the table is equally likely to hash
to any of the m slots.
To search unsuccessfully for any key k, need to search to
the end of the list T[h(k)], whose expected length is α.
Adding the time to compute the hash function, the total
time required is Θ(1+α).
145
Expected Cost of a Successful Search
Theorem:
A successful search takes expected time Θ(1+α).
Proof:
The probability that a list is searched is proportional to the number of elements
it contains.
Assume that the element being searched for is equally likely to be any of the n
elements in the table.
The number of elements examined during a successful search for an element x
is 1 more than the number of elements that appear before x in x’s list.
These are the elements inserted after x was inserted.
Goal:
Find the average, over the n elements x in the table, of how many elements were inserted
into x’s list after x was inserted.
146
Expected Cost of a Successful Search
Theorem:
A successful search takes expected time Θ(1+α).
Proof (contd):
Let xi be the ith element inserted into the table, and let ki = key[xi].
Define indicator random variables Xij = I{h(ki) = h(kj)}, for all i, j.
Simple uniform hashing Pr{h(ki) = h(kj)} = 1/m
E[Xij] = 1/m.
Expected number of elements examined in a successful search is:
1 n n
E 1 X ij
n i 1 j i 1
1 n
1 (n i)
nm i 1
1 n n
1 n i
nm i 1 i 1
1 2 n(n 1)
1 n
nm 2
Expected total time for a successful search
n 1
1 = Time to compute hash function + Time
2m
1
to search
2 2n
= O(2+/2 – /2n) = O(1+ ).
148
Expected Cost – Interpretation
If n = O(m), then =n/m = O(m)/m = O(1).
Searching takes constant time on average.
Insertion is O(1) in the worst case.
Deletion takes O(1) worst-case time when lists are doubly
linked.
Hence, all dictionary operations take O(1) time on
average with hash tables with chaining.
149
Good Hash Functions
Satisfy the assumption of simple uniform hashing.
Not possible to satisfy the assumption in practice.
Often use heuristics, based on the domain of the keys, to
create a hash function that performs well.
Regularity in key distribution should not affect uniformity.
Hash value should be independent of any patterns that might
exist in the data.
E.g. Each key is drawn independently from U according to a
probability distribution P:
k:h(k) = j P(k) = 1/m for j = 0, 1, … , m–1.
An example is the division method.
150
Keys as Natural Numbers
Hash functions assume that the keys are natural numbers.
When they are not, have to interpret them as natural numbers.
Example: Interpret a character string as an integer expressed
in some radix notation. Suppose the string is CLRS:
ASCII values: C=67, L=76, R=82, S=83.
There are 128 basic ASCII values.
So, CLRS = 67·1283+76 ·1282+ 82·1281+ 83·1280
= 141,764,947.
151
Division Method
Map a key k into one of the m slots by taking the
remainder of k divided by m. That is,
h(k) = k mod m
Example: m = 31 and k = 78 h(k) = 16.
Advantage: Fast, since requires just one division
operation.
Disadvantage: Have to avoid certain values of m.
Don’t pick certain values, such as m=2p
Or hash won’t depend on all bits of k.
Good choice for m:
Primes, not too close to power of 2 (or 10) are good.
152
Multiplication Method
If 0 < A < 1, h(k) = m (kA mod 1) = m (kA – kA)
where kA mod 1 means the fractional part of kA, i.e., kA –
kA.
Disadvantage: Slower than the division method.
Advantage: Value of m is not critical.
Typically chosen as a power of 2, i.e., m = 2p, which makes
implementation easy.