Data structure using C language
Data structure using C language
UNIT-II
Stack: Stack ADT, array and linked list implementation, Applications- expression conversion
and evaluation. Queue: Types of Queue: Simple Queue, Circular Queue, Queue ADT- array
and linked list implementation. Priority Queue, heaps.
UNIT-III
Searching: Linear and binary search methods. Sorting: Selection Sort, Bubble Sort, Insertion
Sort, Quick Sort, Merge Sort, Heap Sort. Time Complexities .Graphs: Basic terminology,
representation of graphs, graph traversal methods DFS, BFS.
UNIT IV
Dictionaries: linear list representation, skip list representation, operations - insertion,
deletion and searching. Hash Table Representation: hash functions, collision resolution-
separate chaining, open addressing-linear probing, quadratic probing, double hashing,
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING rehashing, extendible hashing.
UNIT-V
MALLA REDDY COLLEGE OF ENGINEERING & TECHNOLOGY Binary Search Trees: Various Binary tree representation, definition, BST ADT,
Implementation, Operations- Searching, Insertion and Deletion, Binary tree traversals,
(Autonomous Institution – UGC, Govt. of India) threaded binary trees,
(Recognized under 2(f) and 12 (B) of UGC ACT 1956)
(Affiliated to JNTUH, Hyderabad, Approved by AICTE - Accredited by NBA & NAAC – ‘A’ Grade - ISO 9001:2015 Certified) AVL Trees : Definition, Height of an AVL Tree, Operations – Insertion, Deletion and
Maisammaguda, Dhulapally (Post Via. Hakimpet), Secunderabad – 500100, Telangana State, India Searching
B-Trees: B-Tree of order m, height of a B-Tree, insertion, deletion and searching, B+ Tree.
TEXTBOOKS:
1. Data Structures using C++, Special Edition-MRCET, Tata McGraw-Hill Publishers 2017.
2. Data structures, Algorithms and Applications in C++, S.Sahni, University Press (India)
Pvt.Ltd, 2nd edition, Universities Press Orient Longman Pvt. Ltd. Education.
INDEX
TOPIC PAGE NO
UNIT -1 UNIT -1
UNIT NO
Introduction 01
Introduction: Abstract data types, Singly linked list: Definition, operations: Traversing, Searching, The linked allocation has the following draw backs:
Singly linked list 02 1. No direct access to a particular element.
I Insertion and deletion, Doubly linked list: Definition, operations: Traversing, Searching, Insertion and
Doubly linked list 14 2. Additional memory required for pointers.
deletion, Circular Linked List: Definition, operations: Traversing, Searching, Insertion and deletion
Circular Linked List 28
Stack ADT 34 Data structure A data structure is a specialized format for organizing and storing data. Linked list are of 3 types:
General data structure types include the array, the file, the record, the table, the tree, and so on. 1. Singly Linked List
Array implementation 35
Any data structure is designed to organize data to suit a specific purpose so that it can be accessed 2. Doubly Linked List
linked list implementation 38 3. Circularly Linked List
and worked with in appropriate ways
Queue ADT 42
II Array implementation 43
Abstract Data Type SINGLY LINKED LIST
In computer science, an abstract data type (ADT) is a mathematical model for data types A singly linked list, or simply a linked list, is a linear collection of data items. The linear order is
linked list implementation 45 where a data type is defined by its behavior (semantics) from the point of view of a user given by means of POINTERS. These types of lists are often referred to as linear linked list.
Circular Queue 47 of the data, specifically in terms of possible values, possible operations on data of this type, * Each item in the list is called a node.
Priority Queue 52 and the behavior of these operations. When a class is used as a type, it is an abstract type that * Each node of the list has two fields:
Heaps 53 refers to a hidden representation. In this model an ADT is typically implemented as a class, and 1. Information- contains the item being stored in the list.
Searching: Linear Search 67 each instance of the ADT is usually a n object of that class. 2. Next address- contains the address of the next item in the list.
In ADT all the implementation details are hidden * The last node in the list contains NULL pointer to indicate that it is the end of the list.
Binary search 70
Sorting: Bubble Sort 74 Conceptual view of Singly Linked List
Selection Sort 75
Insertion Sort 77
Quick Sort 78
III
Merge Sort 82
Operations on Singly linked list:
Heap Sort 84 Insertion of a node
Time Complexities 86 Deletions of a node
Graphs: Basic terminology 87 Traversing the list
Representation of graphs 89
Graph traversal methods 91 Structure of a node:
Dictionaries: linear list representation 94 Method -1:
Skip list representation 98
IV Hash Table Representation 102 struct node
Rehashing, 109 { Data link
Linear data structures are the data structures in which data is arranged in a list or in a int data;
Extendible hashing 111 sequence. struct node *link;
Binary Search Trees: Basics 115 Non linear data structures are the data structures in which data may be arranged in a };
Binary tree traversals 119 hierarchic al manner
Binary Search Tree 121 LIST ADT
V List is basically the collection of elements arrange d in a sequential manner. In memory Method -2:
AVL Trees 126
B-Trees 138 we can store the list in two ways: one way is we can store the elements in sequential
memory locations. That means we can store the list in arrays. class node
B+ Tree 147 The other way is we can use pointers or links to associate elements sequentially. {
This is known as linked list. public:
int data;
LINKED LISTS node *link;
The linked list is very different type of collection from an array. Using such lists, we can };
store collections of information limited only by the total amount of memory that the OS will allow
us to use.Further more, there is no need to specify our needs in advance. The linked list is very
flexible dynamic data structure : items may be added to it or deleted from it at will. A programmer
need not worry about how many items a program will have to accommodate in advance. This
allows us to write robust programs which require much less maintenance.
Page 1 Page 2
1 2
UNIT -1 UNIT -1 UNIT -1
Traversing the list: Assuming we are given the pointer to the head of the list, how do we get the end template <class T> template <class T>
of the list. list<T>::list() void list<T>::insert_front()
{ {
template <class T> head=NULL; struct node <T>*t,*temp;
void list<T>:: display() } cout<<"Enter data into node:";
{ cin>>item;
struct node<T>*t; template <class T> temp=create_node(item);
void list<T>:: display() if(head==NULL)
if(head==NULL) { head=temp;
{ struct node<T>*t; else
cout<<"List is Empty\n"; { temp->link=head;
} if(head==NULL) head=temp;
else { }
{ t=head; cout<<"List is Empty\n"; }
while(t!=NULL) }
{ cout<<t->data<<"->"; else template <class T>
t=t->link; { t=head; void list<T>::delete_end()
} while(t!=NULL) {
} { cout<<t->data<<"->"; struct node<T>*cur,*prev;
} t=t->link; cur=prev=head;
} if(head==NULL)
Dynamic Implementation of list ADT } cout<<"List is Empty\n";
} else
#include<iostream.h> { cur=prev=head;
#include<stdlib.h> template <class T> if(head->link==NULL)
template <class T> struct node<T>* list<T>::create_node(int n) {
struct node {struct node<T> *t; cout<<"node "<<cur->data<<" Deletion is sucess";
{ t=new struct node<T>; free(cur);
T data; t->data=n; head=NULL;
struct node<T> *link; t->link=NULL; }
}; return t; else
template <class T> } { while(cur->link!=NULL)
class list { prev=cur;
{ template <class T> cur=cur->link;
int item; void list<T>::insert_end() }
struct node<T>*head; {struct node<T> *t,*temp; prev->link=NULL;
public: int n; cout<<"node "<<cur->data<<" Deletion is sucess";
list(); cout<<"Enter data into node:"; free(cur);
void display(); cin>>n; }
struct node<T>*create_node(int n); temp=create_node(n); }
void insert_end(); if(head==NULL) }
void insert_front(); head=temp;
void Insert_at_pos(int pos); else template <class T>
void delete_end(); { t=head; void list<T>::delete_front()
void delete_front(); while(t->link!=NULL) {
void Delete_at_pos(int pos); t=t->link; struct node<T>*t;
void Node_count(); t->link=temp; if(head==NULL)
}; } cout<<"List is Empty\n";
} else
{ t=head;
head=head->link;
class node
NULL 40 NULL t=head;
{ temp
public: while(t->next!=NULL)
int data; head is the pointer variable which contains address of the first node and temp contains address of new t=t->next;
node *prev; node to be inserted then sample code is t->next=temp;
node * next; temp->prev=t;
};
temp->next=head;
head->prev=temp;
NULL 10 20 30 NULL head=temp; head
template <class T> Code for insert front:- Code to insert a node at End:-
class dlist template <class T>
{ void DLL<T>::insert_front() template <class T>
int data; { void DLL<T>::insert_end()
struct dnode<T>*head; struct dnode <T>*t,*temp; {
public: cout<<"Enter data into node:"; struct dnode<T> *t,*temp;
dlist() cin>>data; int n;
{ temp=create_dnode(data); cout<<"Enter data into dnode:";
head=NULL; if(head==NULL) cin>>n;
} head=temp; temp=create_dnode(n);
void display(); else if(head==NULL)
struct dnode<T>*create_dnode(int n); { temp->next=head; head- head=temp;
void insert_end(); >prev=temp; else
void insert_front(); head=temp; { t=head;
void delete_end(); } while(t->next!=NULL)
void delete_front(); } t=t->next;
void dnode_count();
t->next=temp;
temp->prev=t; Code to insert a node at a position head is the pointer variable which contains address of the first node
}
} template <class T> sample code is
void dlist<T>::Insert_at_pos(int pos)
{ t=head;
case 3:Inserting at a give position struct dnode<T>*cr,*pr,*temp; head=head->next;
int count=1; head->prev=NULL;
cout<<"Enter data into dnode:"; cout<<"dnode "<<t->data<<" Deletion is sucess";
cin>>data; delete(t);
head temp=create_dnode(data);
display();
if(head==NULL)
NULL 10 20 30 NULL
{//when list is empty
head=temp; head
temp }
40 else
{ pr=cr=head; NULL 10 NULL 20 30 NULL
insert 40 at position 2 if(pos==1)
head is the pointer variable which contains address of the first node and temp contains address of new { //inserting at pos=1
node to be inserted then sample code is temp->next=head;
head=temp;
} code for deleting a node at front
else
while(count<pos) { template <class T>
{ count++; while(count<pos) void dlist<T>:: delete_front()
pr=cr; { count++; {struct dnode<T>*t;
cr=cr->next; pr=cr; if(head==NULL)
} cr=cr->next; cout<<"List is Empty\n";
pr->next=temp; } else
temp->prev=pr; pr->next=temp; { t=head;
temp->next=cr; temp->prev=pr; head=head->next;
cr->prev=temp; temp->next=cr; head->prev=NULL;
cr->prev=temp; cout<<"dnode "<<t->data<<" Deletion is sucess";
} delete(t);
} }
} }
head pr cr
Deletions: Removing an element from the list, without destroying the integrity of the list itself. Case 2. Delete a node at end of the list
To place an element from the list there are 3 cases : To deleted the last node find the last node. find the node using following code
NULL 10 20 30 NULL
1. Delete a node at beginning of the list
2. Delete a node at end of the list struct dnode<T>*pr,*cr;
3. Delete a node at a given position pr=cr=head;
NULL 40 NULL
while(cr->next!=NULL)
Case 1: Delete a node at beginning of the list { pr=cr;
temp cr=cr->next;
head }
pr->next=NULL;
cout<<"dnode "<<cr->data<<" Deletion is sucess";
NULL 10 20 30 NULL delete(cr);
cin>>data; { }
temp=create_dnode(data); while(count<pos) }
if(head==NULL) { count++; }
head=temp; pr=cr; template <class T>
else cr=cr->next; void dlist<T>::Delete_at_pos(int pos)
{ temp->next=head; head- } {
>prev=temp; pr->next=temp; struct dnode<T>*cr,*pr,*temp;
head=temp; temp->prev=pr; int count=1;
} temp->next=cr; display();
} cr->prev=temp; if(head==NULL)
template <class T> } {
void dlist<T>::insert_end() } cout<<"List is Empty\n";
{ } }
struct dnode<T> *t,*temp; else
int n; template <class T> { pr=cr=head;
cout<<"Enter data into dnode:"; void dlist<T>:: delete_front() if(pos==1)
cin>>n; {struct dnode<T>*t; {
temp=create_dnode(n); if(head==NULL) head=head->next;
if(head==NULL) cout<<"List is Empty\n"; head->prev=NULL;
head=temp; else cout<<cr->data <<"is deleted sucesfully";
else { display(); delete cr;
{ t=head; t=head; }
while(t->next!=NULL) head=head->next; else
t=t->next; head->prev=NULL; {
t->next=temp; cout<<"dnode "<<t->data<<" Deletion is sucess"; while(count<pos)
temp->prev=t; delete(t); { count++;
} } pr=cr;
} } cr=cr->next;
template <class T> }
void dlist<T>::delete_end() pr->next=cr->next;
template <class T> { cr->next->prev=pr;
void dlist<T>::Insert_at_pos(int pos) struct dnode<T>*pr,*cr; cout<<cr->data <<"is deleted sucesfully";
{ pr=cr=head; delete cr;
struct dnode<T>*cr,*pr,*temp; if(head==NULL) }
int count=1; cout<<"List is Empty\n"; }
cout<<"Enter data into dnode:"; else }
cin>>data; { cr=pr=head; template <class T>
temp=create_dnode(data); if(head->next==NULL) void dlist<T>::dnode_count()
display(); { {
if(head==NULL) cout<<"dnode "<<cr->data<<" Deletion is sucess"; struct dnode<T>*t;
{//when list is empty delete(cr); int count=0;
head=temp; head=NULL; display();
} } t=head;
else else if(head==NULL)
{ pr=cr=head; { while(cr->next!=NULL) cout<<"List is Empty\n";
if(pos==1) { pr=cr; else
{ //inserting at pos=1 cr=cr->next; { while(t!=NULL)
temp->next=head; } { count++;
head=temp; pr->next=NULL; t=t->next;
} cout<<"dnode "<<cr->data<<" Deletion is sucess"; }
else delete(cr); cout<<"node count is "<<count;
{ temp=create_cnode(data); //prev=cur;
struct cnode<T> *t; if(head==NULL) //cur=cur->link;
t=new struct cnode<T>; { prev->link=head;//points to head
t->data=n; head=temp; cout<<"cnode "<<cur->data<<" Deletion is sucess";
t->link=NULL; temp->link=temp; free(cur);
return t; } }
} else }
//Code to insert node at the end { }
template <class T> t=head; //Code to delete node at front
void clist<T>::insert_end() if(t->link==head) template <class T>
{ { void clist<T>::delete_front()
struct cnode<T>*t; t- >link=temp; {
struct cnode<T>*temp; temp->link=t; struct cnode<T>*t,*temp;
int n; } if(head==NULL)
cout<<"Enter data into cnode:"; else cout<<"circular list is Empty\n";
cin>>n; { else
temp=create_cnode(n); //code to find last node { t=head;
if(head==NULL) while(t->link!=head) //head=head->link;
{ { if(t->link==head)
head=temp; t=t->link; {
temp->link=temp; } head=NULL;
} t->link=temp; //linking last and first node cout<<"cnode "<<t->data<<" Deletion is sucess";
else temp->link=head; delete(t);
{ head=temp; }
t=head; else
if(t->link==head)// list containing only one node } {
{ } //code to find last node
t->link=temp; cout<<"Node inserted \n"; while(t->link!=head)
temp->link=t; } {
} t=t->link;
else //Code to delete node at end }
{ template <class T> temp=head;
while(t->link!=head) void clist<T>::delete_end() t->link=head->link; //linking last and first node
{ { cout<<"cnode "<<temp->data<<" Deletion is sucess";
t=t->link; struct cnode<T>*cur,*prev; head=head->link;
} cur=prev=head; delete(temp);
t->link=temp; if(head==NULL) }
temp->link=head; cout<<"clist is Empty\n"; }
} else }
} { cur=prev=head; //Code to count nodes in the circular linked list
cout<<"Node inerted"<<endl; if(cur->link==head) template <class T>
} { void clist<T>::cnode_count()
cout<<"cnode "<<cur->data<<" Deletion is sucess"; {
//Code to insert node at front free(cur); struct cnode<T>*t;
template <class T> head=NULL; int c=0;
void clist<T>::insert_front() } t=head;
{ else if(head==NULL)
struct cnode <T>*t; { while(cur->link!=head) {
struct cnode<T>*temp; { prev=cur; cout<<"circular list is Empty\n";
cout<<"Enter data into cnode:"; cur=cur->link;
cin>>data; } }
else Stack: Stack ADT, array and linked list implementation, Applications- expression conversion and
{ t=t->link; Popping an element from stack:
evaluation. Queue: Types of Queue: Simple Queue, Circular Queue, Queue ADT- array and linked
c++; To remove an item, first extract the data from top position in the stack and then decrement the
list implementation. Priority Queue, heaps.
while(t!=head) stack pointer, top.
{ c++; STACK ADT:- A Stack is a linear data structure where insertion and deletion of items takes place
t=t->link; at one end called top of the stack. A Stack is defined as a data structure which operates on a last-in
} first-out basis. So it is also is referred as Last-in First-out( LIFO).
cout<<"Node Count="<<c; Stack uses a single index or pointer to keep track of the information in the stack. The basic
operations associated with the stack are:
} a) push(insert) an item onto the stack.
b) pop(remove) an item from the stack.
}
int main() The general terminology associated with the stack is as follows:
{ A stack pointer keeps track of the current position on the stack. When an element is placed
int ch,pos; on the stack, it is said to be pushed on the stack. When an object is removed from the stack, it is //code to remove an element from stack
clist <int> L; said to be popped off the stack. Two additional terms almost always used with stacks are template<class T>
while(1) overflow, which occurs when we try to push more information on a stack that it can hold, and void stack<T>::pop()
{ underflow, which occurs when we try to pop an item off a stack which is empty. {
cout<<"\n ***Operations on Circular Linked clist***"<<endl; if(top= =-1)
cout<<"\n1.Insert cnode at End"<<endl; cout<<"Stack is Underflow";
cout<<"2.Insert Cnode at Front"<<endl; Pushing items onto the stack: else
cout<<"3.Delete Cnode at END"<<endl; {
cout<<"4.Delete Cnode at Front"<<endl; data=stk[top];
cout<<"5.Display Nodes "<<endl; top--;
cout<<"6.Cnode Count"<<endl; cout<<data<<" is poped Sucesfully ....\n";
cout<<"7.Exit "<<endl; }
cout<<"8.Clear Screen "<<endl; }
cout<<"Enter Your choice:";
cin>>ch; Assume that the array elements begin at 0 ( because the array subscript starts from 0)
switch(ch) and the maximum elements that can be placed in stack is max. The stack pointer, top, is considered to Static implementation of Stack ADT
{ be pointing to the top element of the stack. A push operation thus involves adjusting the stack pointer
case 1: L.insert_end(); to point to next free slot and then copying data into that slot of the stack. Initially the top is initialized #include<stdlib.h>
break; to -1.
#include<iostream.h>
case 2: L.insert_front();
#define max 4
break; //code to push an element on to stack;
template<class T>
case 3:L.delete_end(); template<class T>
class stack
break; void stack<T>::push()
{
case 4:L.delete_front(); {
private:
break; if(top==max-1)
int top;
case 5://display contents cout<<"Stack Overflow...\n";
T stk[max],data;
L.display(); else
public:
break; {
case 6: L.cnode_count(); stack();
cout<<"Enter an element to be pushed:";
break; void push();
top++;
case 7:exit(0); void pop();
cin>>data;
void display();
case 8:system("cls"); stk[top]=data;
break; };
cout<<"Pushed Sucesfully.... \n";
template<class T>
default:cout<<"Invalid choice"; }
stack<T>::stack()
} }
{
}
top=-1;
}
In priority queue, the elements are arranged in any order and out of which only the smallest or largest element 11 10 18 20
allowed to delete each time.
The implementation of priority queue can be done using arrays or linked list. The data structure heap is used
to implement the priority queue effectively.
APPLICATIONS: Max heap Min heap
1. The typical example of priority queue is scheduling the jobs in operating system. Typically OS allocates
priority to jobs. The jobs are placed in the queue and position of the job in priority queue determines their
Insertion of element in the Heap:
priority. In OS there are 3 jobs- real time jobs, foreground jobs and background jobs. The OS always
schedules the real time jobs first. If there is no real time jobs pending then it schedules foreground jobs. Lastly
Consider a max heap as given below:
if no real time and foreground jobs are pending then OS schedules the background jobs.
2. In network communication, the manage limited bandwidth for transmission the priority queue is used.
3. In simulation modeling to manage the discrete events the priority queue is used.
Various operations that can be performed on priority queue are-
1. Find an element
2. Insert a new element
3. Remove or delete an element
The abstract data type specification for a max priority queue is given below. The specification for a min priority
queue is the same as ordinary queue except while deletion, find and remove the element with minimum priority
For deletion operation always the maximum element is deleted from heap. In Max heap the maximum
18 element is always present at root. And if root element is deleted then we need to reheapify the tree.
12 7 inserted! 25
11 10 4 12 18
If we want to insert node 25, then as 25 is greatest element it should be the root. Hence 25 will bubble up and 18
will move down. 11 10 4
Thus deletion operation can be performed. The time complexity of deletion operation is O(log n).
25 inserted! 1. Remove the maximum element which is present at the root. Then a hole is created at the root.
Delete root element:25, Now we cannot put either 12 or 18 as root node and that should be greater than all its 2. Now reheapify the tree. Start moving from root to children nodes. If any maximum element is found then
children elements. place it at root. Ensure that the tree is satisfying the heap property or not.
3. Repeat the step 1 and 2 if any more elements are to be deleted.
18
Applications Of Heap:
Deletion of element from the heap: 1. Heap is used in sorting algorithms. One such algorithm using heap is known as heap sort.
HEAP SORT
Heap sort is a method in which a binary tree is used. In this method first the heap is created using binary tree and then
heap is sorted using priority queue.
Eg:
25 57 48 38 10 91 84 33
In the heap sort method we first take all these elements in the array “A”
Now start building the heap structure. In forming the heap the key point is build heap in such a way that the
highest value in the array will always be a root.
Insert 25
The next element is 84, which 91>84>57 the middle element. So 84 will be the parent of 57. For making the
complete binary tree 57 will be attached as right of 84.
Now the heap is formed. Let us sort it. For sorting the heap remember two main things the first thing is that the
binary tree form of the heap should not be distributed at all. For the complete sorting binary tree should be remained.
And the second thing is that we will start sorting the higher elements at the end of array in sorted manner i.e..
A[7]=91, A[6]=84 and so on..
Step 1:- Exchange A[0] with A[7]
// If largest is not root searching every element of the list till the required record is found. The elements in the list may be
Searching: Linear and binary search methods.
if (largest != i) in any order. i.e. sorted or unsorted.
Sorting: Bubble sort, selection sort, Insertion sort, Quick sort, Merge sort, Heap sort. Time complexities.
{ We begin search by comparing the first element of the list with the target element. If it
Graphs: Basic terminology, representation of graphs, graph traversal methods DFS, BFS.
swap(&arr[i], &arr[largest]); matches, the search ends and position of the element is returned. Otherwise, we will move to next
element and compare. In this way, the target element is compared with all the elements until a
match occurs. If the match do not occur and there are no more elements to be compared, we
// Recursively heapify the affected sub-tree ALGORITHMS conclude that target element is absent in the list by returning position as -1.
heapify(arr, n, largest); Definition: An Algorithm is a method of representing the step-by-step procedure for solving a
} problem. It is a method of finding the right answer to a problem or to a different problem by For example consider the following list of elements.
} breaking the problem into simple cases. 55 95 75 85 11 25 65 45
Suppose we want to search for element 11(i.e. Target element = 11). We first compare the
// function to do heap sort It must possess the following properties: target element with first element in list i.e. 55. Since both are not matching we move on the next
void heapSort(int arr[], int n) elements in the list and compare. Finally we will find the match after 5 comparisons at position 4
{ int i; 1. Finiteness: An algorithm should terminate in a finite number of steps. starting from position 0.
// Build heap (rearrange array) Linear search can be implemented in two ways.i)Non recursive ii)recursive
for ( i = n / 2 - 1; i >= 0; i--) 2. Definiteness: Each step of the algorithm must be precisely (clearly) stated.
heapify(arr, n, i);
Algorithm for Linear search
3. Effectiveness: Each step must be effective.i.e; it should be easily convertible into
// One by one extract an element from heap program statement and can be performed exactly in a finite amount of time.
for ( i=n-1; i>=0; i--) Linear_Search (A[ ], N, val , pos )
{ Step 1 : Set pos = -1 and k = 0
4. Generality: Algorithm should be complete in itself, so that it can be used to solve all
Step 2 : Repeat while k < N
// Move current root to end problems of given type for any input data.
Begin
swap(&arr[0], &arr[i]);
Step 3 : if A[ k ] = val
5. Input/Output: Each algorithm must take zero, one or more quantities as input data
Set pos = k
// call max heapify on the reduced heap and gives one of more output values.
print pos
heapify(arr, i, 0); An algorithm can be written in English like sentences or in any standard
Goto step 5
} representations. The algorithm written in English language is called Pseudo code.
End while
} Step 4 : print “Value is not present”
/* A utility function to print array of size n */ Example: To find the average of 3 numbers, the algorithm is as shown below.
Step 5 : Exit
void printArray(int arr[], int n) Step1: Read the numbers a, b, c, and d.
{ Step2: Compute the sum of a, b, and c.
for (int i=0; i<n; ++i) Step3: Divide the sum by 3. Non recursive C++ program for Linear search
cout << arr[i] << " "; Step4: Store the result in variable of d.
cout << "\n"; Step5: End the program.
} #include<iostream>
int main() using namespace std;
{ int Lsearch(int list[ ],int n,int key);
int n,i; int main()
int list[30]; {
cout<<"enter no of elements\n"; int n,i,key,list[25],pos;
cin>>n; Searching: Searching is the technique of finding desired data items that has been stored cout<<"enter no of elements\n";
cout<<"enter "<<n<<" numbers "; within some data structure. Data structures can include linked lists, arrays, search trees, hash cin>>n;
tables, or various other storage methods. The appropriate search algorithm often depends on the
for(i=0;i<n;i++) cout<<"enter "<<n<<" elements ";
data structure being searched. for(i=0;i<n;i++)
cin>>list[i];
Search algorithms can be classified based on their mechanism of searching. They are cin>>list[i];
heapSort(list, n);
Linear searching cout<<"enter key to search";
cout << "Sorted array is \n";
printArray(list, n); Binary searching cin>>key;
return 0; Linear or Sequential searching: Linear Search is the most natural searching method and pos= Lsearch (list,n,key);
} It is very simple but very poor in performance at times .In this method, the searching begins with if(pos==-1)
cout<<"\nelement not found";
else
Page 1 Page 2
66 67 68
UNIT -3 UNIT -3 UNIT -3
cout<<"\n element found at index "<<pos; /*recursive function for linear search*/
} int Rec_Lsearch(int list[],int n,int key)
/*function for linear search*/ {
int Lsearch(int list[ ],int n,int key) if(n<0)
{ return -1;
int i,pos=-1; if(list[n]==key)
for(i=0;i<n;i++) return n;
if(key==list[i]) else
{ return Rec_Lsearch(list,n-1,key);
pos=i; }
break;
} RUN1:
return pos; enter no of elements 5
} enter 5 elements 5 55 -4 99 7
enter key to search-4
Run 1: element found at index 2
enter no of elements 5
enter 5 elements 99 88 7 2 4 RUN 2:
enter key to search 7 enter no of elements 5 Algorithm:
element found at index 2 enter 5 elements 5 55 -4 99 7 Binary_Search (A [ ], U_bound, VAL)
enter key to search77 Step 1 : set BEG = 0 , END = U_bound , POS = -1
Run 2: element not found Step 2 : Repeat while (BEG <= END )
enter no of elements 5 Step 3 : set MID = ( BEG + END ) / 2
enter 5 elements 99 88 7 2 4 Step 4 : if A [ MID ] == VAL then
enter key to search 88 POS = MID
element not found print VAL “ is available at “, POS
BINARY SEARCHING GoTo Step 6
End if
Binary search is a fast search algorithm with run-time complexity of Ο(log n). This search if A [ MID ] > VAL then
algorithm works on the principle of divide and conquer. Binary search looks for a particular item set END = MID – 1
Recursive C++ program for Linear search Else
by comparing the middle most item of the collection. If a match occurs, then the index of item is
returned. If the middle item is greater than the item, then the item is searched in the sub-array to set BEG = MID + 1
#include<iostream> the left of the middle item. Otherwise, the item is searched for in the sub-array to the right of the End if
using namespace std; middle item. This process continues on the sub-array as well until the size of the subarray reduces End while
int Rec_Lsearch(int list[ ],int n,int key); to zero. Step 5 : if POS = -1 then
int main() Before applying binary searching, the list of items should be sorted in ascending or print VAL “ is not present “
{ descending order. End if
int n,i,key,list[25],pos; Best case time complexity is O(1) Step 6 : EXIT
cout<<"enter no of elements\n"; Worst case time complexity is O(log n)
cin>>n;
cout<<"enter "<<n<<" elements ";
for(i=0;i<n;i++)
cin>>list[i]; Non recursive C++ program for binary search
cout<<"enter key to search";
cin>>key; #include<iostream>
pos=Rec_Lsearch(list,n-1,key); using namespace std;
if(pos==-1) int binary_search(int list[],int key,int low,int high);
cout<<"\nelement not found"; int main()
else {
cout<<"\n element found at index "<<pos; int n,i,key,list[25],pos;
} cout<<"enter no of elements\n" ;
RUN 1:
enter no of elements 5
enter 5 numbers 55 44 33 22 11
after sorting 11 22 33 44 55
Quick sort
Quick sort: It is a divide and conquer algorithm. Developed by Tony Hoare in 1959. Quick sort
first divides a large array into two smaller sub-arrays: the low elements and the high elements.
Quick sort can then recursively sort the sub-arrays.
ALGORITHM:
a) Start with just one element. One element will always satisfy heap property. /* A utility function to print array of size n */
b) Insert next elements and make this heap. void printArray(int arr[], int n)
c) Repeat step b, until all elements are included in the heap. {
Steps of Sorting: for (int i=0; i<n; ++i)
a) Exchange the root and last element in the heap. cout << arr[i] << " ";
b) Make this heap again, but this time do not include the last node. cout << "\n";
c) Repeat steps a and b until there is no element left. }
int main()
C++ program for implementation of Heap Sort {
int n,i;
#include <iostream> int list[30];
using namespace std; cout<<"enter no of elements\n";
// To heapify a subtree rooted with node i which is cin>>n;
// an index in arr[]. n is size of heap cout<<"enter "<<n<<" numbers ";
void heapify(int arr[], int n, int i) for(i=0;i<n;i++)
{ cin>>list[i];
int largest = i; // Initialize largest as root heapSort(list, n);
int L= 2*i + 1; // left = 2*i + 1 cout << "Sorted array is \n";
int R= 2*i + 2; // right = 2*i + 2 printArray(list, n);
Terminology of Graph
Graphs:-
A graph G is a discrete structure consisting of nodes (called vertices) and lines joining the nodes
(called edges). Two vertices are adjacent to each other if they are joint by an edge. The edge
joining the two vertices is said to be an edge incident with them. We use V (G) and E(G) to
denote the set of vertices and edges of G respectively.
Graph Representations
Graph data structure is represented using following representations...
1. Adjacency Matrix
2. Incidence Matrix
3. Adjacency List
Adjacency Matrix
In this representation, graph can be represented using a matrix of size total number of vertices by total
number of vertices. That means if a graph with 4 vertices can be represented using a matrix of 4X4 class.
In this matrix, rows and columns both represents vertices. This matrix is filled with either 1 or 0. Here, 1
represents there is an edge from row vertex to column vertex and 0 represents there is no edge from row
vertex to column vertex. This recursive nature of DFS can be implemented using stacks. The basic idea is as follows:
For example, consider the following directed graph representation implemented using linked Pick a starting node and push all its adjacent nodes into a stack.
For example, consider the following undirected graph representation... list... Pop a node from stack to select the next node to visit and push all its adjacent nodes into a stack.
Repeat this process until the stack is empty. However, ensure that the nodes that are visited are marked.
This will prevent you from visiting the same node more than once. If you do not mark the nodes that are
visited and you visit the same node more than once, you may end up in an infinite loop.
DFS-recursive(G, s):
Incidence Matrix mark s as visited
In this representation, graph can be represented using a matrix of size total number of vertices for all neighbours w of s in Graph G:
by total number of edges. That means if a graph with 4 vertices and 6 edges can be if w is not visited:
Graph traversals DFS-recursive(G, w)
represented using a matrix of 4X6 class. In this matrix, rows represents vertices and columns
represents edges. This matrix is filled with either 0 or 1 or -1. Here, 0 represents row edge is Graph traversal means visiting every vertex and edge exactly once in a well-defined order. While using
not connected to column vertex, 1 represents row edge is connected as outgoing edge to certain graph algorithms, you must ensure that each vertex of the graph is visited exactly once. The order
column vertex and -1 represents row edge is connected as incoming edge to column vertex. in which the vertices are visited are important and may depend upon the algorithm or question that you
are solving.
For example, consider the following directed graph representation...
During a traversal, it is important that you track which vertices have been visited. The most common way
of tracking vertices is to mark them.
Here, the word backtrack means that when you are moving forward and there are no more nodes along
the current path, you move backwards on the same path to find nodes to traverse. All the nodes will be
visited on the current path till all the unvisited nodes have been traversed after which the next path will be
Adjacency List selected.
In this representation, every vertex of graph contains list of its adjacent vertices.
public:
dictionary(); If we insert <3,15> then we have to search for it proper position by comparing key value.
void insert_d( );
void delete_d( ); (curr->key < New->key) is false. Hence else part will get executed.
void display_d( );
void length();
}; 1 10 4 20 7 80 NULL
void dictionary::insert_d( )
{
node *p,*curr,*prev;
cout<<"Enter an key and value to be inserted:";
cin>>k;
cin>>data;
CHAINING The next record key is 9. According to decision hash function it demands for the home bucket 9.
Initially, we will put the following keys in the hash table. Hence we will place 9 at index 9. Now the next final record key 29 and it hashes a key 9. But
In collision handling method chaining is a concept which introduces an additional field with data We will use Division hash function. That means the keys are placed using the formula home bucket 9 is already occupied. And there is no next empty bucket as the table size is limited
i.e. chain. A separate chain table is maintained for colliding data. When collision occurs then a to index 9. The overflow occurs. To handle it we move back to bucket 0 and is the location over
linked list(chain) is maintained at the home bucket. H(key) = key % tablesize there is empty 29 will be placed at 0th index.
H(key) = key % 10 Problem with linear probing:
For eg; One major problem with linear probing is primary clustering. Primary clustering is a process in
For instance the element 131 can be placed at which a block of data is formed in the hash table when collision is resolved.
Consider the keys to be placed in their home buckets are Key
131, 3, 4, 21, 61, 7, 97, 8, 9 H(key) = 131 % 10
39
=1 19%10 = 9 cluster is formed
then we will apply a hash function as H(key) = key % D 18%10 = 8 29
Index 1 will be the home bucket for 131. Continuing in this fashion we will place 4, 8, 7. 39%10 = 9 8
Where D is the size of table. The hash table will be- 29%10 = 9
Now the next key to be inserted is 21. According to the hash function 8%10 = 8
Here D = 10
H(key)=21%10 rest of the table is empty
H(key) = 1
0 this cluster problem can be solved by quadratic probing.
1 131 21 But the index 1 location is already occupied by 131 i.e. collision occurs. To resolve this collision
61 NULL
we will linearly move down and at the next empty location we will prob the element. Therefore 18
21 will be placed at the index 2. If the next element is 5 then we get the home bucket for 5 as
3 NULL QUADRATIC PROBING: 19
index 5 and this bucket is empty so we will put the element 5 at index 5.
61 NULL Quadratic probing operates by taking the original hash value and adding successive values of an
131
arbitrary quadratic polynomial to the starting value. This method uses following formula.
Index Key Key Key
7 97 NULL
NULL NULL NULL H(key) = (Hash(key) + i2) % m)
0
131 131 131 where m can be table size or any prime number.
1
NULL 21 21 for eg; If we have to insert following elements in the hash table with table size 10:
A chain is maintained for colliding elements. for instance 131 has a home bucket (key) 1. 2
similarly key 21 and 61 demand for home bucket 1. Hence a chain is maintained at index 1. NULL NULL 31 37, 90, 55, 22, 17, 49, 87 0 90
3 1 11
OPEN ADDRESSING – LINEAR PROBING 4 4 4 37 % 10 = 7 2 22
4 90 % 10 = 0 3
This is the easiest method of handling collision. When collision occurs i.e. when two records NULL 5 5 55 % 10 = 5 4
demand for the same home bucket in the hash table then collision can be solved by placing the 5 22 % 10 = 2 55
5
second record linearly down whenever the empty bucket is found. When use linear probing (open NULL NULL 61 11 % 10 = 1 6
addressing), the hash table is represented as a one-dimensional array with indices that range from 6
7 37
0 to the desired table size-1. Before inserting any elements into this table, we must initialize the 7 7 7 Now if we want to place 17 a collision will occur as 17%10 = 7 and 8
table to represent the situation where all slots are empty. This allows us to detect overflows and 7 bucket 7 has already an element 37. Hence we will apply 9
collisions when we inset elements into the table. Then using some suitable hash function the 8 8 8 quadratic probing to insert this record in the hash table.
element can be inserted into the hash table. 8
NULL NULL NULL Hi (key) = (Hash(key) + i2) % m
For example: 9
Consider i = 0 then
Consider that following keys are to be inserted in the hash table (17 + 02) % 10 = 7
after placing keys 31, 61
131, 4, 8, 7, 21, 5, 31, 61, 9, 29
(17 + 12) % 10 = 8, when i =1 Now if 17 to be inserted then In such situations, we have to transfer entries from old table to the new table by re computing
Key their positions using hash functions.
The bucket 8 is empty hence we will place the element at index 8. 0 90 H1(17) = 17 % 10 = 7 90
Then comes 49 which will be placed at index 9. 1 11 H2(key) = M – (key % M) Consider we have to insert the elements 37, 90, 55, 22, 17, 49, and 87. the table size is 10 and will
17
2 22 use hash function.,
49 % 10 = 9 3 Here M is prime number smaller than the size of the table. Prime number 22
1. This technique provides the programmer a flexibility to enlarge the table size if required.
2. Only the space gets doubled with simple hash function which avoids occurrence of
collisions.
1 = 001 Thus the data is inserted using extensible hashing.
EXTENSIBLE HASHING 0 1
4 = 100 Deletion Operation:
Extensible hashing is a technique which handles a large amount of data. The data to be (0) (1)
placed in the hash table is by extracting certain number of bits. 5 = 101 If we wan tot delete 10 then, simply make the bucket of 10 empty.
Extensible hashing grow and shrink similar to B-trees. 100 001
In extensible hashing referring the size of directory the elements are to be placed in 010 Based on last bit the data
buckets. The levels are indicated in parenthesis. is inserted. 00 01 10 11
00 01 10 11
Step 1: Insert 1, 4 Delete 8. Remove entry from directory 00.
(2)
1 = 001
0 (1)
001 111
4 = 100 100
010 00 00 10 11
(0) 1000
We will examine last bit
001 (1) (1)
of data and insert the data Step 4: Insert 1 0
010
in bucket. 100 001
101
Applications of hashing:
Page 18 Page 20
111 112 113
UNIT -4 Binary Search Trees: Various Binary tree representation, definition, BST ADT, Implementation, 4. Internal nodes: The nodes other than the root node and the leaves are called the internal nodes. Eg:
Operations- Searching, Insertion and Deletion, Binary tree traversals, threaded binary trees,
B, C, D, G
AVL Trees : Definition, Height of an AVL Tree, Operations – Insertion, Deletion and Searching
B-Trees: B-Tree of order m, height of a B-Tree, insertion, deletion and searching, B+ Tree. 5. Parent nodes: The node which is having further sub-trees(branches) is called the parent node of
1. In compilers to keep track of declared variables.
2. For online spelling checking the hashing functions are used. those sub-trees. Eg: B is the parent node of E and F.
3. Hashing helps in Game playing programs to store the moves made.
6. Predecessor: While displaying the tree, if some particular node occurs previous to some other node
4. For browser program while caching the web pages, hashing is used. TREES
5. Construct a message authentication code (MAC) then that node is called the predecessor of the other node. Eg: E is the predecessor of the node B.
6. Digital signature. A Tree is a data structure in which each element is attached to one or more elements directly beneath it.
7. Successor: The node which occurs next to some other node is a successor node. Eg: B is the
7. Time stamping
8. Key updating: key is hashed at specific intervals resulting in new key successor of E and F.
Level 0
A 8. Level of the tree: The root node is always considered at level 0, then its adjacent children are
supposed to be at level 1 and so on. Eg: A is at level 0, B,C,D are at level 1, E,F,G,H,I,J are at level 2,
K,L are at level 3.
9. Height of the tree: The maximum level is the height of the tree. Here height of the tree is 3. The
B 1 height if the tree is also called depth of the tree.
C D
10. Degree of tree: The maximum degree of the node is called the degree of the tree.
E F G BINARY TREES
H I J
2 Binary tree is a tree in which each node has at most two children, a left child and a right child. Thus the
K L 3 order of binary tree is 2.
Page 21
114 Page 1 115 Page 2 116
2. Right skewed binary tree: If the left sub-tree is missing in every node of a tree we call it is right Disadvantages of linked representation:
sub-tree.
1. This representation does not provide direct access to a node and special algorithms are
A required.
2. This representation needs additional space in each node for storing the left and right sub-
trees.
B
TRAVERSING A BINARY TREE
C Traversing a tree means that processing it so that each node is visited exactly once. A binary
tree can be
3. Complete binary tree: traversed a number of ways.The most common tree traversals are
The tree in which degree of each node is at the most two is called a complete binary tree. In
a complete binary tree there is exactly one node at level 0, two nodes at level 1 and four nodes at level
l In-order
2 and so on. So we can say that a complete binary tree depth d will contain exactly 2 nodes at each Pre-order and
level l, where l is from 0 to d.
Post-order
A
Pre-order 1.Visit the root Root | Left | Right
Advantages of sequential representation: 2.Traverse the left sub tree in pre-order
The only advantage with this type of representation is that the 3.Traverse the right sub tree in pre-order.
B C direct access to any node can be possible and finding the parent or left children of any particular node In-order 1.Traverse the left sub tree in in-order Left | Root | Right
is fast because of the random access. 2.Visit the root
3.Traverse the right sub tree in in-order.
Disadvantages of sequential representation: Post-order 1.Traverse the left sub tree in post-order Left | Right | Root
D E F G 1. The major disadvantage with this type of representation is wastage of memory. For example in 2.Traverse the right sub tree in post-order.
the skewed tree half of the array is unutilized.
3.Visit the root
Note: 2. In this type of representation the maximum depth of the tree has to be fixed. Because we have
n decide the array size. If we choose the array size quite larger than the depth of the tree, then it
1. A binary tree of depth n will have maximum 2 -1 nodes. will be wastage of the memory. And if we coose array size lesser than the depth of the tree then A
2. A complete binary tree of level l will have maximum 2l nodes at each level, where l starts from 0. we will be unable to represent some part of the tree.
3. Any binary tree with n nodes will have at the most n+1 null branches. 3. The insertions and deletion of any node in the tree will be costlier as other nodes has to be B C
4. The total number of edges in a complete binary tree with n terminal nodes are 2(n-1). adjusted at appropriate positions so that the meaning of binary tree can be preserved.
As these drawbacks are there with this sequential type of representation, we will search for more
Binary Tree Representation flexible representation. So instead of array we will make use of linked list to represent the tree.
D E F G
b) Linked Representation
A binary tree can be represented mainly in 2 ways: Linked representation of trees in memory is implemented using pointers. Since each node in a
binary tree can have maximum two children, a node in a linked representation has two pointers for both
left and right child, and one information field. If a node does not have any child, the corresponding H I J
a) Sequential Representation
pointer field is made NULL pointer.
b) Linked Representation
In linked list each node will look like this:
a) Sequential Representation K
The simplest way to represent binary trees in memory is the sequential representation that uses one- Left Child Data Right Child The pre-order traversal is: ABDEHCFGIKJ
dimensional array. The in-order traversal is : DBHEAFCKIGJ
Advantages of linked representation:
1) The root of binary tree is stored in the 1 st location of array
th 1. This representation is superior to our array representation as there is no wastage of The post-order traversal is:DHEBFKIJGCA
2) If a node is in the j location of array, then its left child is in the location 2J+1 and its right memory. And so there is no need to have prior knowledge of depth of the tree.
child in the location 2J+2 Using dynamic memory concept one can create as much memory(nodes) as
d+1 required. By chance if some nodes are unutilized one can delete the nodes by
The maximum size that is required for an array to store a tree is 2 -1, where d is the depth of the tree.
making the address free.
2. Insertions and deletions which are the most common operations can be done without
moving the nodes.
C Print this
E
at the last
st Operations On Binary Search Tree:
Print 1
The basic operations which can be performed on binary search tree are.
1. Insertion of a node in binary search tree.
C-B-A-D-E is the inorder traversal i.e. first we go towards the leftmost node. i.e. C so print that node
C. Then go back to the node B and print B. Then root node A then move towards the right sub-tree 2. Deletion of a node from binary search tree.
print D and finally E. Thus we are following the tracing sequence of Left|Root|Right. This type of 3. Searching for a particular node in binary search tree.
traversal is called inorder traversal. The basic principle is to traverse left sub-tree then root and then the Insertion of a node in binary search tree.
right sub-tree. While inserting any node in binary search tree, look for its appropriate position in the binary search
tree. We start comparing this new node with each node of the tree. If the value of the node which is
to be inserted is greater than the value of the current node we move on to the right sub-branch
Pseudo Code: otherwise we move on to the left sub-branch. As soon as the appropriate position is found we
From figure the postorder traversal is C-D-B-E-A. In the postorder traversal we are following the
Left|Right|Root principle i.e. move to the leftmost node, if right sub-tree is there or not if not then attach this new node as left or right child appropriately.
template <class T>
void inorder(bintree<T> *temp) print the leftmost node, if right sub-tree is there move towards the right most node. The key idea
{ here is that at each sub-tree we are following the Left|Right|Root principle and print the data
if(temp!=NULL) accordingly.
{ Pseudo Code:
inorder(temp->left);
cout<<”temp->data”; template <class T>
inorder(temp->right); void postorder(bintree<T> *temp)
} {
} if(temp!=NULL)
{
postorder(temp->left);
postorder(temp->right);
cout<<”temp->data”;
}
}
Before Insertion
In the above fig, if we wan to insert 23. Then we will start comparing 23 with value of root node
BINARY SEARCH TREE
i.e. 10. As 23 is greater than 10, we will move on right sub-tree. Now we will compare 23 with 20
In the simple binary tree the nodes are arranged in any fashion. Depending on user’s desire
and move right, compare 23 with 22 and move right. Now compare 23 with 24 but it is less than
is the preorder traversal of the above fig. We are following Root|Left|Right path i.e. data at the the new nodes can be attached as a left or right child of any desired node. In such a case finding for
any node is a long cut procedure, because in that case we have to search the entire tree. And thus 24. We will move on left branch of 24. But as there is node as left child of 24, we can attach 23 as
root node will be printed first then we move on the left sub-tree and go on printing the data till
the searching time complexity will get increased unnecessarily. So to make the searching left child of 24.
we reach to the left most node. Print the data at that node and then move to the right sub- tree.
Follow the same principle at each sub-tree and go on printing the data accordingly. algorithm faster in a binary tree we will go for building the binary search tree. The binary search
tree is based on the binary search algorithm. While creating the binary search tree the data is
template <class T> systematically arranged. That means values at left sub-tree < root node value < right sub-tree
void preorder(bintree<T> *temp) values.
This is the simplest deletion, in which we set the left or right pointer of parent node as NULL.
10
7 15
Before deletion
5 9 12 18
Deletion of a node having two children. Searching for a node in binary search tree.
From the above fig, we want to delete the node having value 5 then we will set left pointer of its parent
node as NULL. That is left pointer of node having value 7 is set to NULL. Consider a tree as given below. In searching, the node which we want to search is called a key node. The key node will be compared
with each node starting from root node if value of key node is greater than current node then we
search for it on right sub branch otherwise on left sub branch. If we reach to leaf node and still we do
not get the value of key node then we declare “node is not present in the tree”.
> 2Nh-2
> 4Nh-4
.
.
> 2iNh-2i
Definition of Balance Factor: The AVL tree follows the property of binary search tree. In fact AVL trees are
basically binary search trees with balance factors as -1, 0, or +1.
The balance factor BF(T) of a node in binary tree is defined to be hL-hR where hL and hR Height of AVL Tree: After insertion of any node in an AVL tree if the balance factor of any node
are heights of left and right sub trees of T. becomes other than -1, 0, or +1 then it is said that AVL property is violated. Then
Theorem: The height of AVL tree with n elements (nodes) is O(log n). we have to restore the destroyed balance condition. The balance factor is denoted at
For any node in AVL tree the balance factor i.e. BF(T) is -1, 0 or +1. right top corner inside the node.
Proof: Let an AVL tree with n nodes in it. Nh be the minimum number of nodes in an AVL tree of
height h.
In worst case, one sub tree may have height h-1 and other sub tree may have height h-2. And both these
sub trees are AVL trees. Since for every node in AVL tree the height of left and right sub trees differ
by at most 1.
Hence
Nh = Nh-1+Nh-2+1
N0=0 N1=2
There are four different cases when rebalancing is required after insertion of new node. When node ‘4’ gets attached as right child of node ‘C’ then node ‘A’ gets unbalanced. The rotation
which needs to be applied is RR rotation as shown in fig.
1. An insertion of new node into left sub tree of left child. (LL).
2. An insertion of new node into right sub tree of left child. (LR).
3. An insertion of new node into left sub tree of right child. (RL).
4. An insertion of new node into right sub tree of right child.(RR).
Some modifications done on AVL tree in order to rebalance it is called rotations of AVL tree
After insertion of a new node if balance condition gets destroyed, then the nodes on that
path(new node insertion point to root) needs to be readjusted. That means only the affected sub Right-Right(RR rotation) Right-Left(RL rotation)
tree is to be rebalanced.
The rebalancing should be such that entire tree should satisfy AVL property.
In above given example- Insertion Algorithm:
1. Insert a new node as new leaf just as an ordinary binary search tree.
2. Now trace the path from insertion point(new node inserted as leaf) towards root. For each node
‘n’ encountered, check if heights of left (n) and right (n) differ by at most 1.
a) If yes, move towards parent (n).
b) Otherwise restructure by doing either a single rotation or a double rotation.
Thus once we perform a rotation at node ‘n’ we do not require to perform any rotation at any
ancestor on ‘n’.
To insert node ‘1’ we have to attach it as a left child of ‘2’. This will unbalance the tree as follows.
We will apply LL rotation to preserve AVL property of it.
Insert 28
When node ‘3’ is attached as a right child of node ‘C’ then unbalancing occurs because of LR. The node ‘28’ is attached as a right child of 25. RR rotation is required to rebalance.
Hence LR rotation needs to be applied.
When node ‘2’ is attached as a left child of node ‘C’ then node ‘A’ gets unbalanced as its balance
factor becomes -2. Then RL rotation needs to be applied to rebalance the AVL tree.
Example:
Insert 25
Insert 1, 25, 28, 12 in the following AVL tree. We will attach 25 as a right child of 18. No balancing is required as entire tree preserves the AVL
property
Even after deletion of any particular node from AVL tree, the tree has to be restructured in order to
preserve AVL property. And thereby various rotations need to be applied.
Definition:
A B tree of order m is an m-way search tree and hence may be empty. If non empty, then the following
properties are satisfied on its extended tree representation:
i. The root node must have at least two child nodes and at most m child nodes.
ii. All internal nodes other than the root node must have at least |m/2 | non empty child nodes and at most Step 2: Insert 8, Since the node is full split the node at medium 1, 3, 7, 8, 14
m non empty child nodes.
iii. The number of keys in each internal node is one less than its number of child nodes and these keys
partition the keys of the tree into sub trees. 7
iv. All external nodes are at the same level.
v.
Example:
F K O B tree of order 4
1 3 8 14
Level 1
Searching:
The searching of a node in an AVL tree is very simple. As AVL tree is basically binary search tree, the C D G M N P Q W Step 3: Insert 5, 11, 17 which can be easily inserted in a B-tree.
algorithm used for searching a node from binary search tree is the same one is used to search a node
from AVL tree. 7
S T X Y Z
Level 1 3 5 8 11 14 17
BTREES 3
Multi-way trees are tree data structures with more than two branches at a node. The data
structures of m-way search trees, B trees and Tries belong to this category of tree
structures.
AVL search trees are height balanced versions of binary search trees, provide efficient Insertion
retrievals and storage operations. The complexity of insert, delete and search operations on For example construct a B-tree of order 5 using following numbers. 3, 14, 7, 1, 8, 5, 11, 17, 13, 6, 23, 12,
AVL search trees id O(log n). 20, 26, 4, 16, 18, 24, 25, 19 Step 4: Now insert 13. But if we insert 13 then the leaf node will have 5 keys which is not allowed. Hence
Applications such as File indexing where the entries in an index may be very large, The order 5 means at the most 4 keys are allowed. The internal node should have at least 3 non empty 8,
maintaining the index as m-way search trees provides a better option than AVL search trees children and each leaf node must contain at least 2 keys. 11, 13, 14, 17 is split and medium node 13 is moved up.
which are but only balanced binary search trees.
While binary search trees are two-way search trees, m-way search trees are extended binary
search trees and hence provide efficient retrievals.
B trees are height balanced versions of m-way search trees and they do not recommend Step 1: Insert 3, 14, 7, 1
representation of keys with varying sizes. 7 13
Tries are tree based data structures that support keys with varying sizes. 1 3 7 14
1 3 5 8 11 14 17
.
Page 25 Page 26
Page 24 138 139 140
UNIT -5 UNIT -5 UNIT -5
Step 7: Insertion of node 4 causes left most node to split. The 1, 3, 4, 5, 6 causes key 4 to move up.
Then insert 16, 18, 24, 25.
Delete 8, then it is very simple.
13
4 7 13 20
4 7 17 20
1 3 5 6 11 12 14 16 18 19 23 24 25 26
Step 8: Finally insert 19. Then 4, 7, 13, 19, 20 needs to be split. The median 13 will be moved up to
from a root node.
The tree then will be -
1 3 5 6 8 11 12 14 17 20 23 13
Now we will delete 20, the 20 is not in a leaf node so we will find its successor which is 23, Hence 23
will be moved up to replace 20.
4 7 17 20 13
Step 6: The 26 is inserted to the right most leaf node. Hence 14, 17, 20, 23, 26 the node is split and 20 will be
moved up.
4 7 17 23
7 13 20 1 3 5 6 8 11 12 14 16 18 19 23 24 25 26
4 7 17 20
Next we will delete 18. Deletion of 18 from the corresponding node causes the node with only one
key, which is not desired (as per rule 4) in B-tree of order 5. The sibling node to immediate right has
an extra key. In such a case we can borrow a key from parent and move spare key of sibling up.
1 3 5 6 8 11 12 14 16 18 19 23 24 25 26
13
7 13 17 24
The running time of search operation depends upon the height of the tree. It is O(log n).
Height of B-tree
4 7 17 24
The maximum height of B-tree gives an upper bound on number of disk access. The maximum number of
1 3 4 6 11 12 14 16 19 23 25 26 keys in a B-tree of order 2m and depth h is
2 h-1
1 + 2m + 2m(m+1) + 2m(m+1) + . . .+ 2m(m+1)
h
1 3 5 6 11 12 14 16 19 23 25 26 i-1
= 1 + ∑ 2m(m+1)
i=1
Searching The maximum height of B-tree with n keys
The search operation on B-tree is similar to a search to a search on binary search tree. Instead of choosing log m+1 n = O(log n)
Now delete 5. But deletion of 5 is not easy. The first thing is 5 is from leaf node. Secondly this leaf between a left and right child as in binary tree, B-tree makes an m-way choice. Consider a B-tree as given 2m
node has no extra keys nor siblings to immediate left or right. In such a situation we can combine this below.
node with one of the siblings. That means remove 5 and combine 6 with the node 1, 3. To make the tree
balanced we have to move parent’s key down. Hence we will move 4 down as 4 is between 1, 3, and 6. 13
The tree will be-
13
4 7
17
7 17 24 20
1 3 5 6 8 11 12 14 16 18 19 23 24 25 26
1 3 4 6 11 12 14 16 19 23 25 26
But again internal node of 7 contains only one key which not allowed in B-tree. We then will try to borrow
a key from sibling. But sibling 17, 24 has no spare key. Hence we can do is that, combine 7 with 13 and 17, If we want to search 11 then
24. Hence the B-tree will be
i. 11 < 13 ; Hence search left node