Ds Internal 2 Materials
Ds Internal 2 Materials
Ds Internal 2 Materials
STUDY MATERIALS
UNIT – II
Queue ADT – Operations – Circular Queue – Priority Queue – deQueue – applications of
queues.
PREPARED BY
M.SIVAKUMAR, AP/CSE
SRI ESHWAR COLLEGE OF ENGINEERING,
COIMBATORE - 641202
1
QUEUE ADT
Definition
Queue is a linear data structure where the first element is inserted from one end called REAR and
deleted from the other end called as FRONT
Features:
1. It is an abstract data type
2. It follows First In First Out property
3. It has three components:
i). actual data ii).front iii).rear
3. Insertion is done using rear and deletion is happened using front
Real-time Examples:
Queue of processes in OS.
Queue of people at any service point such as ticketing etc.
Queue of packets in data communication.
Queue of air planes waiting for landing instructions.
Diagrammatic Representation:
Uses:
Breadth-first search uses a queue to keep track of the nodes to visit next
Printers use queues to manage jobs—jobs get printed in the order they're submitted
Web servers use queues to manage requests—page requests get fulfilled in the order they're
received
Processes wait in the CPU scheduler's queue for their turn to run
Types of Queue
1. Linear Queue
2. Circular Queue
3. Priority Queue
4. Double Ended Queue [ Dequeue]
Implementation
The queue can be implemented in two ways:
Array
Linked list
2
i). Enqueue
- Check if the queue is full or not.
- If the queue is full, then print overflow.
- If the queue is not full, then increment the rear by 1 and
add the element
Code:
printf(“Enter the element to be inserted:”);
scanf(“%d”, &ele);
if(rear==-1) // If there is not element
{
front=rear=0;
Before Insertion
queue[rear]=ele;
}
else if(rear==MAX-1) // Checks for places
{
printf("\n QUEUE is full.");
return;
}
else // Insert new element using rear
{
rear++;
After Insertion
queue[rear]=ele;
}
ii). Dequeue
- Check if the queue is empty or not.
- If the queue is empty, then print underflow.
- If the queue is not empty, then print the element using ‘front’ and increment the front by 1.
Code:
if(front==-1) // Checks for empty queue
{
printf("QUEUE is Empty.");
return;
}
else if(front==rear) // checks for single element
{
ele=queue[front]; Before Deletion
front=rear=-1;
}
else // Delete an element by incrementing front
{
ele=queue[front];
front++;
} After Deletion
printf("\n Deleted item is : %d.", ele);
iii). Display
- Check if the queue is empty or not
- If the queue is empty, then print ‘Queue is empty”
- If the queue is not empty, then print the element using from front and stop till rear
if(rear==-1)
printf("\nQUEUE is Empty.");
else{
for(i=front;i<=rear;i++)
printf("%d,",queue[i]);
}
3
QUEUE [USING LINKED LIST]
Queue can be implemented using an linked list, where the size of an queue will be dynamic
It uses ‘rear’ and ‘front’ variable for insertion and deletion
Major Operations:
i). Enqueue [Insertion]
ii). Dequeue [Deletion]
iii). Display
Global declaration:
struct Node
{
int data;
struct Node *next;
}*front = NULL,*rear = NULL;
i). Enqueue
- Create a new node ‘n’ with given value and set 'n → next' to NULL.
- Check whether queue is Empty (rear == NULL)
- If it is Empty then, set front = n and rear = n.
- If it is Not Empty then, set rear → next = n and rear = n
Code:
struct Node *n;
n = (struct Node*)malloc(sizeof(struct Node));
n->data = value;
n -> next = NULL;
if(front == NULL)
front = rear = n;
else{
rear -> next = n;
rear = n;
} After insertion
Insert 20
ii). Dequeue
- Check whether queue is Empty (front == NULL)
- If it is Empty, then display "Queue is Empty!!! Deletion is not possible!!!"
- If it is Not Empty then, define a Node pointer 'temp' and set it to 'front'
- Then set 'front = front → next' and delete 'temp' Before deletion
Code:
if(front == NULL)
printf("\nQueue is Empty!!!\n");
else{
struct Node *temp = front;
front = front -> next; After deletion
printf("\nDeleted element: %d\n", temp->data);
free(temp);
}
iii). Display
- Check whether queue is empty, if so print as “Queue is empty”
- If it is not, then print the elements from front to rear
4
Code:
if(front == NULL)
printf("\nQueue is Empty!!!\n");
else{
struct Node *temp = front;
while(temp!=NULL){
printf("%d ", temp->data);
temp = temp->next; Output: 10 20 30
}
}
II . CIRCULAR QUEUE
In a circular queue, all nodes are treated as circular. Last node is connected back to the first node.
It contains a collection of data which allows insertion of data at the end of the queue and deletion of
data at the beginning of the queue.
Example:
Eating - breakfast, lunch, snacks, dinner -
breakfast….
Days in a week - Sunday - Saturday - Sunday ….
Months in a year - Jan - Dec- Jan
Major Operations:
i). Enqueue [Insertion]
ii). Dequeue [Deletion]
iii). Display
(i).Enqueue:
Check whether queue is Full, If it is full then display Queue is full.
If queue is not full then, check if (rear == SIZE – 1 && front != 0) if it is true then set rear=0 and
insert element
Code:
int ele;
if((front == 0 && rear == SIZE-1) || (front == rear+1))
printf("Queue Overflow \n");
else
{
printf(“Enter the element:”);
5
Before Insertion After Insertion
scanf(“%d”,&x);
if(front == -1)
front = 0;
rear = (rear + 1) % SIZE;
a[rear] = ele;
}
(ii).De-queue:
Check whether queue is Empty, if so then display queue is empty.
If queue is not empty then check whether the queue is having single element, if it so then make
rear and front as -1, if not then increment front by 1.
Code:
if (front == -1)
printf("Queue Underflow\n");
else Before Deletion After Deletion
{
printf(“Deletetion elemet is : %d\n",a[front]);
if(front == rear) {
front = -1;
rear = -1;
}
else
front = (front+1) % SIZE;
}
iii). Display
Check whether queue is Empty, if so then display queue is empty.
If not, then print all the value from front to rear.
Code:
if (front == -1)
printf("Queue is empty\n");
else
{
for(int i = front; i != rear; i= (i+1) % SIZE)
{
printf(“%d “,a[i]);
} Output: 10 50 20 71
printf(“%d”,a[i]);
}
Applications of Circular Queue
Memory Management: The unused memory locations in the case of ordinary queues can be
utilized in circular queues.
Traffic system: In computer controlled traffic system, circular queues are used to switch on the
traffic lights one by one repeatedly as per the time set.
CPU Scheduling: Operating systems often maintain a queue of processes that are ready to execute
or that are waiting for a particular event to occur.
Types of DeQueue
Input Restricted DeQueue
Output Restricted DeQueue
In Input Restricted DeQueue , insertion can be done from REAR only, but deletion can be done from
both FRONT and REAR.
In Output Restricted DeQueue, deletion can be done from FRONT only, but insertion can be done
from both FRONT and REAR.
Basic Operations:
i). Insertion_left
ii). Insertion_right
iii).Deletion_left
iv).Deltion_right
v).Display
Global declaration:
# define MAX 10
int deque_arr[MAX];
int left = -1;
int right = -1;
8
(i). Insertion_left
- Check whether the queue is full or not, if so print “Queue is full”
- If not, decrement the front and insert the new element.
Code:
int item;
if(front == 0)
{
printf("Queue Overflow \n");
return;
}
else if (front == -1)
front = 0; rear = 0;
else
front=front-1;
printf(" Enter the element to insert: ");
scanf("%d", & item);
deque_arr [front] = item ;
(ii). Insertion_right
- Check whether the queue is full or not, if so print “Queue is full”
- If not, increment the rear and insert the new element.
Code:
int item;
if(rear == (QSIZE-1))
{
printf("Queue Overflow \n");
return;
}
else if (front == -1)
{
front = 0; rear = 0;
}
else
rear++;
printf(“Enter the element to insert: ");
scanf("%d", &item);
deque_arr [rear] = item ;
(iii). Deletion_left
- Check whether the queue is empty or not, if so print “Queue is empty”
- If not, increment the front and delete the element at left side.
Code:
if(front == -1 && rear ==-1) {
printf("Queue Underflow \n");
return;
}
else {
if(front==rear)
front = rear = -1;
else
front++;
}
9
(iv). Deletion_right
- Check whether the queue is empty or not, if so print “Queue is empty”
- If not, decrement the rear and delete the element at left side.
Code:
if(front == -1 && rear ==-1) {
printf("Queue Underflow \n");
return;
}
else {
if(front==rear)
front = rear = -1;
else
rear--;
}
(v). Display
- Check whether the queue is empty or not, if so print “Queue is empty”
- If not, start to print element from front to rear cursor in an array.
Code:
if(rear == -1 && front == -1) {
printf("Queue is Underflow \n");
}
else
{
printf(“The content from front…:”); Output:
for(int i=front;i<= rear;i++) The content from front 2 3 4
..Rear
printf(“%d ”, deque_arr [i]);
printf(“..Rear”);
}
Applications of DeQueue
Palindrome Checker
A Steal job scheduling algorithm
Undo-redo operation in software
10
UNIT – III
TREE
I . BINARY TREE
A tree in which every node can have a maximum of two children is called Binary Tree
Example:
Global declaration:
struct tree {
int data;
struct node* left;
struct node* right;
};
11
(i). Insertion
- Fill the element from left to right based on root node.
Code:
struct tree *create()
{
struct tree *p;
int x;
printf("Enter data(-1 for no data):");
scanf("%d",&x);
if(x==-1)
return NULL;
p=(node*)malloc(sizeof(node));
p->data=x;
printf("Enter left child of %d:\n",x);
p->left=create();
printf("Enter right child of %d:\n",x);
p->right=create();
return p;
}
(ii). Tree Traversal
a). In-Order Traversal
It performs the following steps starting from the root:
o First left node
o Second root node
o Third right node
Code:
void inorder(struct tree *t)
{
if(t!=NULL)
{
In-Order: D B E A C
inorder(t->left);
printf("\n%d",t->data);
inorder(t->right);
}
}
b). Pre-Order Traversal
It performs the following steps starting from the root:
o First root node
o Second left node
o Third right node
Code:
void preorder(struct tree *t)
{
if(t!=NULL)
{
Pre-Order: A B D E C
printf("\n%d",t->data);
preorder(t->left);
preorder(t->right);
}
}
12
c). Post-Order Traversal
It performs the following steps starting from the root:
o First left node
o Second right node
o Third root node
Code:
void postorder(struct tree *t)
{
if(t!=NULL)
{
Post-Order: D E B C A
postorder(t->left);
postorder(t->right);
printf("\n%d",t->data);
}
}
Global declaration:
struct tree {
int data;
struct node* left;
struct node* right;
};
(i). Insertion
- If the inserting element is smaller than root, it should be placed in left side
- If not identify the appropriate place at right side of the root node
13
Code:
struct tree* insert(struct tree*root, int x)
{
if(!root)
{
root=(struct tree*)malloc(sizeof(struct tree));
root->info = x;
root->left = NULL;
root->right = NULL;
return root;
}
if(root->info > x)
root->left = insert(root->left, x);
else
{
if(root->info < x) Before insertion of ‘4’ After insertion of ‘4’
root->right = insert(root->right,x);
}
return root;
}
(ii). FindMin
- Traverse till left most end from root node
- Print the element
Code:
void FindMin(struct tree* node) {
struct tree* temp = node;
/* loop down to find the leftmost leaf */ The min value is : 1
while (temp->left != NULL) {
temp=temp->left;
}
printf(“The min value is :%d”,temp->data);
}
(iii). FindMax
- Traverse till right most end from root node
- Print the element
Code:
void FindMax(struct tree* node) {
struct tree* temp = node;
The max value is : 14
/* loop down to find the leftmost leaf */
while (temp->right != NULL)
temp=temp->right;
printf(“The min value is :%d”,temp->data);
}
(iv). Search
- Traverse upto the last level in a given tree
- If searching element is matched, then print “found”, if not “not found”
Code:
struct node* search(struct node* root, int key)
{
// Base Cases: root is null or key is present at root
if (root == NULL || root->key == key)
return root;
14
// Key is greater than root's key
if (root->key < key)
return search(root->right, key);
// Key is smaller than root's key
return search(root->left, key);
}
(v). Deletion
- When we delete a node, we have to take care of the children of the node and also that the property
of a BST is maintained
- There can be three cases in deletion of a node
(a).The node is a leaf - This is the most simple case and here we can delete the node immediately
without giving a second thought.
(b).The node has one child
(c).The node has 2 children - When the node to be deleted has 2 children, we need to choose a
node to be replaced with the node to be deleted such that the property of the binary tree remains
intact
Advantages:
BST is fast in insertion and deletion etc when balanced.
Very efficient and its code is easier than link lists.
15
Why do we need Threaded Binary Tree?
Binary trees have a lot of wasted space: the leaf nodes each have 2 null pointers. We can use these
pointers to help us in inorder traversals.
Threaded binary tree makes the tree traversal faster since we do not need stack or recursion for
traversal
Types of threaded binary trees:
1. Single Threaded or One way threaded binary tree
The empty left child field of a node can be used to point to its inorder predecessor.
Similarly, the empty right child field of a node can be used to point to its in-order successor.
Such a type of binary tree is known as a one way threaded binary tree.
A field that holds the address of its in-order successor is known as thread
2. Double Threaded or Two way threaded binary tree
A field that holds the address of its inorder successor or predecessor is known as thread.
The empty left child field of a node can be used to point to its inorder predecessor.
Similarly, the empty right child field of a node can be used to point to its inorder successor.
16
Construction of Expression Tree:
Now for constructing expression tree we should use a stack. We loop through input expression and do
following for every character.
1) If character is operand push that into stack
2) If character is operator pop two values from stack make them its child and push current node again.
At the end only element of stack will be root of expression tree.
Example: a b + c d e + * *
Read ‘*’. Pop two operand and form a tree and Read ‘*’. Pop two operand and form a tree and push
push again into stack again into stack
Note: Inorder traversal of expression tree produces infix version of given postfix expression (same
with preorder traversal it gives prefix expression)
17
V. AVL TREE [Adelson, Velskii, and Landi ]
AVL tree is a binary search tree in which the difference of heights of left and right subtrees of any node is
less than or equal to one. (-1, 0,1)
Balance factor of a node is the difference between the heights of the left and right subtrees of that node.
The balance factor of a node is calculated either height of left subtree - height of right subtree (OR) height
of right subtree - height of left subtree
Example:
AVL Rotations
To balance itself, an AVL tree may perform the following four kinds of rotations −
Single left rotation
Single right rotation
Double Left-Right rotation
Double Right-Left rotation
(i). Single left rotation
- If a tree becomes unbalanced, when a node is inserted into the right subtree of the right subtree,
then we perform a single left rotation
18
We first perform the left rotation on the left We shall now right-rotate the tree, finally
First, we perform the right rotation along C node, We shall now left-rotate the tree, finally balanbed
making C the right subtree of its own left subtree tree is obtained
B. Now, B becomes the right subtree of A.
19
Operations on AVL Trees
The following operations are performed on AVL Trees:
Search
Insertion
Deletion
VI. B - TREE
B Tree is a specialized m-way tree.
It is a self-balanced search tree in which every node contains multiple keys and has more than two
children.
Properties:
Every node in a B-Tree contains at most m children.
Every node in a B-Tree except the root node and the leaf node contain at least m/2 children.
The root nodes must have at least 2 nodes.
All leaf nodes must be at the same level.
Example: B-tree with Order = 4
20
21
(ii). Deletion from B Tree
Deletion of the key also requires the first traversal in B tree, after reaching on a particular node two
cases may be occurred that are:
1. Node is leaf node
2. Node is non leaf node
22