Data Structures and Algorithms_dsa Full Notes
Data Structures and Algorithms_dsa Full Notes
Unit-1:
Algorithms: Introduction, Algorithm Specifications, Recursive Algorithms,
Performance Analysis of an algorithm- Time and Space Complexity, Asymptotic
Notations.
Arrays: Arrays - ADT, Polynomials, Sparse matrices, Strings-ADT, Pattern
Matching.
Objective:
To develop proficiency in the specification, representation, and implementation of
abstract data types and data structures.
Outcome: Implementing the concepts of data structure using abstract data type
and Evaluate an algorithm by using algorithmic performance and measures.
Algorithms
Algorithm is a step-by-step procedure, which defines a set of instructions to be
executed in a certain order to get the desired output. Algorithms are generally created
independent of underlying languages, i.e. an algorithm can be implemented in more than one
programming language.
From the data structure point of view, following are some important types of algorithms:
1. Sorting
2. Searching
3. Compression
4. Encoding
5. Fast Fourier transforms
6. Geometric
7. Pattern matching
8. Parsing
Characteristics of an Algorithm:
Algorithm Specification:
1
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
Pseudo code convention: In this code convention algorithm will written in two parts.
a. Heading Part
b. Body part
a. Heading Part:
Syntax: algorithm Name(Parameters list)
1. // Comments
2. {
3. Identifiers
4. <Variable>=<Value>
5. Operators
6. Looping statements
7. If condition Statements
8. Input and Output will write as read and write
9. }
The performance of a program is the amount of computer memory and time needed to
run a program.
Time Complexity: The time needed by an algorithm expressed as a function of the size
of a problem is called the time complexity of the algorithm. The time complexity of a
program is the amount of computer time it needs to run to completion. The limiting
behavior of the complexity as size increases is called the asymptotic time complexity. It is
the asymptotic complexity of an algorithm, which ultimately determines the size of
problems that can be solved by the algorithm.
Space Complexity: The space complexity of a program is the amount of memory it needs
to run to completion. The space need by a program has the following components:
Complexity of Algorithms:
The complexity of an algorithm M is the function f(n) which gives the running time
and/or storage space requirement of the algorithm in terms of the size „n‟ of the input
2
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
data. Mostly, the storage space required by an algorithm is simply a multiple of the data
size „n‟. Complexity shall refer to the running time of the algorithm.
The function f(n), gives the running time of an algorithm, depends not only on the size
„n‟ of the input data but also on the particular data. The complexity function f(n) for
certain cases are:
1. Best Case : The minimum possible value of f(n) is called the best case.
2. Average Case : The expected value of f(n).
3. Worst Case : The maximum value of f(n) for any key possible input.
The field of computer science, which studies efficiency of algorithms, is known as
analysis of algorithms.
Algorithms can be evaluated by a variety of criteria. Most often we shall be interested in
the rate of growth of the time or space required to solve larger and larger instances of a
problem. We will associate with the problem an integer, called the size of the problem,
which is a measure of the quantity of input data.
Asymptotic Notations:
The following notations are commonly use notations in performance analysis and
used to characterize the complexity of an algorithm:
1. Big–OH (O)
2. Big–OMEGA ( ) and
3. THETA()
1. Big–OH O (Upper Bound) f(n) = O(g(n)), (pronounced order of or big oh), says that
the growth rate of f(n) is less than or equal that of g(n).
2. . Big–OMEGA ( ):
3
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
3. THETA() :
Array ADT:
The array is an abstract data type (ADT) that holds a collection of elements accessible
by an index.
The elements stored in an array can be anything from primitive types such as integers,
characters, etc..
An element is stored in each index and they can be retrieved later by specifying the
same index.
The Array ADT is usually implemented by an Array (Data Structure).
ADT — Operations
• Insertion- Adds an element at the given index.
• Deletion - Deletes an element at the given index
• Traverse- print all the array elements one by one
• Search- Searches an element using the given index or by the value
• Update- Updates an element at the given index
void insert()
{
4
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
void search()
{
printf("\nEnter an element to search\n");
scanf("%d",&n);
for(i=0;i<5;i++)
{
if(a[i]==n)
{
printf("\nthe searching element %d found at %d index",n,i);
}
}
}
5
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
void update()
{
printf("enter the index number and value which u want to update:");
scanf("%d%d",&index,&value);
a[index]=value;
}
int main()
{
int ch;
do
{
printf("\n**** MENU ****");
printf("\n1:insert()\n2:delete()\n3:display()\n4:search()\n5:update()\n");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1: insert();
break;
case 2: delete();
break;
case 3: display();
break;
case 4: search();
break;
case 5: update();
break;
default: printf("choose correct option");
}
}while(ch!=0);
}
1. Polynomial Expression:
• A polynomial is an expression representing a mathematical sum of many terms.
• Each term has a number called the coefficient, a variable and a power of the variable
called the exponent.
axn+axn-1+axn-2+…….+a
• The largest exponent is the polynomial‘s degree.
6
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
Not a polynomial:
1. Array Representation:
There may arise some situation where you need to evaluate many polynomial
expressions and perform basic arithmetic operations like addition and subtraction with those
numbers. For this, you will have to get a way to represent those polynomials. The simple way
is to represent a polynomial with degree 'n' and store the coefficient of n+1 terms of the
polynomial in the array. So every array element will consist of two values:
Coefficient and
Exponent
#include<stdio.h>
#include<math.h>
struct poly
{
float coeff;
int exp;
7
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
};
//declaration of polynomials
struct poly a[50],b[50],c[50],d[50];
int main()
{
int i;
int deg1,deg2; //stores degrees of the polynomial
int k=0,l=0,m=0;
printf("Enter the highest degree of polynomial1:");
scanf("%d",°1); //taking polynomial terms from the user
for(i=0;i<=deg1;i++)
{
//entering values in coefficient of the polynomial terms
printf("\nEnter the coeff of x^%d :",i);
scanf("%f",&a[i].coeff);
//entering values in exponent of the polynomial terms
a[k++].exp = i;
}
//taking second polynomial from the user
printf("\nEnter the highest degree of polynomial2:");
scanf("%d",°2);
for(i=0;i<=deg2;i++)
{
printf("\nEnter the coeff of x^%d :",i);
scanf("%f",&b[i].coeff);
b[l++].exp = i;
}
//printing first polynomial
printf("\nExpression 1 = %.1f",a[0].coeff);
for(i=1;i<=deg1;i++)
{
printf("+ %.1fx^%d",a[i].coeff,a[i].exp);
}
//printing second polynomial
printf("\nExpression 2 = %.1f",b[0].coeff);
for(i=1;i<=deg2;i++)
{
printf("+ %.1fx^%d",b[i].coeff,b[i].exp);
}
//Adding the polynomials
if(deg1>deg2)
{
for(i=0;i<=deg2;i++)
{
c[m].coeff = a[i].coeff + b[i].coeff;
c[m].exp = a[i].exp;
m++;
}
for(i=deg2+1;i<=deg1;i++)
{
8
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
c[m].coeff = a[i].coeff;
c[m].exp = a[i].exp;
m++;
}
}
else
{
for(i=0;i<=deg1;i++)
{
c[m].coeff = a[i].coeff + b[i].coeff;
c[m].exp = a[i].exp;
m++;
}
for(i=deg1+1;i<=deg2;i++)
{
c[m].coeff = b[i].coeff;
c[m].exp = b[i].exp;
m++;
}
}
//printing the sum of the two polynomials
printf("\nExpression after addition = %.1f",c[0].coeff);
for(i=1;i<m;i++)
{
printf("+ %.1fx^%d",c[i].coeff,c[i].exp);
}
return 0;
}
A polynomial can be thought of as an ordered list of non zero terms. Each non zero
term is a two-tuple which holds two pieces of information:
Ex: 3x2+4x-1
3 2 4 1 -1 0 NULL
2. Sparse Matrix:
• A matrix can be defined as a two-dimensional array having 'm' columns and 'n' rows
representing m*n matrix.
• Sometimes it happens when a matrix has zero values is more than NON-ZERO
values.
9
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
• The matrix which has a greater number of zero elements in comparison to the non-
zero elements is known as a sparse matrix.
• The sparse matrix is represented using triplets, i.e., row, column, and value because of
that we called it is triplet representation.
10
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
{
for(j=0;j<c;j++)
{
printf("a[%d][%d]:",i,j);
scanf("%d",&a[i][j]);
}
}
printf("\nPrinting the Sparse Matrix:");
for(i=0;i<r;i++)
{
printf("\n");
for (j=0;j<c;j++)
{
printf("%d\t",a[i][j]);
}
}
printf("\nThe 3 tuple represenation of the sparse matrix: ");
printf("\nR C V");
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
{
if(a[i][j]!=0)
{
printf("\n%d %d %d",i,j,a[i][j]);
}
}
}
printf("\n");
return 0;
}
11
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
int a[50][50],r,c,i,j;
printf("Enter the no. of rows and columns of matrix:");
scanf("%d%d",&r,&c);
12
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
}
printf("\nPrinting the Sparse Matrix:");
for(i=0;i<r;i++)
{
printf("\n");
for (j=0;j<c;j++)
{
printf("%d\t",a[i][j]);
}
}
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
{
if(a[i][j]!=0)
{
struct node *temp;
temp=(struct node*)malloc(sizeof(struct node));
temp->row=i;
temp->col=j;
temp->value=a[i][j];
temp->next=NULL;
if(head==NULL)
{
head=temp;
last=head;
}
else
{
last->next=temp;
last=temp;
}
}
}
}
printf("\nThe linked list represenation of the sparse matrix: ");
display();
printf("\n");
return 0;
}
String ADT:
• A string is a sequence of characters stored in an array(i.e., one dimensional array).
• Every string terminated with a special character called null character(‗\0‘).
• Each character in the array occupies one byte of memory, and the last character must
always be 0.
13
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
• The termination character ('\0') is important in a string since it is the only way to
identify where the string ends.
• There are two ways to declare a string in c language.
1. By char array
2. By string literal
1. By char array: we can declare a string by char array in C language by the following
ways
char ch[5]={‗H‘, ‗E‘, ‗L‘, ‗L‘, ‗O‘, '\0'};
As we know, array index starts from 0, so it will be represented as in the figure given below.
• While declaring string, size is not mandatory. So we can write the above code as
given below:
char ch[]={‗H‘, ‗E‘, ‗L‘, ‗L‘, ‗O‘, '\0'};
2. By string literal:
char ch[]=―Hello‖;
In such case, '\0' will be appended at the end of the string by the compiler.
Difference between char array and string literal:
1. We need to add the null character '\0' at the end of the array by ourself in char array
whereas, it is appended internally by the compiler in the case of the string literal.
2. The string literal cannot be reassigned to another set of characters whereas, we can
reassign the characters of the array.
• We can read a string from the keyboard in two ways
1. Using scanf() method - reads single word
2. Using gets() method - reads a line of text
• Using scanf() method we can read only one word of string. We use %s to represent
string in scanf() and printf() methods.
• The puts() function is very much similar to printf() function.
• The puts() function is used to print the string on the console which is previously read
by using gets() or scanf() function.
Operations on string:
1. length
2. concatenation
3. copy
4. compare
Implementation of String ADT:
#include<stdio.h>
#include<string.h>
int main()
{
char a[30],b[30],c[30];
printf("Enter first string:");
scanf("%s",a);
printf("Enter second string:");
scanf("%s",b);
printf("Enter third string:");
scanf("%s",c);
14
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
Pattern Matching:
• Pattern matching is the way of checking a series of pattern or a sequence of digits or
string with some other pattern and find out if it matches or not, in pattern recognition,
the match usually has to be exact.
• A pattern can be a series of digits, a string arranged in an order. The order is really
important in case of pattern matching.
#include <stdio.h>
#include <string.h>
int match(char [], char []);
int main() {
char a[100], b[100];
int position;
if (position != -1) {
printf("Found at location: %d\n", position + 1);
}
else {
printf("Not found.\n");
}
return 0;
}
15
Data Structures and Algorithms UNIT-I—Algorithms & Arrays
text_length = strlen(text);
pattern_length = strlen(pattern);
16
Data Structures and Algorithms UNIT-II—Stacks and Queues
Unit-2:
Stacks and Queues: Stacks, Stacks using Arrays, Stacks using dynamic arrays,
Evaluation of Expressions – Evaluating Postfix Expression, Infix to Postfix.
Queues: Queues ADT, operations, Circular Queues, Applications
Objective:
To introduce various linear data Structures such as stacks, queues and their
applications
Outcome: Implement linear data structures such as stacks, queues to solve
various computing problems.
1
Data Structures and Algorithms UNIT-II—Stacks and Queues
Operations applied on linear data structure: The following list of operations applied on linear
data structures
1. Add an element
2. Delete an element
3. Traverse
4. Sort the list of elements
5. Search for a data element
For example Stack, Queue, Tables, List, and Linked Lists.
2. Non-linear Data Structure:
Operations applied on non-linear data structures: The following list of operations applied on
non-linear data structures.
1. Add elements
2. Delete elements
3. Display the elements
4. Sort the list of elements
5. Search for a data element For example Tree, Decision tree, Graph and Forest
1. Linear Data structures: Linear data structures are Stack, Queue and Linked list.
Stack:
A stack is a container of objects that are inserted and removed according to the last-in
first-out (LIFO) principle. In the pushdown stacks only two operations are allowed: push the
item into the stack, and pop the item out of the stack. A stack is a limited access data
structure - elements can be added and removed from the stack only at the top. Push adds an
item to the top of the stack, pop removes the item from the top. A helpful analogy is to think
2
Data Structures and Algorithms UNIT-II—Stacks and Queues
of a stack of books; you can remove only the top book, also you can add a new book on the
top.
A stack may be implemented to have a bounded capacity. If the stack is full and does
not contain enough space to accept an entity to be pushed, the stack is then considered to be
in an overflow state. The pop operation removes an item from the top of the stack. A pop
either reveals previously concealed items or results in an empty stack, but, if the stack is
empty, it goes into underflow state, which means no items are present in stack to be removed.
Stack (ADT) Data Structure: Stack is an Abstract data structure (ADT) works on the
principle Last In First Out (LIFO). The last element add to the stack is the first element to be
delete. Insertion and deletion can be takes place at one end called TOP. It looks like one side
closed tube.
The add operation of the stack is called push operation.
The delete operation is called as pop operation.
Push operation on a full stack causes stack overflow.
Pop operation on an empty stack causes stack underflow.
4 4 4 4
3 3 3 3 40
2 2 2 2 30
1 1 1 20 1 20
0 0 10 0 10 0 10
Operations of stack: There are two operations applied on stack they are
1. push
2. pop.
While performing push & pop operations the following test must be conducted on the stack.
1) Stack is empty or not
2) Stack is full or not
3
Data Structures and Algorithms UNIT-II—Stacks and Queues
Push: Push operation is used to add new elements in to the stack. At the time of addition first
check the stack is full or not. If the stack is full it generates an error message "stack
overflow".
Pop: Pop operation is used to delete elements from the stack. At the time of deletion first
check the stack is empty or not. If the stack is empty it generates an error message "stack
underflow".
4 4 4 4 4
3 3 3 3 40 3
2 2 2 2 30 2 30
1 1 1 20 1 20 1 20
0 0 10 0 10 0 10 0 10
1. PUSH: if (top==MAX), display Stack overflow else reading the data and making stack
[top] =data and incrementing the top value by doing top++.
2. POP: if (top==-1), display Stack underflow else printing the element at the top of the stack
and decrementing the top value by doing the top.
algorithm isEmpty()
{
top;
if(top==-1) then
write stack is empty;
else
4
Data Structures and Algorithms UNIT-II—Stacks and Queues
algorithm isFull()
{
top, maxsize;
if(top==maxsize-1) then
write stack is full;
else
write stack is not full;
end if;
}
algorithm push(item)
{
top, a[maxsize];
if(top==maxsize-1) then
write stack overflow;
else
top=top+1;
a[top]=item;
}
algorithm pop()
{
top, item;
if(top==-1) then
write stack underflow;
else
write item=stack[top];
top=top-1;
return item;
}
#include<stdio.h>
int top=-1,a[5];
5
Data Structures and Algorithms UNIT-II—Stacks and Queues
int isEmpty()
{
if(top==-1)
{
return 1;
}
else
{
return 0;
}
}
int isFull()
{
if(top==4)
{
return 1;
}
else
{
return 0;
}
}
void push(int item)
{
if(isFull())
{
printf("stack overflow");
}
else
{
top++;
a[top]=item;
}
}
void pop()
{
if(isEmpty())
{
printf("stack underflow");
}
else
{
printf("The popped element is %d",a[top]);
top--;
}
}
void display()
{
if(top>=0)
6
Data Structures and Algorithms UNIT-II—Stacks and Queues
{
printf("Elements in the stack are:");
for(int i=top;i>=0;i--)
{
printf("\n%d",a[i]);
}
}
else
{
printf("stack is empty");
}
}
void count()
{
printf("\nNumber of elements in the stack are: %d",top+1);
}
void peek()
{
if(top==-1)
{
printf("stack is empty");
}
else
{
printf("The top element is %d",a[top]);
}
}
void search()
{
int index;
if(top==-1)
{
printf("stack is empty");
}
else
{
printf("Enter index number u want to display:");
scanf("%d",&index);
printf("\nthe value in the %d index is %d",index,a[index]);
}
}
void change()
{
int index,value;
if(top==-1)
{
printf("stack is empty");
}
7
Data Structures and Algorithms UNIT-II—Stacks and Queues
else
{
printf("enter the index number and value which u want to change:");
scanf("%d%d",&index,&value);
a[index]=value;
}
}
int main()
{
int ch,item,index,value;
do
{
printf("\n**** MENU ****");
printf("\n1:isEmpty()\n2:isFull()\n3:push()\n4:pop()\n5:count()\n6:display()\n7:peek()\n8:sea
rch()\n9:change()");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1: if(isEmpty())
printf("stack is empty\n");
else
printf("stack is not empty\n");
break;
case 2: if(isFull())
printf("stack is full\n");
else
printf("stack is not full\n");
break;
case 3: printf("enter an item to push:");
scanf("%d",&item);
push(item);
break;
case 4: pop();
break;
case 5: count();
break;
case 6: display();
break;
case 7: peek();
break;
case 8: search();
break;
case 9: change();
break;
default: printf("choose correct option");
}
}while(ch!=0);
8
Data Structures and Algorithms UNIT-II—Stacks and Queues
#include<stdio.h>
#include<stdlib.h>
int *a=NULL;
int top=-1,size;
void create_st()
{
printf("\nEnter size of the array");
scanf("%d",&size);
a=(int*)malloc(size*sizeof(int));
}
int isEmpty()
{
if(top==-1)
{
return 1;
}
else
{
return 0;
}
}
int isFull()
{
if(top==size-1)
{
return 1;
}
else
{
return 0;
}
}
void push(int item)
{
if(isFull())
{
printf("stack overflow");
}
else
{
top++;
*(a+top)=item;
}
9
Data Structures and Algorithms UNIT-II—Stacks and Queues
}
void pop()
{
if(isEmpty())
{
printf("stack underflow");
}
else
{
printf("The popped element is %d",*(a+top));
top--;
}
}
void display()
{
if(top>=0)
{
printf("Elements in the stack are:");
for(int i=0;i<=top;i++)
{
printf("\n%d",*(a+i));
}
}
else
{
printf("stack is empty");
}
}
/*void count()
{
printf("\nNumber of elements in the stack are: %d",top+1);
}
void peek()
{
if(top==-1)
{
printf("stack is empty");
}
else
{
printf("The top element is %d",a[top]);
}
}
void search()
{
int index;
if(top==-1)
{
printf("stack is empty");
10
Data Structures and Algorithms UNIT-II—Stacks and Queues
}
else
{
printf("Enter index number u want to display:");
scanf("%d",&index);
printf("\nthe value in the %d index is %d",index,a[index]);
}
}
void change()
{
int index,value;
if(top==-1)
{
printf("stack is empty");
}
else
{
printf("enter the index number and value which u want to change:");
scanf("%d%d",&index,&value);
a[index]=value;
}
}*/
int main()
{
int ch,item,index,value;
do
{
printf("\n**** MENU ****");
printf("\n1:isEmpty()\n2:isFull()\n3:push()\n4:pop()\n6:count()\n5:display()\n7:peek()
\n8:search()\n9:change()\n10:create()");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1: if(isEmpty())
printf("stack is empty\n");
else
printf("stack is not empty\n");
break;
case 2: if(isFull())
printf("stack is full\n");
else
printf("stack is not full\n");
break;
case 3: printf("enter an item to push:");
scanf("%d",&item);
push(item);
break;
11
Data Structures and Algorithms UNIT-II—Stacks and Queues
case 4: pop();
break;
case 5: display();
break;
/* case 6: count();
break;
case 7: peek();
break;
case 8: search();
break;
case 9: change();
break;*/
case 10: create_st();
break;
default: printf("choose correct option");
}
}while(ch!=0);
}
Stack Applications:
1. Stack is used by compilers to check for balancing of parentheses, brackets and braces.
2. Stack is used to evaluate a postfix expression.
3. Stack is used to convert an infix expression into postfix/prefix form.
Below mentioned are the time complexities for various operations that can be
performed on the Stack data structure.
The time complexities for push() and pop() functions are O(1) because we always
have to insert or remove the data from the top of the stack, which is a one step process.
12
Data Structures and Algorithms UNIT-II—Stacks and Queues
d) If the scanned symbol is an operator, then go on removing all the operators from
the stack and place them in the postfix expression, if and only if the precedence of the
operator which is on the top of the stack is greater than (or equal) to the precedence of the
scanned operator and push the scanned operator onto the stack otherwise, push the scanned
operator onto the stack.
SET i to 0
GET infix expression from user into input_array
SET var with input_array[i]
CALL createStack
WHILE var != end of string
IF var equals to '(' THEN
CALL pushIntoStack (stack, var)
ELSE IF var is a number THEN
PRINT var
ELSE IF var is an arithmetic operator THEN
CALL pushIntoStack (stack, var)
ELSE IF var equals to ')' THEN
WHILE stackTop != '('
IF stackTop is an arithmetic operator THEN
PRINT stackTop
popFromStack (stack)
ENDIF
ENDWHILE
popFromStack (stack)
ENDIF
13
Data Structures and Algorithms UNIT-II—Stacks and Queues
int isEmpty()
{
if(top==-1)
{
return 1;
}
else
{
return 0;
}
}
int isFull()
{
if(top==19)
{
return 1;
}
else
{
return 0;
}
}
void push(int item)
{
if(isFull())
{
printf("stack overflow");
}
else
{
top++;
stk[top]=item;
}
}
14
Data Structures and Algorithms UNIT-II—Stacks and Queues
char pop()
{
if(isEmpty())
{
printf("stack underflow");
}
else
{
return stk[top--];
}
}
char peep()
{
return stk[top];
}
int pri(char opr)
{
switch(opr)
{
case '(':return 0;
case ')':return 0;
case '+':return 1;
case '-':return 1;
case '*':return 2;
case '/':return 2;
case '%':return 2;
case '$':return 3;
}
}
int main()
{
int i,j=0;
char ch;
char infix[100],postfix[100];
printf("enter a valid infix expression:");
scanf("%s",infix);
i=0;
while(infix[i]!='\0')
{
if(infix[i]=='(')
{
push(infix[i]);
}
15
Data Structures and Algorithms UNIT-II—Stacks and Queues
if(top==-1)
{
push(infix[i]);
}
else
{
while(peep()=='+'||peep()=='-
'||peep()=='*'||peep()=='/'||peep()=='%'||peep()=='$'||peep()=='('||peep()==')')
{
if(pri(peep())>=pri(infix[i]))
{
postfix[j]=pop();
j++;
}
else
{
break;
}
}
push(infix[i]);
}
}
else if(infix[i]==')')
{
while((ch=pop())!='(')
{
postfix[j]=ch;
j++;
}
16
Data Structures and Algorithms UNIT-II—Stacks and Queues
i++;
}
while(top>-1)
{
postfix[j]=pop();
j++;
}
postfix[j]='\0';
printf("%s",postfix);
}
Complexity:
Time Complexity: O(n)
Space Complexity: O(n)
17
Data Structures and Algorithms UNIT-II—Stacks and Queues
+ 40 5 45 6 45 Next, a „+‟ is
seen, so 40
and 5 are
popped and
40 + 5 = 45
is pushed
3 6 45 3 3 is pushed
+ 45 3 48 6 48 Next, „+‟
pops 3 and
45 and
pushes 45 +
3 = 48 is
pushed
* 6 48 288 288 Finally, a „*‟
is seen and
48 and 6 are
popped, the
result 6 * 48
= 288 is
pushed
1. algorithm postfixeval(postfix[],i,top)
2.{
3. while(postfix[i]!='\0') do
4.if(postfix[i]>='0'&&postfix[i]<='9') then
x=postfix[i]-48;
push(x);
5.else if(postfix[i]=='+'||postfix[i]=='-'||postfix[i]=='*'||postfix[i]=='/'||postfix[i]=='%')
then
a=pop();
b=pop();
6.switch(postfix[i])
case '+':
c=b+a;
push(c);
break;
case '-':
c=b-a;
push(c);
break;
case '*':
c=b*a;
push(c);
break;
case '/':
c=b/a;
push(c);
18
Data Structures and Algorithms UNIT-II—Stacks and Queues
break;
case '%':
c=b%a;
push(c);
break;
end if;
i++;
end while;
write top;
}
int isEmpty()
{
if(top==-1)
{
return 1;
}
else
{
return 0;
}
}
int isFull()
{
if(top==19)
{
return 1;
}
else
{
return 0;
}
}
void push(int value)
{
if(isFull())
{
printf("stack overflow");
}
19
Data Structures and Algorithms UNIT-II—Stacks and Queues
else
{
top++;
stk[top]=value;
printf("pushing element is %d\n",stk[top]);
}
}
int pop()
{
printf("the popped element is %d\n",stk[top]);
return stk[top--];
}
int peep()
{
return stk[top];
}
int main()
{
int i=0,x,a,b,c;
char postfix[100];
printf("enter a valid postfix Expression:");
scanf("%s",postfix);
while(postfix[i]!='\0')
{
if(postfix[i]>='0'&&postfix[i]<='9')
{
x=postfix[i]-48;
push(x);
}
else if(postfix[i]=='+'||postfix[i]=='-'||postfix[i]=='*'||postfix[i]=='/'||postfix[i]=='%')
{
a=pop();
b=pop();
switch(postfix[i])
{
case '+':
c=b+a;
push(c);
break;
case '-':
c=b-a;
push(c);
break;
20
Data Structures and Algorithms UNIT-II—Stacks and Queues
case '*':
c=b*a;
push(c);
break;
case '/':
c=b/a;
push(c);
break;
case '%':
c=b%a;
push(c);
break;
}
}
i++;
}
printf("The Answer is %d",peep());
}
Complexity:
Time Complexity: O(n)
Space Complexity: O(n)
Queue:
A queue is a data structure that is best described as "first in, first out". A queue is
another special kind of list, where items are inserted at one end called the rear and deleted at
the other end called the front. A real world example of a queue is people waiting in line at the
bank. As each person enters the bank, he or she is "enqueued" at the back of the line. When a
teller becomes available, they are "dequeued" at the front of the line.
Let us consider a queue, which can hold maximum of five elements. Initially the queue is
empty.
0 1 2 3 4
Q u e u e E mp t y F RO NT = REA R = -1
21
Data Structures and Algorithms UNIT-II—Stacks and Queues
rear=rear+1=-2+1=3 rear
rear=rear+1=-3+1=4 rear
Now, delete an element. The element deleted is the element at the front of the queue, if we
increment the front. So the status of the queue is:
0 1 2 3 4
20 30 40 50
0 1 2 3 4
20 30 40 50
0 1 2 3 4
30 40 50
22
Data Structures and Algorithms UNIT-II—Stacks and Queues
23
Data Structures and Algorithms UNIT-II—Stacks and Queues
24
Data Structures and Algorithms UNIT-II—Stacks and Queues
printf("Queue is full");
return;
}
else if(isEmpty())
{
rear=0;
front=0;
}
else
{
rear++;
}
q[rear]=value;
}
void dequeue()
{
if(isEmpty())
{
printf("Queue is empty");
}
else if(front==rear)
{
printf("dequeued value: %d",q[front]);
front=-1;
rear=-1;
}
else
{
printf("dequeued value: %d",q[front]);
front++;
}
}
int count()
{
if(rear==-1&&front==-1)
{
return 0;
}
else
{
return (rear-front+1);
}
}
void display()
25
Data Structures and Algorithms UNIT-II—Stacks and Queues
{
if(isEmpty())
{
printf("Queue is empty");
}
else
{
printf("All valus in the queue are: ");
for(int i=front;i<=rear;i++)
{
printf("%d ",q[i]);
}
}
}
int main()
{
int option,value;
do
{
printf("\n**** MENU ****");
printf("\n1.Enqueue()");
printf("\n2.Dequeue()");
printf("\n3.isEmpty()");
printf("\n4.isFull()");
printf("\n5.Count()");
printf("\n6.Display()");
printf("\nselect an option: if u want to exit press 0\n");
scanf("%d",&option);
switch(option)
{
case 0:
break;
case 1:
printf("Enter an item into the queue:");
scanf("%d",&value);
enqueue(value);
break;
case 2: dequeue();
break;
case 3:
if(isEmpty())
{
printf("Queue is empty");
26
Data Structures and Algorithms UNIT-II—Stacks and Queues
}
else
{
printf("Queue is not empty");
}
break;
case 4:
if(isFull())
{
printf("Queue is Full");
}
else
{
printf("Queue is not full");
}
break;
case 5:
printf("Number of items in the queue : %d",count());
break;
case 6:
display();
break;
default:
printf("Please select valid option");
break;
}
}while(option!=0);
return 0;
}
Applications of Queues:
Just like Stack, in case of a Queue too, we know exactly, on which position new
element will be added and from where an element will be removed, hence both these
operations requires a single step.
Enqueue: O(1)
27
Data Structures and Algorithms UNIT-II—Stacks and Queues
Dequeue: O(1)
Size: O(1)
Circular Queue:
Circular queue is a linear data structure. It follows FIFO principle. In circular queue the last node
is connected back to the first node to make a circle.
Circular linked list fallow the First In First Out principle.
Elements are added at the rear end and the elements are deleted at front end of the queue.
Let us consider a circular queue, which can hold maximum (MAX) of six elements. Initially
the queue is empty.
28
Data Structures and Algorithms UNIT-II—Stacks and Queues
#include<stdio.h>
int front=-1;
29
Data Structures and Algorithms UNIT-II—Stacks and Queues
int rear=-1;
int q[5];
int itemcount=0;
int isEmpty()
{
if(front==-1 && rear==-1)
{
return 1;
}
else
{
return 0;
}
}
int isFull()
{
if((rear+1)%5==front)
{
return 1;
}
else
{
return 0;
}
}
void enqueue(int value)
{
if(isFull())
{
printf("Queue is full");
}
else if(isEmpty())
{
rear=0;
front=0;
q[rear]=value;
}
else
{
rear=((rear+1)%5);
q[rear]=value;
}
itemcount++;
}
void dequeue()
{
30
Data Structures and Algorithms UNIT-II—Stacks and Queues
int x=0;
if(isEmpty())
{
printf("Queue is empty");
}
else if(front==rear)
{
x=q[front];
q[front]=0;
front=-1;
rear=-1;
itemcount--;
printf("dequeued value: %d",x);
}
else
{
x=q[front];
q[front]=0;
front=((front+1)%5);
itemcount--;
printf("dequeued value: %d",x);
}
}
int count()
{
if(rear==-1&&front==-1)
{
return 0;
}
else
{
return (itemcount);
}
}
void display()
{
printf("All valus in the queue are: ");
for(int i=0;i<5;i++)
{
printf("%d ",q[i]);
}
}
int main()
{
int option,value;
do
{
31
Data Structures and Algorithms UNIT-II—Stacks and Queues
switch(option)
{
case 0:
break;
case 1:
printf("Enter an item into the queue:");
scanf("%d",&value);
enqueue(value);
break;
case 2: dequeue();
break;
case 3:
if(isEmpty())
{
printf("Queue is empty");
}
else
{
printf("Queue is not empty");
}
break;
case 4:
if(isFull())
{
printf("Queue is Full");
}
else
{
printf("Queue is not full");
}
break;
case 5:
printf("Number of items in the queue : %d",count());
break;
case 6:
display();
break;
default:
32
Data Structures and Algorithms UNIT-II—Stacks and Queues
Enqueue: O(1)
Dequeue: O(1)
33
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Unit-3:
Linked Lists: Singly Linked Lists and Chains, Linked Stacks and Queues,
Polynomials, Operations for Circularly linked lists, Equivalence Classes, Sparse
matrices, Doubly Linked Lists.
Hashing: Static Hashing, Hash Tables, Hash Functions, Overflow Handling,
Theoretical Evaluation of Overflow Techniques
Objective:
To introduce various non linear data Structures such as trees, graphs and their
applications.
Outcome: Implement linked list data structures to solve various computing
problems.
Linked Lists
Linked lists and arrays are similar since they both store collections of data. Array is the most
common data structure used to store collections of elements. Arrays are convenient to declare and
provide the easy syntax to access any element by its index number. Once the array is set up, access to
any element is convenient and fast.
The disadvantages of arrays are:
• The size of the array is fixed. Most often this size is specified at compile time. This makes the
programmers to allocate arrays, which seems "large enough" than required.
• Inserting new elements at the front is potentially expensive because existing elements need to
be shifted over to make room.
• Deleting an element from an array is not possible. Linked lists have their own strengths and
weaknesses, but they happen to be strong where arrays are weak.
• Generally array's allocates the memory for all its elements in one block whereas linked lists
use an entirely different strategy. Linked lists allocate memory for each element separately
and only when necessary.
Linked List Concepts:
A linked list is a non-sequential collection of data items. It is a dynamic data structure. For
every data item in a linked list, there is an associated pointer that would give the memory location of
the next data item in the linked list. The data items in the linked list are not in consecutive memory
locations. They may be anywhere, but the accessing of these data items is easier as each data item
contains the address of the next data item.
1
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
A single linked list is one in which all nodes are linked together in some sequential manner.
Hence, it is also called as linear linked list.
A double linked list is one in which all nodes are linked together by multiple links which
helps in accessing both the successor node (next node) and predecessor node (previous node) from
any arbitrary node within the list. Therefore each node in a double linked list has two link fields
(pointers) to point to the left node (previous) and the right node (next). This helps to traverse in
forward direction and backward direction.
A circular linked list is one, which has no beginning and no end. A single linked list can be
made a circular linked by simply storing address of the very first node in the link field of the last
node.
2
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
1. Linked lists are used to represent and manipulate polynomial. Polynomials are expression
containing terms with non zero coefficient and exponents. For example: P(x) = a0 Xn + a1 Xn-1 +
…… + an-1 X + an
2. Represent very large numbers and operations of the large number such as addition, multiplication
and division.
3. Linked lists are to implement stack, queue, trees and graphs. 4. Implement the symbol table in
compiler construction.
A linked list allocates space for each element separately in its own block of memory called a
"node". The list gets an overall structure by using pointers to connect all its nodes together like the
links in a chain. Each node contains two fields; a "data" field to store whatever element, and a "next"
field which is a pointer used to link to the next node. Each node is allocated in the heap using
malloc(), so the node memory continues to exist until it is explicitly de-allocated using free(). The
front of the list is a pointer to the “start” node.
The beginning of the linked list is stored in a "start" pointer which points to the first node.
The first node contains a pointer to the second node. The second node contains a pointer to the third
node, ... and so on. The last node in the list has its next field set to NULL to mark the end of the list.
Code can access any node in the list by starting at the start and following the next pointers.
The start pointer is an ordinary local pointer variable, so it is drawn separately on the left top
to show that it is in the stack. The list nodes are drawn on the right to show that they are allocated in
the heap.
The basic operations in a single linked list are:
• Creation.
• Insertion.
• Deletion.
• Traversing.
3
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Creating a singly linked list starts with creating a node. Sufficient memory has to be allocated for
creating a node. The information is stored in the memory.
Insertion of a Node:
One of the most primitive operations that can be done in a singly linked list is the insertion of a node.
Memory is to be allocated for the new node (in a similar way that is done while creating a list) before
reading the data. The new node will contain empty data field and empty next field. The data field of
the new node is then stored with the information read from the user. The next field of the new node is
assigned to NULL. The new node can then be inserted at three different places namely:
Inserting a node at the beginning.
Inserting a node at the end.
Inserting a node at intermediate position.
Inserting a node into the single linked list at a specified intermediate position other than
beginning and end.
4
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Deletion of a node:
Another primitive operation that can be done in a singly linked list is the deletion of a node. Memory
is to be released for the node to be deleted. A node can be deleted from the list from three different
places namely.
Deleting a node at the beginning.
Deleting a node at the end.
Deleting a node at intermediate position.
5
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
1. algorithm traversing(head)
2. {
3. create Node *temp=head;
4. read temp=head;
5. if(temp==NULL) then
6. write "\nList is Empty";
7. end if;
8. while(temp!=NULL) do
9. write temp->data;
10. temp=temp->next;
11. end of while;
12. }
1. algorithm searching(value)
2. {
3. read pos=0,flag=0;
4. if(head==NULL) then
5. write List is Empty;
6. return;
7. endif;
8. create a Node *temp;
9. temp=head;
10. while(temp!=NULL) do
11. pos++;
12. if(temp->data==value) then
13. flag=1;
14. write element is found;
15. return;
16. endif ;
17. temp=temp->next;
6
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
1. algorithm insertion(pos,ch,n)
2. {
3. Node *prev,*cur;
4. head=Null;
5. read prev=NULL,cur=head,count=1;
6. create a Node *temp=new Node;
7. temp->data=n;
8. temp->next=NULL;
9. write “INSERT AS\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN
FIRST&LAST NODES";
10. write “Enter Your Choice:";
11. read ch;
12. switch(ch)
{
case 1:
temp->next=head;
head=temp;
break;
case 2:
last->next=temp;
last=temp;
break;
case 3:
write "\nEnter the Position to Insert:";
read pos;
while(count!=pos)
{
prev=cur;
cur=cur->next;
count++;
}
13. if(count==pos) then
14. prev->next=temp;
15. temp->next=cur;
16. else
17. write “Not Able to Insert";
18. break;
19. }
1. algorithm deletion(pos,ch)
2. Node *prev=NULL,*cur=head,count=1;
3. write “DELETE\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN FIRST&LAST
NODES";
7
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
case 2:
if(head==NULL)
cout<<"\nNot Able to Delete";
else
while(cur!=last)
prev=cur;
cur=cur->next;
end while;
end if;
if(cur==last)
write "\nDeleted Element is: "cur->data;
prev->next=NULL;
last=prev;
endif;
break;
case 3:
wirte “nEnter the Position of Deletion:";
read pos;
if(head==NULL)
write”/nNot Able to Delete";
else
while(count!=pos)
prev=cur;
cur=cur->next;
count++;
end while;
end if;
if(count==pos)
write "\nDeleted Element is: " cur->data;
prev->next=cur->next;
end if;
break;
7. }
#include<stdio.h>
#include<stdlib.h>
8
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
struct node
{
int data;
struct node *next;
};
void create()
{
struct node *temp;
temp=(struct node*)malloc(sizeof(struct node));
int n;
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n;
temp->next=NULL;
if(head==NULL)
{
head=temp;
last=head;
}
else
{
last->next=temp;
last=temp;
}
}
void insert()
{
struct node *prev,*cur,*temp;
prev=NULL;
cur=head;
int count=1,pos,ch,n;
temp=(struct node*)malloc(sizeof(struct node));
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n;
temp->next=NULL;
printf("\nINSERT AS\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN FIRST&LAST
NODES");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
temp->next=head;
head=temp;
9
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
break;
case 2:
last->next=temp;
last=temp;
break;
case 3:
printf("\nEnter the Position to Insert:");
scanf("%d",&pos);
printf("pos:%d,count=%d",pos,count);
while(count!=pos)
{
prev=cur;
cur=cur->next;
count++;
}
if(count==pos)
{
prev->next=temp;
temp->next=cur;
}
else
{
printf("\nNot Able to Insert");
}
break;
}
}
void delet()
{
struct node *prev=NULL,*cur=head;
int count=1,pos,ch;
printf("\nDELETE\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN FIRST&LAST
NODES");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
if(head!=NULL)
{
printf("Deleted Element is %d",head->data);
head=head->next;
}
else
printf("Not Able to Delete");
break;
case 2:
if(head==NULL)
{
printf("Not Able to Delete");
}
else
{
10
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
while(cur!=last)
{
prev=cur;
cur=cur->next;
}
if(cur==last)
{
printf("\nDeleted Element is:%d ",cur->data);
prev->next=NULL;
last=prev;
}
}
break;
case 3:
printf("\nEnter the Position of Deletion:");
scanf("%d",&pos);
if(head==NULL)
{
printf("\nNot Able to Delete");
}
else
{
while(count!=pos)
{
prev=cur;
cur=cur->next;
count++;
}
if(count==pos)
{
printf("\nDeleted Element is:%d ",cur->data);
prev->next=cur->next;
}
}
break;
}
}
void display()
{
struct node *temp=head;
if(temp==NULL)
{
printf("\nList is Empty");
}
while(temp!=NULL)
{
printf("%d",temp->data);
temp=temp->next;
if(temp!=NULL)
{
printf("-->");
}
}
}
void search()
11
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
{
int value,pos=0;
int flag=0;
if(head==NULL)
{
printf("List is Empty");
return;
}
printf("Enter the Value to be Searched:");
scanf("%d",&value);
struct node *temp;
temp=head;
while(temp!=NULL)
{
pos++;
if(temp->data==value)
{
flag=1;
printf("Element %d is Found at %d Position",value,pos);
return;
}
temp=temp->next;
}
if(!flag)
{
printf("Element %d not Found in the List",value);
}
}
int main()
{
int ch;
while(1)
{
printf("\n**** MENU ****");
printf("\n1:CREATE\n2:INSERT\n3:DELETE\n4:SEARCH\n5:DISPLAY\n6:EXIT\n");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
create();
break;
case 2:
insert();
break;
case 3:
delet();
break;
case 4:
search();
break;
case 5:
display();
break;
case 6:
12
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
return 0;
default:
printf("\n Invalid choice: Choose correct one");
break;
}
}
return 0;
}
The major problem with the stack implemented using an array is, it works only for a fixed
number of data values. That means the amount of data must be specified at the beginning of the
implementation itself. Stack implemented using an array is not suitable, when we don't know the size
of data which we are going to use. A stack data structure can be implemented by using a linked list
data structure. The stack implemented using linked list can work for an unlimited number of values.
That means, stack implemented using linked list works for the variable size of data. So, there is no
need to fix the size at the beginning of the implementation. The Stack implemented using linked list
can organize as many data values as we want.
In linked list implementation of a stack, every new element is inserted as 'top' element. That
means every newly inserted element is pointed by 'top'. Whenever we want to remove an element
from the stack, simply remove the node which is pointed by 'top' by moving 'top' to its previous node
in the list. The next field of the first element must be always NULL.
In the above example, the last inserted node is 99 and the first inserted node is 25. The order
of elements inserted is 25, 32,50 and 99.
13
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
int data;
struct node *next;
};
14
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
}
else
{
printf("Element at top is : %d", top->data);
}
}
// Main function
int main()
{
int choice,flag=1,value;
//Menu Driven Program using Switch
while(flag)
{
printf("\n1.Push \n2.Pop \n3.showTop \n4.displayStack \n5.exit\n");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("Enter Value:\n");
scanf("%d",&value);
push(value);
break;
case 2: pop();
break;
case 3: showTop();
break;
case 4: displayStack();
break;
case 5: flag=0;
break;
}
}
15
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
return 0;
}
The major problem with the queue implemented using an array is, It will work for an only
fixed number of data values. That means, the amount of data must be specified at the beginning itself.
Queue using an array is not suitable when we don't know the size of data which we are going to use.
A queue data structure can be implemented using a linked list data structure. The queue which is
implemented using a linked list can work for an unlimited number of values. That means, queue using
linked list can work for the variable size of data (No need to fix the size at the beginning of the
implementation). The Queue implemented using linked list can organize as many data values as we
want.
In linked list implementation of a queue, the last inserted node is always pointed by 'rear' and
the first node is always pointed by 'front'.
Example:
In above example, the last inserted node is 50 and it is pointed by 'rear' and the first inserted
node is 10 and it is pointed by 'front'. The order of elements inserted is 10, 15, 22 and 50.
// Structure of Node.
struct node
{
int data;
struct node *next;
};
int isEmpty()
{
if(front == NULL && rear == NULL)
{
return 1;
}
else
{
16
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
return 0;
}
}
17
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
//Main Function
int main()
{
int choice, flag=1, value;
while( flag == 1)
{
printf("\n1.enqueue 2.dequeue 3.showfront 4.displayQueue 5.exit\n");
scanf("%d",&choice);
switch (choice)
{
case 1: printf("Enter Value:\n");
scanf("%d",&value);
enqueue(value);
break;
case 2: dequeue();
break;
case 3: showfront();
break;
case 4: displayQueue();
break;
case 5: flag = 0;
break;
}
}
return 0;
}
Using a header node:
A header node is a special dummy node found at the front of the list. The use of header node is an
alternative to remove the first node in a list. For example, the picture below shows how the list with
data 10, 20 and 30 would be represented using a linked list without and with a header node:
18
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Note that if your linked lists do include a header node, there is no need for the special case code given
above for the remove operation; node n can never be the first node in the list, so there is no need to
check for that case. Similarly, having a header node can simplify the code that adds a node before a
given node n.
Note that if you do decide to use a header node, you must remember to initialize an empty list to
contain one (dummy) node, you must remember not to include the header node in the count of "real"
nodes in the list.
In a single linked list, every node has a link to its next node in the sequence. So, we can traverse from
one node to another node only in one direction and we cannot traverse back. We can solve this kind of
problem by using a double linked list. A double linked list can be defined as follows...
“Double linked list is a sequence of elements in which every element has links to its previous
element and next element in the sequence”
In a double linked list, every node has a link to its previous node and next node. So, we can
traverse forward by using the next field and can traverse backward by using the previous field. Every
node in a double linked list contains three fields and they are shown in the following figure...
Here, 'link1' field is used to store the address of the previous node in the sequence, 'link2' field
is used to store the address of the next node in the sequence and 'data' field is used to store the actual
value of that node.
Example:
19
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
In double linked list, the first node must be always pointed by head.
Always the previous field of the first node must be NULL.
Always the next field of the last node must be NULL.
Operations on Double Linked List:
1. Insertion
2. Deletion
3. Display
1. Insertion:
In a double linked list, the insertion operation can be performed in three ways as follows...
Insertion of a new node at the front of the list is shown above. As seen, the previous new node N
is set to null. Head points to the new node. The next pointer of N now points to N1 and previous of
N1 that was earlier pointing to Null now points to N.
Inserting node at the end of the doubly linked list is achieved by pointing the next pointer of new
node N to null. The previous pointer of N is pointed to N5. The „Next‟ pointer of N5 is pointed to N.
20
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
When we have to add a node before or after a particular node, we change the previous and next
pointers of the before and after nodes so as to appropriately point to the new node. Also, the new node
pointers are appropriately pointed to the existing nodes.
2. Deletion:
A node can be deleted from a doubly linked list from any position like from the front, end or
any other given position or given data. When deleting a node from the doubly linked list, we first
reposition the pointer pointing to that particular node so that the previous and after nodes do not have
any connection to the node to be deleted. We can then easily delete the node.
In a double linked list, the deletion operation can be performed in three ways as follows...
The deletion of node B from the given linked list. The sequence of operation remains
the same even if the node is first or last. The only care that should be taken is that if in case
the first node is deleted, the second node‟s previous pointer will be set to null.
Similarly, when the last node is deleted, the next pointer of the previous node will be
set to null. If in between nodes are deleted, then the sequence will be as above.
21
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Step 1 - Create a newNode with given value and newNode → previous as NULL.
Step 2 - Check whether list is Empty (head == NULL)
Step 3 - If it is Empty then, assign NULL to newNode → next and newNode to head.
Step4 - If it is not Empty then, assign head to newNode → next and newNode to head.
Step 1 - Create a newNode with given value and newNode → next as NULL.
Step 2 - Check whether list is Empty (head == NULL)
Step 3 - If it is Empty, then assign NULL to newNode → previous and newNode to head.
Step 4 - If it is not Empty, then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the last node in the list
(until temp → next is equal to NULL).
Step 6 - Assign newNode to temp → next and temp to newNode → previous.
22
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
23
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Step 12 - If temp is not the first node and not the last node, then
set temp of previous of next to temp of next (temp → previous → next = temp →
next), temp of next of previous to temp of previous (temp → next → previous = temp →
previous) and delete temp (free(temp)).
Implementation:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *prev,*next;
};
void create()
{
struct node *temp;
temp=(struct node*)malloc(sizeof(struct node));
int n;
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n;
temp->next=NULL;
temp->prev=NULL;
if(head==NULL)
{
head=temp;
last=head;
}
else
{
last->next=temp;
temp->prev=last;
24
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
last=temp;
}
}
void insert()
{
struct node *old,*cur,*temp;
old=NULL;
cur=head;
int count=1,pos,ch,n;
temp=(struct node*)malloc(sizeof(struct node));
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n;
temp->next=NULL;
temp->prev=NULL;
printf("\nINSERT AS\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN FIRST&LAST
NODES");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
temp->next=head;
head->prev=temp;
head=temp;
break;
case 2:
last->next=temp;
temp->prev=last;
last=temp;
break;
case 3:
printf("\nEnter the Position to Insert:");
scanf("%d",&pos);
while(count!=pos)
{
old=cur;
cur=cur->next;
count++;
}
if(count==pos)
{
temp->next=old->next;
cur->prev=temp;
old->next=temp;
temp->prev=old;
}
else
printf("\nNot Able to Insert");
break;
}
}
void delet()
{
25
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
while(cur!=last)
{
old=cur;
cur=cur->next;
}
if(cur==last)
{
printf("\nDeleted Element is: %d",cur->data);
if(old==NULL)
{
head=NULL;
}
else
{
old->next=NULL;
last=old;
}
}
}
26
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
break;
case 3:
printf("\nEnter the Position of Deletion:");
scanf("%d",&pos);
if(head==NULL)
{
printf("\nNot Able to Delete");
}
else
{
while(count!=pos)
{
old=cur;
cur=cur->next;
count++;
}
if(count==pos)
{
printf("\nDeleted Element is:%d",cur->data);
old->next=cur->next;
(cur->next)->prev=old;
}
}
break;
}
}
void display()
{
struct node *temp=head;
if(temp==NULL)
{
printf("\nList is Empty");
}
while(temp!=NULL)
{
printf("%p[%p,%d,%p]",temp,temp->prev,temp->data,temp->next);
temp=temp->next;
if(temp!=NULL)
{
printf("-->");
}
}
}
void search()
{
int value,pos=0;
int flag=0;
if(head==NULL)
{
printf("List is Empty");
return;
}
printf("Enter the Value to be Searched:");
scanf("%d",&value);
27
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
28
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
the first node in the list. A circular linked list is a sequence of elements in which every element has a
link to its next element in the sequence and the last element has a link to the first element.
That means circular linked list is similar to the single linked list except that the last node points to the
first node in the list.
Example:
Operations:
In a circular linked list, we perform the following operations...
1. Insertion
2. Deletion
3. Display
Before we implement actual operations, first we need to setup empty list. First perform the following
steps before implementing actual operations.
Step 1 - Include all the header files which are used in the program.
Step 2 - Declare all the user defined functions.
Step 3 - Define a Node structure with two members data and next
Step 4 - Define a Node pointer 'head' and set it to NULL.
Step 5 - Implement the main method by displaying operations menu and make suitable
function calls in the main method to perform user selected operation.
Insertion:
In a circular linked list, the insertion operation can be performed in three ways. They are as follows...
29
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Deletion:
In a circular linked list, the deletion operation can be performed in three ways those are as follows...
30
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Implementation:
31
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head=NULL,*last=NULL;
void create();
void insert();
void delet();
void display();
void search();
void create()
{
struct node *temp;
temp=(struct node*)malloc(sizeof(struct node));
int n;
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n;
temp->next=NULL;
if(head==NULL)
{
head=temp;
temp->next=head;
last=head;
}
else
{
temp->next=last->next;
last->next=temp;
last=temp;
}
}
void insert()
{
struct node *prev,*cur,*temp;
prev=NULL;
cur=head;
int count=1,pos,ch,n;
temp=(struct node*)malloc(sizeof(struct node));
printf("\nEnter an Element:");
scanf("%d",&n);
temp->data=n;
temp->next=NULL;
printf("\nINSERT AS\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN FIRST&LAST
NODES");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
32
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
temp->next=head;
head=temp;
last->next=head;
break;
case 2:
temp->next=last->next;
last->next=temp;
last=temp;
break;
case 3:
printf("\nEnter the Position to Insert:");
scanf("%d",&pos);
while(count!=pos)
{
prev=cur;
cur=cur->next;
count++;
}
if(count==pos)
{
temp->next=prev->next;
prev->next=temp;
}
else
printf("\nNot Able to Insert");
break;
}
}
void delet()
{
struct node *prev=NULL,*cur=head;
int count=1,pos,ch;
printf("\nDELETE\n1:FIRSTNODE\n2:LASTNODE\n3:IN BETWEEN FIRST&LAST
NODES");
printf("\nEnter Your Choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
if(head!=NULL)
{
if(head==last)
{
printf("\nDeleted Element is %d",head->data);
head=NULL;
}
else
{
printf("\nDeleted Element is %d",head->data);
head=head->next;
last->next=head;
}
}
else
33
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
while(cur!=last)
{
prev=cur;
cur=cur->next;
}
if(cur==last)
{
printf("\nDeleted Element is: %d",cur->data);
prev->next=head;
last=prev;
}
}
break;
case 3:
printf("\nEnter the Position of Deletion:");
scanf("%d",&pos);
if(head==NULL)
{
printf("\nNot Able to Delete");
}
else
{
while(count!=pos)
{
prev=cur;
cur=cur->next;
count++;
}
if(count==pos)
{
printf("\nDeleted Element is: %d",cur->data);
prev->next=cur->next;
}
}
break;
}
}
void display()
{
struct node *temp=head;
34
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
if(temp==NULL)
{
printf("\nList is Empty");
}
else
{
while(temp!=last)
{
printf("[data:%d,Present node address:%p,Next node address:%p]\n",temp-
>data,temp,temp->next);
temp=temp->next;
}
printf("[data:%d,Present node address:%p,Next node address:%p]",last-
>data,last,last->next);
}
}
void search()
{
int value,pos=0;
int flag=0;
if(head==NULL)
{
printf("List is Empty");
return;
}
printf("Enter the Value to be Searched:");
scanf("%d",&value);
struct node *temp;
temp=head;
do
{
pos++;
if(temp->data==value)
{
flag=1;
printf("Element %d is Found at %d Position",value,pos);
return;
}
temp=temp->next;
}while(temp!=head);
if(!flag)
{
printf("Element %d not Found in the List",value);
}
}
int main()
{
int ch;
while(1)
{
printf("\n**** MENU ****");
printf("\n1:CREATE\n2:INSERT\n3:DELETE\n4:SEARCH\n5:DISPLAY\n6:EXIT\n");
printf("\nEnter Your Choice:");
35
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
scanf("%d",&ch);
switch(ch)
{
case 1:
create();
break;
case 2:
insert();
break;
case 3:
delet();
break;
case 4:
search();
break;
case 5:
display();
break;
case 6:
return 0;
}
}
return 0;
}
Hashing:
In all search techniques like linear search, binary search and search trees, the time required to
search an element depends on the total number of elements present in that data structure. In all these
searching techniques, as the number of elements increases the time required to search an element also
increases linearly.
Hashing is another approach in which time required to search an element doesn't depend on
the total number of elements. Using hashing data structure, a given element is searched with constant
time complexity. Hashing is an effective way to reduce the number of comparisons to search an
element in a data structure.
Hashing is defined as follows...
“Hashing is the process of indexing and retrieving element (data) in a data structure to
provide a faster way of finding the element using a hash key”.
Here, the hash key is a value which provides the index value where the actual data is likely to
be stored in the data structure.
36
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
In this data structure, we use a concept called Hash table to store data. All the data values are inserted
into the hash table based on the hash key value. The hash key value is used to map the data with an
index in the hash table. And the hash key is generated for every data using a hash function.
That means every entry in the hash table is based on the hash key value generated using the
hash function.
Hash Table is defined as follows...
“Hash table is just an array which maps a key (data) into the data structure with the help of
hash function such that insertion, deletion and search operations are performed with constant time
complexity (i.e. O(1))”.
Hash tables are used to perform insertion, deletion and search operations very quickly in a
data structure. Using hash table concept, insertion, deletion, and search operations are accomplished
in constant time complexity. Generally, every hash table makes use of a function called hash function
to map the data into the hash table.
A hash function is defined as follows...
“Hash function is a function which takes a piece of data (i.e. key) as input and produces an
integer (i.e. hash value) as output which maps the data to a particular index in the hash table”.
Basic concept of hashing and hash table is shown in the following figure...
• To insert elements into the hash table we use hash function i.e., h(x)=x.
• Let us consider an example ,insert 5,7,10,12,15,100
Hash function is h(x)=x
Now, we will insert the values into the table
i.e., h(5)=5
h(7)=7
h(10)=10
h(12)=12
h(15)=15
Actually this function is a linear function, because of this we want to insert a large number
then we require large amount of memory, so there may be a wastage of memory. To overcome this,
we use another type of hash function called modulo division hash function.
37
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Collision:
If the hash function returns same hash key for more than one element, then that situation is
called Collision.
In this collision, first element will overwrite with the second element.
38
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
The situation where a newly inserted key maps to an already occupied slot in hash table is
called collision and must be handled using some collision handling technique.
There are mainly two methods to handle collision:
1. Separate Chaining
2. Open Addressing
1. Separate Chaining:
Separate Chaining is also called as closed addressing and open hashing. Separate chaining is
one of the most commonly used collision resolution techniques. It is usually implemented using
linked lists. In separate chaining, each element of the hash table is a linked list. To store an element in
the hash table you must insert it into a specific linked list. If there is any collision (i.e. two different
elements have same hash value) then store both the elements in the same linked list.
The cost of a lookup is that of scanning the entries of the selected linked list for the required
key. If the distribution of the keys is sufficiently uniform, then the average cost of a lookup depends
only on the average number of keys per linked list. For this reason, chained hash tables remain
effective even when the number of table entries (N) is much higher than the number of slots.
For separate chaining, the worst-case scenario is when all the entries are inserted into the
same linked list. The lookup procedure may have to scan all its entries, so the worst-case cost is
proportional to the number (N) of entries in the table.
Let us consider a simple hash function as “key mod 7” and sequence of keys as 50, 700, 76,
85, 92, 73, 101.
39
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
Advantages:
Simple to implement.
Hash table never fills up, we can always add more elements to chain.
Less sensitive to the hash function or load factors.
It is mostly used when it is unknown how many and how frequently keys may be inserted or
deleted.
Disadvantages:
Cache performance of chaining is not good as keys are stored using linked list. Open
addressing provides better cache performance as everything is stored in same table.
Wastage of Space (Some Parts of hash table are never used)
If the chain becomes long, then search time can become O(n) in worst case.
Uses extra space for links.
2. Open Addressing:
Like separate chaining, open addressing is a method for handling collisions. In Open
Addressing, all elements are stored in the hash table itself. In open addressing, instead of linked lists,
all entry elements are stored in the array itself. When a new entry has to be inserted, the hash index of
the hashed value is computed and then the array is examined (starting with the hashed index). If the
slot at the hashed index is unoccupied, then the entry record is inserted in slot at the hashed index else
it proceeds in some probe sequence until it finds an unoccupied slot.
40
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
a. Linear probing:
When searching for an entry, the array is scanned in the same sequence until either the target
element is found or an unused slot is found. This indicates that there is no such key in the table. The
name "open addressing" refers to the fact that the location or address of the item is not determined by
its hash value.
Linear probing is when the interval between successive probes is fixed (usually to 1). Let‟s
assume that the hashed index for a particular entry is index. The probing sequence for linear probing
will be:
index = index % hashTableSize
index = (index + 1) % hashTableSize
index = (index + 2) % hashTableSize
index = (index + 3) % hashTableSize
In such a case, we can search the next empty location in the array by looking into the next cell until
we find an empty cell. This technique is called linear probing.
Let us consider a simple hash function as “key mod 7” and sequence of keys as 50, 700, 76,
85, 92, 73, 101.
While inserting 85,there is a collision with slot 1,so we are using linear probing approach,
index = (index + 1) % hashTableSize
i.e., index=(85+1)%7
=86%7
=2 so now 85 will insert in slot 2 which is empty.
Next element 92, While inserting 92,there is a collision with slot 1so again we are using linear
probing approach
index = (index + 1) % hashTableSize=(92+1)%7=1, there is a collision with slot 2
index = (index + 2) % hashTableSize=(92+2)%7=3 so now 92 will insert in slot 3 which is empty.
b. Quadratic probing:
Quadratic probing is similar to linear probing and the only difference is the interval between
successive probes or entry slots. Here, when the slot at a hashed index for an entry record is already
occupied, you must start traversing until you find an unoccupied slot. The interval between slots is
computed by adding the successive value of an arbitrary polynomial in the original hashed index.
Let us assume that the hashed index for an entry is index and at index there is an occupied slot. The
probe sequence will be as follows:
41
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
While inserting 85,there is a collision with slot 1,so we are using quadratic probing approach,
index = (index + 12) % hashTableSize
i.e., index=(85+12)%7=(85+1)%7
=86%7
=2 so now 85 will insert in slot 2 which is empty.
Next element 92, While inserting 92,there is a collision with slot 1so again we are using linear
probing approach
index = (index + 12) % hashTableSize=(92+12)%7=1, there is a collision with slot 2.
index = (index + 22) % hashTableSize=(92+22)%7==(92+4)%7=5 so now 92 will insert in slot 5
which is empty.
0 700
1 50
2 85
3
4
5 92
6 76
42
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
6 76
Next element 101,
index = index % hashTableSize=101%7=3, there is a collision with slot 3.
index = (index + 12) % hashTableSize=(101+12)%7=4, so now 101 will insert in slot 4 which is
empty.
0 700
1 50
2 85
3 73
4 101
5 92
6 76
c. Double Hashing:
Double hashing is a collision resolving technique in Open Addressed Hash tables. Double
hashing is similar to linear probing and the only difference is the interval between successive probes.
Here, the interval between probes is computed by using two hash functions. Double hashing uses the
idea of applying a second hash function to key when a collision occurs.
Double hashing can be done using :
(hash1(index) + i * hash2(index)) % hashTableSize
Here hash1() and hash2() are hash functions and hashTableSize is size of hash table.
(We repeat by increasing i when collision occurs)
Let us consider a simple hash function as “key mod 13” and sequence of keys as 19,27,36,10.
Assume size of the hash table is 13.
Let say Hash1(index)=index%13
Hash2(index)=7-(index%7) ,where 7 is the random prime number.
43
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
4
5 10
6 19
7
8
9
10 36
11
12
13
#include<stdio.h>
/*
This is code for linear probing in open addressing. If you want to do quadratic probing and double
hashing which are also
open addressing methods in this code when I used hash function that (pos+1)%hFn in that place just
replace with another function.
*/
pos = element%size;
while(ary[pos]!= 0) {
if(ary[pos]== size)
break;
pos = (pos+1)%size;
n++;
if(n==size)
break; // If table is full we should break, if not check this, loop will go to infinite
loop.
}
if(n==size)
printf("Hash table was full of elements.No Place to insert this element\n");
else
ary[pos] = element; //Inserting element
}
int element,n=0,pos;
pos = element%size;
44
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
while(n++ != size){
if(ary[pos]==0){
printf("Element not found in hash table\n");
break;
}
else if(ary[pos]==element){
ary[pos]=0;
printf("Element deleted\n");
break;
}
else{
pos = (pos+1) % size;
}
}
if(--n==size)
printf("Element not found in hash table\n");
}
pos = element%size;
while(n++ != size){
if(ary[pos]==element){
printf("Element found at index %d",pos);
break;
}
else
if(ary[pos]==size ||ary[pos]!=0)
pos = (pos+1) %size;
}
if(--n==size)
printf("Element not found in hash table\n");
}
printf("Index\t Value\n");
for(i=0;i<size;i++)
printf("%d\t %d\n",i,ary[i]);
}
int main(){
int size,hFn,i,choice;
45
Data Structures and Algorithms UNIT-III—Linked Lists and Hashing
int ary[size];
for(i=0;i<size;i++)
ary[i]=0;
do{
printf("Enter your choice\n");
printf(" 1-> Insert\n 2-> Delete\n 3-> Display\n 4-> Searching\n 0-> Exit\n");
scanf("%d",&choice);
switch(choice){
case 1:
insert(ary,size);
break;
case 2:
delet(ary,size);
break;
case 3:
display(ary,size);
break;
case 4:
search(ary,size);
break;
default:
printf("Enter correct choice\n");
break;
}
}while(choice);
return 0;
}
46
Data Structures and Algorithms UNIT-IV—Trees
Unit-IV:
Trees: Introduction, Binary Trees, Binary Tree Traversals, Heaps, Binary Search
trees (BST) : Definition, Searching an element, Insertion into a BST, Deletion
from a BST.
Efficient Binary Search Trees: AVL Trees: Definition, Searching an element,
Insertion into a AVL
Objective:
To discuss and implement data structure to solve real world problems.
Outcome: Decide a suitable tree data structure to solve a real world problem.
Trees
In linear data structure data is organized in sequential order and in non-linear data structure data is
organized in random order. A tree is a very popular non-linear data structure used in a wide range of
applications. A tree data structure can be defined as follows...
“Tree is a non-linear data structure which organizes data in hierarchical structure and this is a
recursive definition”.
“Tree data structure is a collection of data (Node) which is organized in hierarchical structure
recursively”.
In tree data structure, every individual element is called as Node. Node in a tree data structure stores
the actual data of that particular element and link to next element in hierarchical structure.
In a tree data structure, if we have N number of nodes then we can have a maximum of N-1 number of
links.
Example:
1. Root:
In a tree data structure, the first node is called as Root Node. Every tree must have a root
node. We can say that the root node is the origin of the tree data structure. In any tree, there must be
only one root node. We never have multiple root nodes in a tree.
1
Data Structures and Algorithms UNIT-IV—Trees
2. Edge:
In a tree data structure, the connecting link between any two nodes is called as EDGE. In a tree with
'N' number of nodes there will be a maximum of 'N-1' number of edges.
3. Parent:
In a tree data structure, the node which is a predecessor of any node is called as PARENT
NODE. In simple words, the node which has a branch from it to any other node is called a parent
node. Parent node can also be defined as "The node which has child / children".
4. Child:
In a tree data structure, the node which is descendant of any node is called as CHILD Node.
In simple words, the node which has a link from its parent node is called as child node. In a tree, any
parent node can have any number of child nodes. In a tree, all the nodes except root are child nodes.
2
Data Structures and Algorithms UNIT-IV—Trees
5. Siblings:
In a tree data structure, nodes which belong to same Parent are called as SIBLINGS. In simple words,
the nodes with the same parent are called Sibling nodes.
6. Leaf:
In a tree data structure, the node which does not have a child is called as LEAF Node. In simple
words, a leaf is a node with no child.
In a tree data structure, the leaf nodes are also called as External Nodes. External node is also a node
with no child. In a tree, leaf node is also called as 'Terminal' node.
7. Internal Nodes:
In a tree data structure, the node which has at least one child is called as INTERNAL Node. In simple
words, an internal node is a node with at least one child.
3
Data Structures and Algorithms UNIT-IV—Trees
In a tree data structure, nodes other than leaf nodes are called as Internal Nodes. The root node is also
said to be Internal Node if the tree has more than one node. Internal nodes are also called as 'Non-
Terminal' nodes.
8. Degree:
In a tree data structure, the total number of children of a node is called as DEGREE of that Node. In
simple words, the Degree of a node is total number of children it has. The highest degree of a node
among all the nodes in a tree is called as 'Degree of Tree'.
9. Level:
In a tree data structure, the root node is said to be at Level 0 and the children of root node are at Level
1 and the children of the nodes which are at Level 1 will be at Level 2 and so on... In simple words, in
a tree each step from top to bottom is called as a Level and the Level count starts with '0' and
incremented by one at each level (Step).
10. Height:
4
Data Structures and Algorithms UNIT-IV—Trees
In a tree data structure, the total number of edges from leaf node to a particular node in the longest
path is called as HEIGHT of that Node. In a tree, height of the root node is said to be height of the
tree. In a tree, height of all leaf nodes is '0'.
11. Depth:
In a tree data structure, the total number of egdes from root node to a particular node is called as
DEPTH of that Node. In a tree, the total number of edges from root node to a leaf node in the longest
path is said to be Depth of the tree. In simple words, the highest depth of any leaf node in a tree is said
to be depth of that tree. In a tree, depth of the root node is '0'.
12. Path:
In a tree data structure, the sequence of Nodes and Edges from one node to another node is called as
PATH between that two Nodes. Length of a Path is total number of nodes in that path. In below
example the path A - B - E - J has length 4.
5
Data Structures and Algorithms UNIT-IV—Trees
In a tree data structure, each child from a node forms a subtree recursively. Every child node will
form a subtree on its parent node.
Tree Representations:
A tree data structure can be represented in two methods. Those methods are as follows...
1. List Representation
2. Left Child - Right Sibling Representation
1. List Representation:
In this representation, we use two types of nodes one for representing the node with data
called 'data node' and another for representing only references called 'reference node'. We start with a
6
Data Structures and Algorithms UNIT-IV—Trees
'data node' from the root node in the tree. Then it is linked to an internal node through a 'reference
node' which is further linked to any other node directly. This process repeats for all the nodes in the
tree.
The above example tree can be represented using List representation as follows...
In this representation, every node's data field stores the actual value of that node. If that node has left a
child, then left reference field stores the address of that left child node otherwise stores NULL. If that
node has the right sibling, then right reference field stores the address of right sibling node otherwise
stores NULL.
The above example tree can be represented using Left Child - Right Sibling representation as
follows...
7
Data Structures and Algorithms UNIT-IV—Trees
1. Binary Tree:
In a normal tree, every node can have any number of children. A binary tree is a special type of tree
data structure in which every node can have a maximum of 2 children. One is known as a left child
and the other is known as right child.
“A tree in which every node can have a maximum of two children is called Binary Tree”. In a binary
tree, every node can have either 0 children or 1 child or 2 children but not more than 2 children.
Example:
In a binary tree, every node can have a maximum of two children. But in strictly binary tree, every
node should have exactly two children or none. That means every internal node must have exactly two
children. A strictly Binary Tree can be defined as follows...
“A binary tree in which every node has either two or zero number of children is called Strictly Binary
Tree”.
Strictly binary tree is also called as Full Binary Tree or Proper Binary Tree or 2-Tree.
Example:
8
Data Structures and Algorithms UNIT-IV—Trees
In a binary tree, every node can have a maximum of two children. But in strictly binary tree, every
node should have exactly two children or none and in complete binary tree all the nodes must have
exactly two children and at every level of complete binary tree there must be 2level number of nodes.
For example at level 2 there must be 22 = 4 nodes and at level 3 there must be 23 = 8 nodes.
“A binary tree in which every internal node has exactly two children and all leaf nodes are at same
level is called Complete Binary Tree.”
Complete binary tree is also called as Perfect Binary Tree.
9
Data Structures and Algorithms UNIT-IV—Trees
In above figure, a normal binary tree is converted into full binary tree by adding dummy nodes (In
pink colour).
1. Array Representation
2. Linked List Representation
To represent a binary tree of depth 'n' using array representation, we need one dimensional array with
a maximum size of 2n+1 -1.
10
Data Structures and Algorithms UNIT-IV—Trees
The above example of the binary tree represented using Linked list representation is shown as
follows...
Traversal is a process to visit all the nodes of a tree and may print or display their values too.
Because, all nodes are connected via edges (links) we always start from the root (head) node. That is,
we cannot randomly access a node in a tree, so we need to follow some order in which all the nodes of
that binary tree must be displayed. In any binary tree, displaying order of nodes depends on the
traversal method.
„Displaying (or) visiting order of nodes in a binary tree is called as Binary Tree Traversal.”
11
Data Structures and Algorithms UNIT-IV—Trees
part so we visit 'G' and then visit G's right child K. With this we have completed the left part of node
C. Then visit root node 'C' and next visit C's right child 'H' which is the rightmost child in the tree. So
we stop the process.
That means here we have visited in the order of I - D - J - B - F - A - G - K - C - H using In-Order
Traversal.
In-Order Traversal for above example of binary tree is
I-D-J-B-F-A-G-K-C-H
12
Data Structures and Algorithms UNIT-IV—Trees
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *left,*right;
};
struct node *root=NULL;
int level=-1;
void create()
{
if(root==NULL)
{
struct node *temp = (struct node*)malloc(sizeof(struct node));
int value;
printf("Enter a value : ");
scanf("%d",&value);
temp->data = value;
temp->left = NULL;
temp->right = NULL;
root = temp;
level = 0;
}
else
{
printf("Root already exists");
}
}
void Insert()
{
if(root==NULL){
printf("Root is NULL");
printf("Create the tree to insert elements.");
create();
13
Data Structures and Algorithms UNIT-IV—Trees
}
else{
struct node *temp = (struct node*)malloc(sizeof(struct node));
int value;
printf("Enter any value : ");
scanf("%d",&value);
temp->data = value;
temp->left = NULL;
temp->right = NULL;
level = 1;
}
level = 2;
}
}
}
14
Data Structures and Algorithms UNIT-IV—Trees
{
printf("%d ",temp->data);
if(temp->left)
preorder(temp->left);
if(temp->right)
preorder(temp->right);
}
else{
printf("Cannot display");
return;
}
}
printf("%d ",temp->data);
if(temp->right)
inorder(temp->right);
}
else{
printf("Cannot display");
return;
}
}
if(temp->right)
postorder(temp->right);
printf("%d ",temp->data);
}
else{
printf("Cannot display");
return;
15
Data Structures and Algorithms UNIT-IV—Trees
}
}
int main()
{
int ch,dis;
while(1)
{
printf("\n1.Create\n2.Insert\n3.Display\n0.EXIT\n");
printf("Enter your choice : ");
scanf("%d",&ch);
switch(ch)
{
case 1: create(); break;
case 2: Insert(); break;
case 3: printf("1.Preorder\n2.Inorder\n3.Postorder\n");
printf("Enter your choice : ");
scanf("%d",&dis);
switch(dis)
{
case 1: preorder(root); break;
case 2: inorder(root); break;
case 3: postorder(root); break;
default : printf("Choose the correct option."); break;
}
break;
case 0: return 0;
default : printf("Choose the correct option."); break;
}
}
}
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *left,*right;
};
struct node *root=NULL;
int level=-1;
void create()
{
if(root==NULL)
{
16
Data Structures and Algorithms UNIT-IV—Trees
void Insert()
{
if(root==NULL){
printf("Root is NULL");
printf("Create the tree to insert elements.");
create();
}
else{
struct node *temp = (struct node*)malloc(sizeof(struct node));
int value;
printf("Enter any value : ");
scanf("%d",&value);
temp->data = value;
temp->left = NULL;
temp->right = NULL;
level = 1;
}
17
Data Structures and Algorithms UNIT-IV—Trees
level = 2;
}
}
}
void preorder(struct node *temp)
{
if(temp!=NULL)
{
printf("%d ",temp->data);
if(temp->left)
preorder(temp->left);
if(temp->right)
preorder(temp->right);
}
else{
printf("tree doesnot exist");
return;
}
}
printf("%d ",temp->data);
if(temp->right)
inorder(temp->right);
}
18
Data Structures and Algorithms UNIT-IV—Trees
else{
printf("tree doesnot exist");
return;
}
}
if(temp->right)
postorder(temp->right);
printf("%d ",temp->data);
}
else{
printf("tree doesnot exist");
return;
}
}
void deleteTree(struct node* temp)
{
if (temp == NULL) return;
/* first delete both subtrees */
deleteTree(temp->left);
deleteTree(temp->right);
/* do the subtrees */
mirror(node->left);
mirror(node->right);
19
Data Structures and Algorithms UNIT-IV—Trees
node->left = node->right;
node->right = temp;
}
}
void printLevelOrder(struct node* root)
{
int h = height(root);
int i;
for (i = 0; i <= h; i++)
printCurrentLevel(root, i);
}
void printCurrentLevel(struct node* root, int level)
{
if (root == NULL)
return;
if (level == 1)
printf("%d ", root->data);
else if (level > 1) {
printCurrentLevel(root->left, level-1);
printCurrentLevel(root->right, level-1);
}
}
int height(struct node* node)
{
if (node == NULL)
return 0;
else {
/* compute the height of each subtree */
int lheight = height(node->left);
int rheight = height(node->right);
int main()
{
int ch,dis;
while(1)
{
printf("\n1.Create\n2.Insert\n3.Display\n4.DeleteTree\n5.mirror\n6.levelorder\n0.EXIT\n");
printf("Enter your choice : ");
scanf("%d",&ch);
switch(ch)
20
Data Structures and Algorithms UNIT-IV—Trees
{
case 1: create(); break;
case 2: Insert(); break;
case 3: printf("1.Preorder\n2.Inorder\n3.Postorder\n");
printf("Enter your choice : ");
scanf("%d",&dis);
switch(dis)
{
case 1: preorder(root); break;
case 2: inorder(root); break;
case 3: postorder(root); break;
default : printf("Choose the correct option."); break;
}
break;
case 4: deleteTree(root);
root=NULL;
break;
case 5: mirror(root);
break;
case 6: printLevelOrder(root);
break;
case 0: return 0;
default : printf("Choose the correct option."); break;
}
}
}
Threaded Binary Trees:
A binary tree can be represented using array representation or linked list representation. When a
binary tree is represented using linked list representation, the reference part of the node which doesn't
have a child is filled with a NULL pointer. In any binary tree linked list representation, there is a
number of NULL pointers are more than actual pointers i.e., if there are 2N number of reference
fields, then N+1 number of reference fields are filled with NULL ( N+1 are NULL out of 2N ). This
NULL pointer does not play any role except indicating that there is no link (no child).
A. J. Perlis and C. Thornton have proposed new binary tree called "Threaded Binary Tree", which
makes use of NULL pointers to improve its traversal process. In a threaded binary tree, NULL
pointers are replaced by references of other nodes in the tree. These extra references are called
as threads.
“Threaded Binary Tree is also a binary tree in which all left child pointers that are NULL (in
Linked list representation) points to its in-order predecessor, and all right child pointers that are
NULL (in Linked list representation) points to its in-order successor.”
If there is no in-order predecessor or in-order successor, then it points to the root node.
Consider the following binary tree...
21
Data Structures and Algorithms UNIT-IV—Trees
To convert the above example binary tree into a threaded binary tree, first find the in-order traversal
of that tree...
In-order traversal of above binary tree...
H-D-I-B-E-A-F-J-C–G
When we represent the above binary tree using linked list representation, nodes H, I, E, F, J and G left
child pointers are NULL. This NULL is replaced by address of its in-order predecessor respectively (I
to D, E to B, F to A, J to F and G to C), but here the node H does not have its in-order predecessor, so
it points to the root node A. And nodes H, I, E, J and G right child pointers are NULL. These NULL
pointers are replaced by address of its in-order successor respectively (H to D, I to B, E to A, and J to
C), but here the node G does not have its in-order successor, so it points to the root node A.
Above example binary tree is converted into threaded binary tree as follows.
In a binary tree, every node can have a maximum of two children but there is no need to maintain the
order of nodes basing on their values. In a binary tree, the elements are arranged in the order they
arrive at the tree from top to bottom and left to right.
A binary tree has the following time complexities...
Search Operation - O(n)
Insertion Operation - O(1)
22
Data Structures and Algorithms UNIT-IV—Trees
In a binary search tree, all the nodes in the left subtree of any node contains smaller values and all the
nodes in the right subtree of any node contains larger values as shown in the following figure...
Example:
The following tree is a Binary Search Tree. In this tree, left subtree of every node contains nodes with
smaller values and right subtree of every node contains larger values.
“Every binary search tree is a binary tree but every binary tree need not to be binary search tree.”
Operations on a Binary Search Tree:
The following operations are performed on a binary search tree...
1. Search
2. Insertion
3. Deletion
23
Data Structures and Algorithms UNIT-IV—Trees
Step 6- If search element is larger, then continue the search process in right subtree.
Step 7 - Repeat the same until we find the exact element or until the search element is compared with
the leaf node
Step 8 - If we reach to the node having the value equal to the search value then display "Element is
found" and terminate the function.
Step 9 - If we reach to the leaf node and if it is also not matched with the search element, then display
"Element is not found" and terminate the function.
Step 1 - Create a newNode with given value and set its left and right to NULL.
Step 2 - Check whether tree is Empty.
Step 3 - If the tree is Empty, then set root to newNode.
Step 4 - If the tree is Not Empty, then check whether the value of newNode is smaller or larger than
the node (here it is root node).
Step 5 - If newNode is smaller than or equal to the node then move to its left child. If newNode is
larger than the node then move to its right child.
Step 6- Repeat the above steps until we reach to the leaf node (i.e., reaches to NULL).
Step 7 - After reaching the leaf node, insert the newNode as left child if the newNode is smaller or
equal to that leaf node or else insert it as right child.
24
Data Structures and Algorithms UNIT-IV—Trees
Implementation:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *left,*right;
};
struct node *root=NULL;
void insert()
{
struct node *cur,*parent=NULL;
int n;
struct node *temp = (struct node*)malloc(sizeof(struct node));
printf("enter a number");
scanf("%d",&n);
temp->data=n;
temp->left=NULL;
temp->right=NULL;
if(root==NULL)
{
root=temp;
}
else
{
cur=root;
while(cur)
{
parent=cur;
if(temp->data>cur->data)
{
cur=cur->right;
}
else
{
cur=cur->left;
}
}
if(temp->data>parent->data)
{
parent->right=temp;
}
else
{
parent->left=temp;
}
}
}
void delet()
{
struct node *cur=root,*parent=NULL;
25
Data Structures and Algorithms UNIT-IV—Trees
int n;
printf("enter a node data which u want to delete");
scanf("%d",&n);
if(root==NULL)
{
printf("Tree is empty");
return;
}
else
{
while(cur!=NULL)
{
if(cur->data==n)
{
break;
}
else
{
parent=cur;
if(n>cur->data)
{
cur=cur->right;
}
else
{
cur=cur->left;
}
}
}
if(cur==NULL)
{
printf("Invalid data node.Try again");
return;
}
}
//Leaf Node
if( cur->left == NULL && cur->right == NULL)
{
if(parent->left == cur)
{
parent->left = NULL;
}
else
{
parent->right = NULL;
}
return;
}
//Node with single child
26
Data Structures and Algorithms UNIT-IV—Trees
{
parent->left = cur->right;
}
else
{
parent->right = cur->right;
}
}
else // left child present, no right child
{
if(parent->left == cur)
{
parent->left = cur->left;
}
else
{
parent->right = cur->left;
}
}
return;
}
27
Data Structures and Algorithms UNIT-IV—Trees
}
return;
}
}
28
Data Structures and Algorithms UNIT-IV—Trees
{
if(t->left) postorder(t->left);
if(t->right) postorder(t->right);
printf("%d ",t->data);
}
else return;
}
int main()
{
int ch,n;
while(1)
{
printf("\n");
printf(" Binary Search Tree Operations\n ");
printf(" ----------------------------- ");
printf(" \n1. Insertion/Creation ");
printf(" \n2. Pre-Order Traversal ");
printf(" \n3. In-Order Traversal ");
printf(" \n4. Post-Order Traversal ");
printf(" \n5. Delete ");
printf(" \n6. Search ");
printf(" \n7. Exit ");
printf(" \nEnter your choice : ");
scanf("%d",&ch);
switch(ch)
{
case 1 : insert();
break;
case 2 : preorder(root);
break;
case 3 : inorder(root);
break;
case 4 : postorder(root);
break;
case 5 : delet();
break;
case 6: printf("enter an element to be search");
scanf("%d",&n);
search(root,n);
break;
case 7: return 0;
default: printf("Selct valid option");
break;
}
}
}
AVL Tree:
29
Data Structures and Algorithms UNIT-IV—Trees
AVL tree is a height-balanced binary search tree. That means, an AVL tree is also a binary search
tree but it is a balanced tree. A binary tree is said to be balanced if, the difference between the heights
of left and right subtree of every node in the tree is either -1, 0 or +1. In other words, a binary tree is
said to be balanced if the height of left and right children of every node differ by either -1, 0 or +1. In
an AVL tree, every node maintains an extra information known as balance factor. The AVL tree was
introduced in the year 1962 by G.M. Adelson-Velsky and E.M. Landis.
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. In the following explanation, we calculate as
follows...
The above tree is a binary search tree and every node is satisfying balance factor condition. So this
tree is said to be an AVL tree.
“Every AVL Tree is a binary search tree but every Binary Search Tree need not be AVL tree.”
30
Data Structures and Algorithms UNIT-IV—Trees
31
Data Structures and Algorithms UNIT-IV—Trees
In an AVL tree, the search operation is performed with O(log n) time complexity. The search
operation in the AVL tree is similar to the search operation in a Binary search tree. We use the
following steps to search an element in AVL tree...
In an AVL tree, the insertion operation is performed with O(log n) time complexity. In AVL Tree,
a new node is always inserted as a leaf node. The insertion operation is performed as follows...
Step 1 - Insert the new element into the tree using Binary Search Tree insertion logic.
Step 2 - After insertion, check the Balance Factor of every node.
Step 3 - If the Balance Factor of every node is 0 or 1 or -1 then go for next operation.
Step 4 - If the Balance Factor of any node is other than 0 or 1 or -1 then that tree is said to be
imbalanced. In this case, perform suitable Rotation to make it balanced and go for next operation.
#include<stdio.h>
32
Data Structures and Algorithms UNIT-IV—Trees
#include<stdlib.h>
/* Helper function that allocates a new node with the given key and NULL left and right
pointers. */
struct node* newNode(int key)
{
struct node *temp = (struct node*)malloc(sizeof(struct node));
temp->key = key;
temp->left = NULL;
temp->right = NULL;
temp->height = 1; // new node is initially
// added at leaf
return(temp);
}
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left),
height(y->right)) + 1;
33
Data Structures and Algorithms UNIT-IV—Trees
x->height = max(height(x->left),
height(x->right)) + 1;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left),
height(x->right)) + 1;
y->height = max(height(y->left),
height(y->right)) + 1;
34
Data Structures and Algorithms UNIT-IV—Trees
return temp;
}
return current;
}
35
Data Structures and Algorithms UNIT-IV—Trees
// No child case
if (temp == NULL)
{
temp = root;
root = NULL;
}
else // One child case
*root = *temp; // Copy the contents of
// the non-empty child
// free(temp);
}
else
{
// node with two children: Get the inorder
// successor (smallest in the right subtree)
struct node *temp = minValueNode(root->right);
36
Data Structures and Algorithms UNIT-IV—Trees
return root;
return root;
}
37
Data Structures and Algorithms UNIT-IV—Trees
// Driver Code
int main()
{
struct node *root = NULL;
return 0;
}
Heaps:
Heap data structure is a specialized binary tree-based data structure. Heap is a binary tree with
special characteristics. In a heap data structure, nodes are arranged based on their values. A heap data
structure sometimes also called as Binary Heap.
38
Data Structures and Algorithms UNIT-IV—Trees
There are two types of heap data structures and they are as follows...
1. Max Heap
2. Min Heap
Every heap data structure has the following properties...
Property #1 (Ordering): Nodes must be arranged in an order according to their values based on Max
heap or Min heap.
Property #2 (Structural): All levels in a heap must be full except the last level and all nodes must be
filled from left to right strictly.
Max Heap:
Max heap data structure is a specialized full binary tree data structure. In a max heap nodes are
arranged based on node value.
Example:
Above tree is satisfying both Ordering property and Structural property according to the Max Heap
data structure.
Operations on Max Heap:
The following operations are performed on a Max heap data structure...
1. Finding Maximum
2. Insertion
3. Deletion
Finding the node which has maximum value in a max heap is very simple. In a max heap, the root
node has the maximum value than all other nodes. So, directly we can display root node value as the
maximum value in max heap.
Insertion Operation in Max Heap:
Insertion Operation in max heap is performed as follows...
39
Data Structures and Algorithms UNIT-IV—Trees
Example:
Consider the above max heap. Insert a new node with value 85.
Step 1 - Insert the newNode with value 85 as last leaf from left to right. That means newNode is
added as a right child of node with value 75. After adding max heap is as follows...
Step 2 - Compare newNode value (85) with its Parent node value (75). That means 85 > 75
Step 3 - Here newNode value (85) is greater than its parent value (75), then swap both of them. After
swapping, max heap is as follows...
40
Data Structures and Algorithms UNIT-IV—Trees
Step 4 - Now, again compare newNode value (85) with its parent node value (89).
Here, newNode value (85) is smaller than its parent node value (89). So, we stop insertion process.
Finally, max heap after insertion of a new node with value 85 is as follows...
41
Data Structures and Algorithms UNIT-IV—Trees
In a max heap, deleting the last node is very simple as it does not disturb max heap properties.
Deleting root node from a max heap is little difficult as it disturbs the max heap properties. We use
the following steps to delete the root node from a max heap...
Step 1 - Swap the root node with last node in max heap
Step 2 - Delete last node.
Step 3 - Now, compare root value with its left child value.
Step 4 - If root value is smaller than its left child, then compare left child with its right sibling. Else
goto Step 6
Step 5 - If left child value is larger than its right sibling, then swap root with left child otherwise swap
root with its right child.
Step 6 - If root value is larger than its left child, then compare root value with its right child value.
Step 7 - If root value is smaller than its right child, then swap root with right child otherwise stop the
process.
Step 8 - Repeat the same until root node fixes at its exact position.
Example:
Consider the above max heap. Delete root node (90) from the max heap.
Step 1 - Swap the root node (90) with last node 75 in max heap. After swapping max heap is as
follows...
Step 2 - Delete last node. Here the last node is 90. After deleting node with value 90 from heap, max
heap is as follows...
42
Data Structures and Algorithms UNIT-IV—Trees
Step 3 - Compare root node (75) with its left child (89).
Here, root value (75) is smaller than its left child value (89). So, compare left child (89) with its right
sibling (70).
Step 4 - Here, left child value (89) is larger than its right sibling (70), So, swap root (75) with left
child (89).
Here, node with value 75 is larger than its left child. So, we compare node 75 with its right child 85.
43
Data Structures and Algorithms UNIT-IV—Trees
Step 6 - Here, node with value 75 is smaller than its right child (85). So, we swap both of them. After
swapping max heap is as follows...
Step 7 - Now, compare node with value 75 with its left child (15).
Here, node with value 75 is larger than its left child (15) and it does not have right child. So we stop
the process.
44
Data Structures and Algorithms UNIT-IV—Trees
45
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Unit-V:
Graphs: Graph Abstract Data Type, Elementary Graph operations (DFS and BFS),
Minimum Cost Spanning Trees (Prim‘s and Kruskal‘s Algorithms).
Sorting and Searching: Insertion sort, Quick sort, Best computing time for
Sorting, Merge sort, Heap sort, shell sort, Sorting on Several Keys, List and Table
Sorts, Summary of Internal Sorting, Linear and Binary Search algorithms.
Objective:
To introduce various searching and sorting techniques.
Outcome: Interpret suitable searching and sorting techniques and implement non
linear data structures using graphs to solve various computing problems.
1. Selection Sort:
Selection Sort algorithm is used to arrange a list of elements in a particular order (Ascending
or Descending). In selection sort, the first element in the list is selected and it is compared repeatedly
with all the remaining elements in the list. If any element is smaller than the selected element (for
Ascending order), then both are swapped so that first position is filled with the smallest element in the
sorted order. Next, we select the element at a second position in the list and it is compared with all the
remaining elements in the list. If any element is smaller than the selected element, then both are
swapped. This procedure is repeated until the entire list is sorted.
In selection sort, element at first location (0th location) is considered as least element, and it
is compared with the other elements of the array. If any element is found to be minimum than the
element in first location, then that location is taken as minimum and element in that location will
be the minimum element.
After completing a set of comparisons, the minimum element is swapped with the element in
first location (0th location).
Then again element second location is considered as minimum and it is compared with the
other elements of array and the process continues till the array is sorted in ascending order.
Note: After first pass, smallest element in given list occupies the first position. After second pass,
second largest element is placed at second position and so on..
Step 1 - Select the first element of the list (i.e., Element at first position in the list).
Step 2: Compare the selected element with all the other elements in the list.
Step 3: In every comparison, if any element is found smaller than the selected element (for Ascending
order), then both are swapped.
Step 4: Repeat the same procedure with element in the next position in the list till the entire list is
sorted.
Implementation:
#include<stdio.h>
void main( )
{
int a[100], n, i, j, temp, min;
1
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
To sort an unsorted list with 'n' number of elements, we need to make ((n-1)+(n-2)+(n-3)+......+1) = (n
(n-1))/2 number of comparisons in the worst case. If the list is already sorted then it requires 'n'
number of comparisons.
2. Bubble Sort:
In bubble sort each element is compared with its adjacent element. If first element is larger
than second one, then both elements are swapped. Otherwise, element are not swapped. Consider the
following list of numbers.
Algorithm:
begin BubbleSort(list)
2
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
return list
end BubbleSort
Implementation:
#include<stdio.h>
int main()
{
int i, j, n, bubble[20], temp;
printf("enter range of elements");
scanf("%d",&n);
printf("enter elements");
for(i=0;i<n; i++)
{
scanf("%d",&bubble[i]);
}
for(i=0; i<n; i++)
{
for(j=0;j<n-i-1;j++)
{
if(bubble[j] > bubble[j+1])
{
temp=bubble[j];
bubble[j]=bubble[j+1];
bubble[j+1]=temp;
}
}
}
printf("after sorting");
for(i=0; i<n; i++)
{
printf("%d ",bubble[i]);
}
}
3. Insertion Sort:
Insertion sort algorithm arranges a list of elements in a particular order. In insertion sort algorithm,
every iteration moves an element from unsorted portion to sorted portion until all the elements are
sorted in the list.
Algorithm:
Step 1 - Assume that first element in the list is in sorted portion and all the remaining elements are in
unsorted portion.
Step 2: Take first element from the unsorted portion and insert that element into the sorted portion in
the order specified.
Step 3: Repeat the above process until all the elements from the unsorted portion are moved into the
sorted portion.
3
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Implementation:
//Insertion Sort
#include<stdio.h>
int main()
{
int i, j, key,n, a[20];
printf("enter range of elements: ");
scanf("%d", &n);
printf("enter elements\n");
for(i=0;i<n; i++)
{
scanf("%d", &a[i]);
}
for(i=1; i<n; i++)
{
key=a[i];
j=i-1;
while(j>=0&&a[j]>key)
{
a[j+1]=a[j];
j=j-1;
}
a[j+1]=key;
}
printf("after sorting ");
for(i=0; i<n; i++)
{
printf("%d ",a[i]);
}
}
Complexity of the Insertion Sort Algorithm:
To sort an unsorted list with 'n' number of elements, we need to make (1+2+3+......+n-1) = (n
(n-1))/2 number of comparisons in the worst case. If the list is already sorted then it requires 'n'
number of comparisons.
4. Quick Sort:
Quick sort is a fast sorting algorithm used to sort a list of elements. Quick sort algorithm is
invented by C. A. R. Hoare.
The quick sort algorithm attempts to separate the list of elements into two parts and then sort
each part recursively. That means it use divide and conquer strategy. In quick sort, the partition of the
list is performed based on the element called pivot. Here pivot element is one of the elements in the
list.
The list is divided into two partitions such that "all elements to the left of pivot are smaller
than the pivot and all elements to the right of pivot are greater than or equal to the pivot".
Algorithm:
Step 1 - Consider the first element of the list as pivot (i.e., Element at first position in the list).
4
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Step 2 - Define two variables i and j. Set i and j to second and last elements of the list respectively.
Step 3 - Increment i until list[i] > pivot then stop.
Step 4 - Decrement j until list[j] < pivot then stop.
Step 5 - If i < j then exchange list[i] and list[j].
Step 6 - Repeat steps 3,4 & 5 until i > j.
Step 7 - Exchange the pivot element with list[j] element.
Implementation:
//Quick Sort
#include<stdio.h>
void QuickSort(int [],int,int);
int main()
{
int i, n, list[20];
printf("enter range of elements");
scanf("%d",&n);
printf("enter elements\n");
for(i=0;i<n; i++)
{
scanf("%d",&list[i]);
}
QuickSort(list,0,n-1);
printf("after sorting: ");
for(i=0; i<n; i++)
{
printf("%d ",list[i]);
}
}
void QuickSort(int list[],int first,int last)
{
int pivot,i,j,temp;
if(first < last)
{
pivot = first;
i = first;
j = last;
while(i < j)
{
while(list[i] <= list[pivot] && i < last)
i++;
while(list[j] > list[pivot])
j--;
if(i < j)
{
temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
temp = list[pivot];
list[pivot] = list[j];
list[j] = temp;
5
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
QuickSort(list,first,j-1);
QuickSort(list,j+1,last);
}
}
Complexity of the Quick Sort Algorithm:
To sort an unsorted list with 'n' number of elements, we need to make ((n-1)+(n-2)+(n-
3)+......+1) = (n (n-1))/2 number of comparisons in the worst case. If the list is already sorted, then it
requires 'n' number of comparisons.
5. Merge Sort:
Merge sort is a sorting technique based on divide and conquer technique. With worst-case
time complexity being Ο(n log n), it is one of the most respected algorithms. Merge sort first divides
the array into equal halves and then combines them in a sorted manner.
6
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Algorithm:
Implementation:
//Merge Sort
#include<stdio.h>
void mergesort(int a[],int lb,int mid, int ub)
{
int i=lb,j=mid+1,k=0,b[50];
while(i<=mid&&j<=ub)
{
if(a[i]<a[j])
{
b[k++]=a[i++];
}
else
{
7
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
b[k++]=a[j++];
}
}
while(i<=mid)
{
b[k++]=a[i++];
}
while(j<=ub)
{
b[k++]=a[j++];
}
for(k=0;k<=ub-lb;k++)
{
a[k+lb]=b[k];
}
}
void merge(int a[],int low,int high)
{
int mid;
if(low<high)
{
mid=(low+high)/2;
merge(a,low,mid);
merge(a,mid+1,high);
mergesort(a,low,mid,high);
}
}
int main()
{
int i, a[30],n;
printf("Enter the number of elements: ");
scanf("%d",&n);
printf("Enter elements:\n");
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
printf("\n\nBefore sorting:");
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
merge(a,0,n-1);
printf("\n\nAfter sorting:");
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
return 0;
}
Complexity of the Merge Sort Algorithm:
Worst Case Time Complexity : O(n*log n)
Best Case Time Complexity : O(n*log n)
Average Time Complexity : O(n*log n)
8
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
6. Heap Sort:
Heap sort is one of the sorting algorithms used to arrange a list of elements in order. Heapsort
algorithm uses one of the tree concepts called Heap Tree. In this sorting algorithm, we use Max Heap
to arrange list of elements in Descending order and Min Heap to arrange list of elements in Ascending
order.
Algorithm:
Implementation:
For example please go through the heap tree concept...
//Heap Sort
#include <stdio.h>
void heapify(int arr[], int n, int i)
{
int smallest = i;
int l = 2 * i + 1;
int r = 2 * i + 2;
if (l < n && arr[l] < arr[smallest])
smallest = l;
if (r < n && arr[r] < arr[smallest])
smallest = r;
if (smallest != i) {
// swap arr[i] with a[smallest]
int temp = arr[i];
arr[i] = arr[smallest];
arr[smallest] = temp;
heapify(arr, n, smallest);
}
}
void heapSort(int arr[], int n)
{
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
for (int i = n - 1; i >= 0; i--) {
// swap arr[0] with arr[i]
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
heapify(arr, i, 0);
}
}
int main()
{
int a[50],n,i;
printf("Enter the size of the array:");
scanf("%d",&n);
9
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
To sort an unsorted list with 'n' number of elements, following are the complexities...
7. Shell Sort:
Shell sort is a special case of insertion sort. It was designed to overcome the drawbacks of
insertion sort. Thus, it is more efficient than insertion sort. In shell sort, we can swap or exchange the
far away items in addition to adjacent items.
In insertion sort, we could move the elements ahead only by one position at a time. If we wish
to move an element to a faraway position in insertion sort, a lot of movements were involved thus
increasing the execution time. Shell sort overcomes this problem of insertion sort by allowing
movement and swap of far-away elements as well.
This sorting technique works by sorting elements in pairs, far away from each other and
subsequently reduces their gap. The gap is known as the interval. We can calculate this gap/interval as
total no.of elements/2(i.e.,n/2) and then n/4,n/8.....
10
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
We compare values in each sub-list and swap them (if necessary) in the original array. After this step,
the new array should look like this −
Then, we take interval of 1 and this gap generates two sub-lists - {14, 27, 35, 42}, {19, 10, 33, 44}
We compare and swap the values, if required, in the original array. After this step, the array should
look like this −
Finally, we sort the rest of the array using interval of value 1. Shell sort uses insertion sort to sort the
array.
Following is the step-by-step depiction −
11
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Algorithm:
Step 1 − Initialize the value of h
Step 2 − Divide the list into smaller sub-list of equal interval h
Step 3 − Sort these sub-lists using insertion sort
Step 3 − Repeat until complete list is sorted
Implementation:
#include <stdio.h>
void shellsort(int arr[], int num)
{
int i, j, k, tmp;
for (i = num / 2; i > 0; i = i / 2)
{
for (j = i; j < num; j++)
{
for(k = j - i; k >= 0; k = k - i)
{
if (arr[k+i] >= arr[k])
break;
else
{
tmp = arr[k];
arr[k] = arr[k+i];
arr[k+i] = tmp;
}
}
}
}
}
int main()
{
int arr[30];
int k, num;
printf("Enter total no. of elements : ");
scanf("%d", &num);
printf("\nEnter %d numbers: ", num);
12
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Time
Sort Average Best Worst Space Stability Remarks
Bubble Always use a modified bubble
O(n2) O(n2) O(n2) Constant Stable
sort sort
Even a perfectly sorted input
Selection
O(n2) O(n2) O(n2) Constant Stable requires scanning the entire
Sort
array
In the best case (already sorted),
Insertion
O(n2) O(n) O(n2) Constant Stable every insert requires constant
Sort
time
By using input array as storage
Heap Sort O(n*log(n)) O(n*log(n)) O(n*log(n)) Constant Instable for the heap, it is possible to
achieve constant space
On arrays, merge sort requires
Merge O(n) space; on linked lists,
O(n*log(n)) O(n*log(n)) O(n*log(n)) Depends Stable
Sort merge sort requires constant
space
Randomly picking a pivot value
(or shuffling the array prior to
Quicksort O(n*log(n)) O(n*log(n)) O(n^2) Constant Stable sorting) can help avoid worst
case scenarios such as a
perfectly sorted array.
Searching:
Search is a process of finding a value in a list of values. In other words, searching is the
process of locating given value position in a list of values.
Gathering any information (or) trying to find any data is said to be a Searching process.
Searching technique can be used more efficiently if the data is present in an ordered manner.
Most widely used Searching methods are:-
1) Linear Search (Sequential Search) 2) Binary Search
1. Linear Search:
Suppose an array is given, which contains “n” elements. If no other information is given and
we are asked to search for an element in array, than we should compare that element, with all the
elements present in the array. This method which is used to Search the element in the array is
known as Liner Search. Since the key element/ the element which is to be searched in array, if
found out by comparing with every element of array one-by-one, this method is also known as
Sequential Search.
Algorithm:
13
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Step 5 - Repeat steps 3 and 4 until search element is compared with last element in the list.
Step 6 - If last element in the list also doesn't match, then display "Element is not found!!!" and
terminate the function.
Implementation:
#include<stdio.h>
void main()
{
int a[100], n, i, key,temp;
printf("Enter Number of elements in array: \n");
scanf("%d", &n);
printf("Enter Array Elements:\n");
for(i=0; i<n; i++)
scanf("%d", &a[i]);
printf("Enter Key value to search\n");
scanf("%d", &key);
for(i=0;i<n;i++)
if(a[i]==key)
{
temp=1;
printf("Number found at position %d\n",i+1);
break;
}
if(temp!=1)
{
printf("Number not found in given elements\n");
}
}
The time complexity of Linear search is:
a. Best case = O(1)
b. Average case = n(n+1)/2n = O(n)
c. Worst case = O(n)
The space complexity of Linear Search is O(1).
2. Binary Search:
Efficient search method for large arrays. Liner search, will required to compare the key
element, with every element in array. If the array size is large, liner search requires more time for
execution.
In such cases, binary search technique can be used.
Find the lowest position & highest position of the array i.e., if an array contains „n‟ elements
then:-
Low=0
High =n-1
Mid =(low+high)/2
Note: We are calculating mid position of the array not the middle element. The element present in the
mid position is considered as middle element of array.
Now the search key element is compared with middle element of array. Three cases arises
Case 1 : If middle element is equal to key, then search is end.
Case 2 : If middle element is greater than key, then search is done on left sublist of the middle element
14
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
of array.
Case 3 : If middle element is less than key, then search is done on right sublist of the middle
element of array.
This process is repeated till we get the key element (or) till the search comes to an end, since
key element is not in the list.
Algorithm:
Implementation:
#include<stdio.h>
void main()
{
int a[100], n, i, high, low, mid, key, location;
printf("Enter Number of elements in array: \n");
scanf("%d", &n);
printf("Enter Array Elements in sorted order:\n");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
printf("Enter Key value to search\n");
scanf("%d",&key);
low=0;
high=n-1;
mid=(low+high)/2;
if(a[mid]==key)
{
location=mid;
}
while((low<=high)&&(a[mid]!=key))
{
mid=(low+high)/2;
if(a[mid]<key)
low=mid+1;
else if(a[mid]>key)
high=mid-1;
else
location=mid;
}
if(a[location]==key)
15
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
Graphs:
Graph is a non-linear data structure. It contains a set of points known as nodes (or vertices)
and a set of links known as edges (or Arcs). Here edges are used to connect the vertices. A graph is
defined as follows...
“Graph is a collection of vertices and arcs in which vertices are connected with arcs” or
“Graph is a collection of nodes and edges in which nodes are connected with edges”.
Generally, a graph G is represented as G = ( V , E ), where V is set of vertices and E is set of edges.
Example:
1. Vertex:
Individual data element of a graph is called as Vertex. Vertex is also known as node. In
above example graph, A, B, C, D & E are known as vertices.
2. Edge:
An edge is a connecting link between two vertices. Edge is also known as Arc. An edge is
represented as (startingVertex, endingVertex). For example, in above graph the link between
vertices A and B is represented as (A,B). In above example graph, there are 7 edges (i.e., (A,B),
(A,C), (A,D), (B,D), (B,E), (C,D), (D,E)).
16
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
3. Undirected Graph: A graph with only undirected edges is said to be undirected graph.
4. Directed Graph: A graph with only directed edges is said to be directed graph.
5. Mixed Graph: A graph with both undirected and directed edges is said to be mixed graph.
6. End vertices or Endpoints: The two vertices joined by edge are called end vertices (or endpoints)
of that edge.
7. Origin: If a edge is directed, its first endpoint is said to be the origin of it.
8. Destination: If a edge is directed, its first endpoint is said to be the origin of it and the other
endpoint is said to be the destination of that edge.
9. Adjacent: If there is an edge between vertices A and B then both A and B are said to be adjacent.
In other words, vertices A and B are said to be adjacent if there is an edge between them.
10. Incident: Edge is said to be incident on a vertex if the vertex is one of the endpoints of that edge.
11. Outgoing Edge: A directed edge is said to be outgoing edge on its origin vertex.
12. Incoming Edge: A directed edge is said to be incoming edge on its destination vertex.
13. Degree: Total number of edges connected to a vertex is said to be degree of that vertex.
14. Indegree: Total number of incoming edges connected to a vertex is said to be indegree of that
vertex.
15. Outdegree: Total number of outgoing edges connected to a vertex is said to be outdegree of that
vertex.
16. Parallel edges or Multiple edges: If there are two undirected edges with same end vertices and
two directed edges with same origin and destination, such edges are called parallel edges or
multiple edges.
17. Self-loop: Edge (undirected or directed) is a self-loop if its two endpoints coincide with each other.
18. Simple Graph: A graph is said to be simple if there are no parallel and self-loop edges.
19. Path: A path is a sequence of alternate vertices and edges that starts at a vertex and ends at other
vertex such that each edge is incident to its predecessor and successor vertex.
Graph Representations:
Graph data structure is represented using following representations...
1. Adjacency Matrix
2. Incidence Matrix
3. Adjacency List
1. Adjacency Matrix:
In this representation, the graph is represented using a matrix of size i.e., total number of
vertices by a total number of vertices. That means a graph with 4 vertices is represented using a
matrix of size 4X4. In this matrix, both rows and columns represent vertices. This matrix is filled
17
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
with either 1 or 0. Here, 1 represents that there is an edge from row vertex to column vertex and 0
represents that there is no edge from row vertex to column vertex.
2. Incidence Matrix
In this representation, the graph is represented using a matrix of size total number of vertices
by a total number of edges. That means graph with 4 vertices and 6 edges is represented using a
matrix of size 4X6. In this matrix, rows represent vertices and columns represent edges. This matrix is
filled with 0 or 1 or -1. Here, 0 represents that the row edge is not connected to column vertex, 1
represents that the row edge is connected as the outgoing edge to column vertex and -1 represents that
the row edge is connected as the incoming edge to column vertex.
18
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
3. Adjacency List:
In this representation, every vertex of a graph contains list of its adjacent vertices.
For example, consider the following directed graph representation implemented using linked list...
Graph traversal is a technique used for a searching a vertex in graph. The graph traversal is
also used to decide the order of vertices is visited in the search process. A graph traversal finds the
edges to be used in the search process without creating loops. That means using graph traversal we
visit all the vertices of the graph without getting into looping path.
There are two graph traversal techniques and they are as follows...
1. DFS (Depth First Search)
2. BFS (Breadth First Search)
19
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
DFS traversal of a graph produces a spanning tree as final result. Spanning Tree is a graph
without loops. We use Stack data structure with maximum size of total number of vertices in the
graph to implement DFS traversal.
Algorithm:
Step 1 - Define a Stack of size total number of vertices in the graph.
Step 2 - Select any vertex as starting point for traversal. Visit that vertex and push it on to the
Stack.
Step 3 - Visit any one of the non-visited adjacent vertices of a vertex which is at the top of
stack and push it on to the stack.
Step 4 - Repeat step 3 until there is no new vertex to be visited from the vertex which is at the
top of the stack.
Step 5 - When there is no new vertex to visit then use back tracking and pop one vertex from
the stack.
Step 6 - Repeat steps 3, 4 and 5 until stack becomes Empty.
Step 7 - When stack becomes Empty, then produce final spanning tree by removing unused
edges from the graph.
“Back tracking is coming back to the vertex from which we reached the current vertex”.
Implementation:
#include<stdio.h>
int cost[10][10],i,j,k,n,m,stack[10],top=-1,v;
int visited[10];
void DFS()
{
printf("enter the initial vertex");
scanf("%d",&v);
printf("visited vertices\n");
stack[++top]=v;
while(top!=-1)
{
v=stack[top--];
if(visited[v]==0)
{
printf("%d",v);
visited[v]=1;
}
else
continue;
for(j=n;j>=1;j--)
if(!visited[j]&& cost[v][j]==1)
stack[++top]=j;
}
}
int main()
{
printf("enter the no of vertices");
scanf("%d",&n);
printf("enter the no of edges");
20
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
scanf("%d",&m);
for ( int i=1;i<=10;i++)
{
visited[i]=0;
}
for (int i=0;i<10;i++)
for(j=0;j<10;j++)
cost[i][j]=0;
printf("\nEnter EDGES");
for(k=1;k<=m;k++)
{
scanf("%d%d",&i,&j);
cost[i][j]=1;
cost[j][i]=1;
}
DFS();
}
Complexity:
Time complexity O(V+E), when implemented using an adjacency list.
Algorithm:
Step 1 - Define a Queue of size total number of vertices in the graph.
Step 2 - Select any vertex as starting point for traversal. Visit that vertex and insert it into the
Queue.
Step 3 - Visit all the non-visited adjacent vertices of the vertex which is at front of the Queue
and insert them into the Queue.
Step 4 - When there is no new vertex to be visited from the vertex which is at front of the
Queue then delete that vertex.
Step 5 - Repeat steps 3 and 4 until queue becomes empty.
Step 6 - When queue becomes empty, then produce final spanning tree by removing unused
edges from the graph.
Implementation:
#include<stdio.h>
int cost[10][10],i,j,k,n,m,queue[10],front,rear,v;
int visited[10];
void BFS()
{
printf("enter the initial vertex");
scanf("%d",&v);
printf("visited vertices\n");
visited[v]=1;
queue[++rear]=v;
while(front!=rear)
{
v=queue[++front];
printf("%d",v);
21
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
for(j=1;j<=n;j++)
if(!visited[j]&& cost[v][j]==1)
{
queue[++rear]=j;
visited[j]=1;
}
}
}
int main()
{
printf("enter the no of vertices");
scanf("%d",&n);
printf("enter the no of edges");
scanf("%d",&m);
front=-1;rear=-1;
for ( int i=1;i<=10;i++) visited[i]=0;
for (int i=0;i<10;i++)
for(j=0;j<10;j++)
cost[i][j]=0;
printf("\nEnter EDGES");
for(k=1;k<=m;k++)
{
scanf("%d%d",&i,&j);
cost[i][j]=1;
cost[j][i]=1;
}
BFS();
}
Complexity:
The time complexity of BFS is O(V + E), where V is the number of nodes and E is the
number of edges.
22
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
There are two most popular algorithms that are used to find the minimum spanning tree in a
graph.
They are:
1. Prim’s algorithm
2. Kruskal’s algorithm
1. Prim’s algorithm:
• Prim’s algorithm is an algorithm to find the MST in a connected graph.
• The graph must be a simple graph.
• Prim’s algorithm starts with a vertex.
• We start with one vertex and keep on adding edges with the least weight till all the vertices
are covered.
The sequence of steps for Prim’s Algorithm is as follows:
• Convert the graph to simple graph.
23
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
• Choose a random vertex as starting vertex and initialize a minimum spanning tree.
• Find the edges that connect to other vertices. Find the edge with minimum weight and add it
to the spanning tree.
• Repeat step 2 until the spanning tree is obtained.
Consider the following example graph to illustrate of Prim’s algorithm:
• In case of parallel edges, keep the one which has the least cost associated and remove all
others.
Step-2:Choose a random vertex as starting vertex and initialize a minimum spanning tree.
24
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
• we choose S node as the root node of Prim's spanning tree. This node is chosen, so any node
can be the root node.
Step-3: Check outgoing edges and select the one with less cost
• After choosing the root node S, we see that S,A and S,C are two edges with weight 7 and 8,
respectively. We choose the edge S,A as it is lesser than the other.
Step-4: Now, the tree S-A is treated as one node and we check for all edges going out from it. We
select the one which has the lowest cost and include it in the tree.
Step-5: After this step, S-A-C tree is formed. Now we'll again treat it as a node and will check all the
edges again. However, we will choose only the least cost edge. In this case, C-D is the new edge,
which is less than(i.e.,3) other edges' cost 8, 6, 4, etc.
Step-6: After adding node D to the spanning tree, we now have two edges going out of it having the
same cost(2), i.e. D-T and D-B. Thus, we can add either one.
25
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
step-7: After adding node B to the spanning tree, the node will be S-A-C-D-B and we check for all
edges going out from it. However, we will choose only the least cost edge. In this case, D-T is the
new edge, which is less than(2) other edges' cost 8, 6, 5, 4, etc.
#include<stdio.h>
int a,b,u,v,n,i,j,ne=1;
int visited[10]={0},min,mincost=0,cost[10][10];
void main()
{
printf("\nEnter the number of nodes:");
scanf("%d",&n);
printf("\nEnter the adjacency matrix:\n");
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&cost[i][j]);
if(cost[i][j]==0)
cost[i][j]=999;
}
visited[1]=1;
printf("\n");
while(ne < n)
{
for(i=1,min=999;i<=n;i++)
for(j=1;j<=n;j++)
if(cost[i][j]< min)
if(visited[i]!=0)
{
min=cost[i][j];
b=v=j;
}
if(visited[u]==0 || visited[v]==0)
{
printf("\n Edge %d:(%d %d) cost:%d",ne++,a,b,min);
mincost+=min;
visited[b]=1;
}
cost[a][b]=cost[b][a]=999;
}
printf("\n Minimun cost=%d",mincost);
}
26
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
2. Kruskal’s algorithm:
• Kruskal’s algorithm is an algorithm to find the MST in a connected graph.
• The graph must be a simple graph.
. The sequence of steps for Kruskal’s Algorithm is as follows:
• Convert the graph to simple graph.
• sort all the edges from the lowest weight to highest.
• Take edge with the lowest weight and add it to the spanning tree. If the cycle is created,
discard the edge.
• Keep adding edges like in step 2 until all the vertices are considered.
• In case of parallel edges, keep the one which has the least cost associated and remove all
others.
27
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
The least cost is 2 and edges involved are B,D and D,T. We add them. Adding them does not violate
spanning tree properties, so we continue to our next edge selection.
Next cost is 3, and associated edges are A,C and C,D. We add them again −
Next cost in the table is 4, and we observe that adding it will create a circuit in the graph.
We ignore it. In the process we shall ignore/avoid all edges that create a circuit.
28
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
• We observe that edges with cost 5 and 6 also create circuits. We ignore them and move on.
• Now we are left with only one node to be added. Between the two least cost edges available 7
and 8, we shall add the edge with cost 7.
• By adding edge S,A we have included all the nodes of the graph and we now have minimum
cost spanning tree.
#include<stdio.h>
#include<stdlib.h>
int i,j,k,a,b,u,v,n,ne=1;
int min,mincost=0,cost[9][9],parent[9];
int find(int);
int uni(int,int);
void main()
{
printf("\n\tImplementation of Kruskal's algorithm\n");
printf("\nEnter the no. of vertices:");
scanf("%d",&n);
printf("\nEnter the cost adjacency matrix:\n");
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&cost[i][j]);
if(cost[i][j]==0)
cost[i][j]=999;
}
}
printf("The edges of Minimum Cost Spanning Tree are\n");
while(ne < n)
{
for(i=1,min=999;i<=n;i++)
{
for(j=1;j <= n;j++)
{
if(cost[i][j] < min)
{
min=cost[i][j];
a=u=i;
b=v=j;
}
}
}
u=find(u);
v=find(v);
29
Data Structures and Algorithms UNIT-V—Graphs and Sorting & Searching
if(uni(u,v))
{
printf("%d edge (%d,%d) =%d\n",ne++,a,b,min);
mincost +=min;
}
cost[a][b]=cost[b][a]=999;
}
printf("\n\tMinimum cost = %d\n",mincost);
}
int find(int i)
{
while(parent[i])
i=parent[i];
return i;
}
int uni(int i,int j)
{
if(i!=j)
{
parent[j]=i;
return 1;
}
return 0;
}
30