(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
DATA STRUCTURE AND ALGORITHM FULL NOTES
1. INTRODUCTION
DATA STRUCTURE:
Information in unorganized or raw form is termed as data. Data is limitless and
present everywhere in the universe. An organization of information or data,
usually in memory, for quick and efficient access is the prime requirement in
this era of digitization.
Data is represented in data values held in them and often the different data
values are related to each other. To make use of these relationships, these data
values must be placed in organized form. The organized collection of data in
memory is called data structure. The programs have to follow certain rules to
access them and process the structured data.
Data Structure= Organized Data+ Allowed Operation
The organized form of data is thus an arrangement of data in a computer
memory or even disk storage. Allowed operation or algorithm, on the other
hand, is used to manipulate the data contained in these data structures. It is a
particular way of storing and organizing, so that data can be used quickly and
easily. Different kind of data structures are suited for different kinds of
applications, and some are highly specified to specific task.
Specific data structures are the essential ingredients of many efficient
algorithms, and make possible the management of huge amount of data, such as
large databases and Internet indexing services.
ALGORITHM:
The word algorithm comes from the name of a Persian author, Abu Jafar
Mohammed ibn Musa al khowarizmi, who wrote a textbook on mathematics.
This word has taken on a special significance, where “algorithm” has come to
refer to a method that can be used by a computer for the solution of a problem.
An algorithm is a specific finite set of instructions that, if followed,
accomplishes a particular task. In addition, all algorithms must satisfy the
following criteria:
1. INPUT: Zero or more quantities are externally supplied.
2. OUTPUT: At least one quantity is produced.
3. DEFINITENESS: each instruction must be clear and unambiguous.
4. FINITENESS: If we trace out the instructions, then for all cases, the
algorithm terminates after a finite number of steps.
2. 5. EFFECTIVENESS: Every instruction must be very basic, so that it can be
easily carried out by a person.
CLASSIFICATION:
Data structures are mainly classified into two distinct types:
LINEAR: If the elements of a data structure are stored sequentially, then it
is called a linear data structure. In linear data structures, we can traverse
either forward or backward from a specific element. Linear data structure
can be represented in two different ways. One is to have linear
relationship between the elements by means of memory locations, such
as array. The second way is to have a linear relationship among the
elements by means of pointers or links, such as linked list.
NON-LINEAR: if the elements of data structure are not stored in a
sequential order, then it is called a non-linear data structure. It branches
to more than one element and cannot be traverse the entire list in a single
run. Example: tree, graph.
ABSTRACT DATA TYPE (ADT):
Abstract data types are a set of data values and associated operations that are
precisely independent of any particular implementation. Generally the
associated operations are abstract methods. Ex: stack, queue etc.
The term abstract signifies that the data type will only set the rule of its usage
but how it will be used depends on the implementation. So the only restriction is
the way of processing data.
The stack data type defines two abstract methods „push‟ and „pop‟. These
abstract methods do not have any definition of their own. Different programs
can inherit this stack data type and can overwrite the methods to provide their
own implementation.
ADVANTAGE:
If any additional functionality is required, then it can be easily added to the
methods.
DISADVANTAGE:
All the programs that inherit the abstract data type have to implement any
changes made in the data type, even if it may not be required.
3. COMPLEXITY ANALYSIS:
Our fundamental objective is to design good algorithms, which use efficient
data structures. The analysis of an algorithm means (i) to develop a formula
capable of predicting in quantitative terms as how much memory an algorithm
requires, based on the size of the input(space complexity) and(ii) to develop the
formula for determining how fast an algorithm is, based on the size of the
input(time complexity). Given a specific problem our aim is to provide an
algorithm having as minimum complexity as possible, both in respect to space
and time.
SPACE COMPLEXITY:
The space complexity is defined as how much space is required to execute an
algorithm. It is the number of elementary objects that an algorithm needs to
store during its implementation. This number is computed with respect to the
size of the input data. Space is generally computer memory space. Naturally, an
algorithm to achieve a specific growth with less space requirement is considered
to be a better algorithm in terms of space complexity.
TIME COMPLEXITY:
Time complexity of an algorithm is the measure of total time required to
execute the algorithm. Time complexity is independent of the computer
programming languages, programmer and the other implementation details.
Usually it is dependent upon the size of the input. It is the number of elementary
instructions that the algorithm implements. This number is computed with
respect to the number of input data. We thus make an assumption that each
elementary instruction takes the same amount of time.
ASYMPTOTIC NOTATION:
We can measure the run time of an algorithm through various methods, but if
the size of the input is very large, then we use asymptotic notation to find the
order of growth of the execution time with respect to the size of the input. The
algorithm that takes minimum time execute given an input of specific size is
asymptotically more efficient algorithm.
BIG-O NOTATION
DEFINITION: If f(n ) be the computing time of an algorithm that run over an
input data size of n and g(n) some standard function like n,n2
,n3
, nlogn,2n
,√n
4. etc then f(n) is said to be O(g(n)) if and only if there exist some positive
constant c such that
|f(n)|<=c*|g(n) | for every n>=n0
NOTE:
The time complexity expressed in Big-O notation is only the upper
bound of an algorithm and the actual complexity may be much lower.
The complexity can almost be treated as worst case, but the input that
causes the worst case may unlike to be appeared in practice.
Both the constants c and n are unknown and not necessarily be small.
GRAPHICAL REPRESENTATION
c*g(n)
f(n)
Computing Time (t)
n0
Input Data Size (n)
EXAMPLES:
Ex: f(n)=n+4 is O(n) since n+4<=2n for all n>=4.so n=4 is O(n)
Ex: f(n)=n2
+3n+4 is O(n2
), since n2
+3n+4<=2n2
for all n>=4
Ex: f(n)=3.2n
+n2
is O(2n
), since 3.2n
+n2
<= 4.2n
for all n>=3
5. FIG: Graphical Representation of Example1
BIG-Ω NOTATION
DEFINITION: If f(n ) be the computing time of an algorithm that run over an
input data size of n and g(n) some standard function like n,n2
,n3
, nlogn,2n
,√n
etc then f(n) is said to be Ω(g(n)) if and only if there exist some positive
constant c such that
|f(n)|>=c*|g(n) | for every n>=n0
NOTE:
The time complexity expressed in Big-Ω notation is only the lower
bound of an algorithm and the actual complexity may be much higher.
The complexity can almost be treated as best case, but the input that
causes the best case may unlike to be appeared in practice.
Both the constants c and n are unknown and not necessarily be small.
6. GRAPHICAL REPRESENTATION
f(n) c*g(n)
Computing Time (t)
n0
Input Data Size (n)
EXAMPLES:
Ex: f(n)=5n+6 is Ω(n), since 5n+6>=5n for all n>=1
Ex: f(n)=3n2
+2n+4 is Ω(n2
), since 3n2
+2n+4>=3n for all n>=1
Ex: f(n)=5.2n
+6 is Ω(2n
), since 5.2n
+6>=5.2n
for all n>=1
BIG-Ө NOTATION
DEFINITION: If f(n ) be the computing time of an algorithm that run over an
input data size of n and g(n) some standard function like n,n2
,n3
, nlogn,2n
,√n
etc then f(n) is said to be Ω(g(n)) if and only if there exist two positive
constant c1,c2 such that
c1*|g(n)|<= |f(n)|<=c2*|g(n)| for all n>=n0
NOTE:
The time complexity expressed in Big-Ө notation is the asymptotically
tight bound of an algorithm.
7. The complexity can almost be treated as average case, but the input
that causes the best case may unlike to be appeared in practice.
The constants c1, c2 and n are unknown and not necessarily be small.
GRAPHICAL REPRESENTATION
c2*g(n) f(n) c1*g(n)
Computing Time (t)
n0
Input Data Size (n)
EXAMPLES:
Ex: f(n)=5n+2 is Ө(n), since 6n>=5n+2>=5n for all n>=3
Ex: f(n)=3n2
+2n+1 is Ө(n2
), since 4n2
>=3n2
+2n+1>=3n2
for all n>=3
Ex: f(n)=3.2n
+n2
+2 is Ө(2n
), since 4.2n
>= 3.2n
+n2
+2 >=3.2n
for all n>=4
8. COMPLEXITY ANALYSIS OF SOME IMPORTANT
ALGORITHMS
/ * BINARY SEARCHING */
We know that, in case of binary search the computing time can be
expressed as follows:
T(n)=T(n/2)+c
Let us assume that, the size of the input data n=2m
and m= log n
Then, T(2m
)=T(2m
/2)+c
= T(2m-1
)+c
= T(2m-2
)+2c
= T(2m-m
)+mc
= c+mc
= m(c+1)
T(2m
)= m [Ignoring the constant terms]
T(n) = log n[ Putting the value of m]
/* TOWER OF HANOI */
9. RECURSION
DEFINITION:
Recursive algorithm is an algorithm which invokes itself with modified input
arguments and obtains the result for the current input arguments. Thus by this
method one can break down a problem into one or more smaller problems of
similar form of the original problem.
In general, the recursive algorithm requires more memory space and
computation as compared to iterative algorithms, but they are simpler in form
and for many cases, a natural way of thinking.
WRITING A RECURSIVE FUNCTION:
There are two main step of writing a recursive function.
Identification of the base case and its solution that is the case where
solution can be achieved without recursion. There may be more that one
base case.
Identification of the general case or the recursive case. That is the case in
which recursive call will be made. Identification of the general case is
very important because without it the function will keep on calling itself
resulting in infinite recursion.
We must make sure that each recursive call takes us closer to the base case
that is the size of the problem should be reduced at each step of recursion.
WINDING AND UNWINDING PHASE:
All recursive function works in two phases- winding and unwinding phase.
Winding phase begins when the recursive function is called for the first time,
and each recursive call continues the winding phase. This phase terminates
when the terminating condition or the base condition is true for some call. After
this the unwinding phase begins and all the recursive function calls start
returning in reverse order till the first instance of the function returns. In
unwinding phase the control returns through each instance of the function.
TYPES OF RECURSION:
Recursive functions are characterized based on-
10. Whether the function calls itself directly or through some other functions
(Direct or Indirect Recursion)
Whether there exist any pending operations at each recursive call (Tail or
Non-tail Recursion)
Whether the pending operation of the recursive function involves any
other recursive call(Linear or Tree Recursion)
DIRECT RECURSION:
int f (int a)
{
if(a<=0)
return a;
return(f(a-1));
}
INDIRECT RECURSION:
int f1(int a)
{
if(a<=0)
return a;
return f2(a);
}
int f2(int b)
{
return f1(b-1);
}
TAIL RECURSION:
enumboolean{true;false};
11. boolean even(int x)
{
if (x%2==0)
return true;
else
return false;
}
NON TAIL RECURSION:
int f (int a)
{
if(a<=0)
return a;
return(a+f(a-1));
}
LINEAR RECURSION:
int f (int a)
{
if(a<=0)
return a;
return(a*f(a-1));
}
TREE RECURSION:
/* FIBBONACCI SERIES*/
int fib(int n)
12. {
if (n==1)
return 0;
else if (n==2)
return 1;
else
return(fib(n-1)+fib(n-2));
}
RECURSION VS ITERATION:
Iteration means repetitive execution of statement/s for desired number of
times, while when a function invokes itself with modified input
arguments to solve a smaller version of its task known as recursion.
Recursion is more top down approach to a problem solving, in which the
original problem is divided into smaller sub problems. On the contrary,
iteration follows a bottom up approach that begins with what is known
and then constructing the solution step by step.
Whenever a recursion function is called some amount of overhead in the
form of run time stack is always involved to store the original parameter,
local variables and the return address. Iteration on the other hand does not
associate with any other data structures.
C language supports three types of iterative statements- (i) for(), (ii)
while(), (iii) do-while(). Where any recursive function can be
characterized based on whether: (i) function calls itself directly or
indirectly (direct or indirect recursion),(ii) any operation is pending at
each recursive call or not (tail and non-tail recursion).
The recursive function has two cases: base case- in which problem is
simple enough to be solved directly without making any further calls
(termination condition), and recursive call- in which the problem gets sub
divided into simpler smaller parts. Where an iteration has three cases:
initialization- the staring value, condition- provide the condition till
13. which it will run, increment/ decrement- how to change the value in each
step.
DIFFERENT EXAMPLES:
/* FACTORIAL OF A NUMBER*/
longintfact(int n)
{
if(n==1)
return 1l;
else if(n==2)
return 2l;
else
return n*fact(n-1);
}
/* GCD OF TWO NUMBERS*/
intgcd(inta,int b)
{
if(a%b==0)
return b;
else
returngcd(b,a%b);
}
/* BINARY SEARCH*/
int bin(int x[],intlb,intub,int target)
14. {
int m=(lb+ub)/2
if (lb>ub)
return -1;
else if (x[m]==target)
return m;
else if (target> x[m])
return bin(x,m+1,ub,target);
else if (target<x[m])
return bin(x,lb,m-1,target);
}
/* SUMMATION OF NUMBERS FROM 1 TO N */
int sum(int n)
{
if (n==0)
return 0;
else
return (n+sum(n-1));
}
/* DISPLAYING NUMBERS FROM 1 TO N */
void display(int n)
{
15. if (n==0)
return;
printf(“%dt”,n);
display(n-1);
}
/* SUM OF THE DIGITS OF A NUMBER */
int sum(int n)
{
int r;
if(n==0)
return 0;
r=n%10;
n=n/10;
return (r+sum(n));
}
/* N-TH EVEN NATURAL NUMBER*/
int even(int n)
{
if (n==1)
return 0;
else
return (2+even(n-1));
}
16. /* N-TH POWER OF 2 */
int power(int n)
{
if(n==0)
return 1;
else
return (2*power(n-1));
}
/* BASE CONVERSION */
void convert (intnum, int base)
{
int r=num%base;
if(num==0)
return;
convert(num/base,base);
if(r<10)
printf(“%d”,r);
else
printf(“%c”,r-10+’A’);
}
/* EXPONENTIATION OF A FLOAT BY A POSITIVE INTEGER */
float power(float a,int n)
17. {
if(n==0)
return 1;
else
return (a*power(n-1));
}
/* PRIME FACTORIZATION */
voidpfact(intnum)
{
int i=2;
if(num==1)
return 1;
while(num%i!=0)
i++;
printf(“%dt”,i);
pfact(num/i);
}
/* CHECKING THE DIVISIBILITY BY 9 */
int div(long int n)
{
intsumdig;
if(n==9)
return 1;
19. STACK
DEFINITION: Stack is a linear data structure, where the data can be inserted
or retrieved only from one end. The structure of stack contains a member
variable known as the ‘top’ to indicate the top most element of the stack. Stack
typically implements last in first out (LIFO) or first in last out (FILO), which
means the element that was inserted first in the stack will be retrieved at the last.
UNDERFLOW: Underflow in the stack occurs when the stack becomes
empty. Obviously initially the stack is empty, and the member variable ‘top’ is
generally initialized by -1to indicate the underflow condition of the stack. This
is a necessary condition to be checked during the pop or retrieve operation.
OVERFLOW: Overflow in stack occurs when the number of elements in the
stack becomes equal to the size of the stack. That is, if there does not exist any
space for further insertion of the elements. We assume the overflow of stack
when the member variable ‘top’ is at position =size-1. This is a necessary
condition to be checked during the push or insertion operation.
ALGORITHM:
/*ALGORITHM FOR PUSH OPERATION*/
1. START PUSH( int val)
2. IF TOP= SIZE-1 THEN DISPLAY” OVERFLOW”
GOTO END
3. TOP:=TOP+1
4. S[TOP]:=VAL
5. END
/*ALGORITHM FOR POP OPERATION*/
1. START POP( )
2. IF TOP= -1 THEN DISPLAY” UNDERFLOW”
GOTO END
3. VAL:=S[TOP];
4. TOP:=TOP-1
5. RETURN VAL
6. END
20. /* C IMPLEMENTATION OF STACK USING STRUCTURE*/
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define size 5
struct stack
{
int item[size];int top;
};
/* FUNCTION PROTOTYPE DECLARATIONS */
void push(struct stack *);
int pop(struct stack *);
void main()
{
struct stack s; s.top=-1; int choice,val;
clrscr();
while(1)
{
printf("n PRESS 1 FOR PUSH");
printf("n PRESS 2 FOR POP");
printf("n PRESS 3 FOR EXIT ");
printf("n ENTER YOUR CHOICE:");
scanf("%d",&choice);
switch(choice)
{
case 1:push(&s); break;
case 2: val= pop(&s);
if(val==-9999)
{
printf("n........ UNDERFLOW........n");
break;
}
printf("n THE POPED VALUE=%dn",val);
break;
case 3: exit(0);
21. default:printf("n WRONG CHOICE");
}// END OF SWITCH
}// END OF WHILE
} // END OF MAIN
/* DEFINITION OF FUNCTION PUSH */
void push(struct stack * sp)
{
int val;
if (sp-> top== size-1)
{
printf(" n........OVERFLOW...........n"); return;
}
printf("n ENTER THE VALUE TO BE INSERTED:");
scanf("%d",&val);
sp->top++;
sp->item[sp->top]=val;
printf("n END OF PUSH OPERATIONn");
}
/* DEFINITION OF FUNCTION POP */
int pop(struct stack * sp)
{
int val;
if (sp->top= =-1)
return -9999;
val= sp->item[sp->top];
sp->top--;
return val;
}
23. DOUBLE STACK
DEFINITION: Double stack or double ended stack is a stack, where elements
can be inserted and retrieved from the either end of the stack according to our
need. To provide the flexibility to insert and retrieve operation from both ends,
the structure of double stack contains two ‘top’ variables, assuming ‘topA’ at
lower end and ‘topB’ at upper end.
UNDERFLOW: As it provides the facility to retrieve from either end of the
stack, we can assume three cases (i) retrieving only from lower end, (ii)
retrieving only from upper end,(iii) retrieving from either ends. In the first case
the underflow of double stack when the member variable ‘topA’ is equal to -1.
For case two, the underflow occurs when the member variable ‘topB’ is equal to
size. As the third case is nothing but the above two cases with user choice, thus
we will use a flag variable to indicate the particular end of the operation (lower
or upper). Thus the condition say if f=1 and ‘topA’ =-1 or if f=2 and ‘topB’=size
then underflow occurs would satisfy all three cases. This is a necessary
condition to be checked during the pop or retrieve operation.
OVERFLOW: As it provides the facility to retrieve from either end of the
stack, we can assume three cases (i) inserting only from lower end, (ii) inserting
only from upper end,(iii) inserting from either ends. In the first case the
overflow of double stack when the member variable ‘topA’ is equal to size-1.
For case two, the overflow occurs when the member variable ‘topB’ is equal to
0. We can generalize these two cases by considering the overflow condition
when ‘topA+1’ become equal to ‘topB’ that satisfies the third case too. This is a
necessary condition to be checked during the push or insertion operation.
ALGORITHM:
/* ALGORITHM FOR PUSH OPERATION */
1. START PUSH( int val)
2. IF TopA+1= TopB THEN DISPLAY” OVERFLOW”
GOTO END
3. IF F=1 THEN TopA:=TopA+1 AND S[TopA]:=VAL
4. ELSE IF F=2 THEN TopB:=TopB-1 AND S[TopB]:=VAL
5. END
24. /* ALGORITHM FOR POP OPERATION*/
1. START POP( )
2. IF F=1 AND TopA= -1 OR F=2 AND TopB=SIZE THEN DISPLAY”
UNDERFLOW” GOTO END
3. IF F=1 THEN VAL:=S[TopA]; TopA:=TopA-1
4. ELSE IF F=2 THEN VAL:=S[TopB]; TopB:=TopB+1
5. RETURN VAL
6. END
/* C IMPLEMENTATION OF DOUBLE STACK*/
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define size 3
struct stack
{
int item[size];int topA,topB;
};
/* FUNCTION PROTOTYPE DECLARATIONS */
void push(struct stack *,int);
int pop(struct stack *,int);
void main()
{
struct stack s; s.topA=-1; s.topB=size;int choice,val;
clrscr();
while(1)
{
printf("nPRESS 1 FOR PUSH INTO LOWER STACK");
printf("nPRESS 2 FOR PUSH INTO UPPER STACK");
printf("nPRESS 3 FOR POP FROM LOWER STACK ");
printf("nPRESS 4 FOR POP FROM UPPER STACK");
printf("nPRESS 5 FOR EXIT");
25. printf("nENTER YOUR CHOICE:");
scanf("%d",&choice);
switch(choice)
{
case 1:push(&s,1); break;
case 2:push(&s,2);break;
case 3: val= pop(&s,1);
if(val==-9999)
{
printf("n.. UNDERFLOW IN LOWER STACK..n");
break;
}
printf("n THE POPED VALUE FROM LOWER STACK =%dn",val);
break;
case 4:val= pop(&s,2);
if(val==-9999)
{
printf("n..UNDERFLOW IN UPPER STACK..n");
break;
}
printf("n THE POPED VALUE FROM UPPER STACK=%dn",val);
break;
case 5: exit(0);
default:printf("nWRONG CHOICE");
}// END OF SWITCH
}// END OF WHILE
} // END OF MAIN
/* DEFINING FUNCTION PUSH */
void push(struct stack * sp,int f)
{
int val;
if (sp-> topA+1==sp->topB)
{
26. printf(" n........OVERFLOW...........n"); return;
}
printf("n ENTER THE VALUE TO BE INSERTED:");
scanf("%d",&val);
if(f==1)
{
sp->topA++;
sp->item[sp->topA]=val;
}
else if(f==2)
{
sp->topB--;
sp->item[sp->topB]=val;
}
printf("n END OF PUSH OPERATIONn");
}
/* DEFINING FUCTION POP */
int pop(struct stack * sp,int f)
{
int val;
if ((f==1 && sp->topA==-1)||(f==2 && sp->topB==size))
return -9999;
if(f==1)
{
val= sp->item[sp->topA];
sp->topA--;
}
else if(f==2)
{
val=sp->item[sp->topB];
sp->topB++;
}
return val;
}
29. QUEUE
DEFINITION: Queue is a linear data structure, where the data can be inserted
at one end and retrieved from another end. The structure of queue contains two
member variables known as the ‘rear’ and ‘front’ for insertion and the retrieval
operation in the queue respectively. Queue typically implements last in last out
(LILO) or first in first out (FIFO), which means the element that was inserted
first in the queue will be retrieved first.
UNDERFLOW: Underflow in the queue occurs when the queue becomes
empty. Obviously initially the queue is empty, and the member variables ‘rear’
and ‘front’ is generally initialized by -1 and 0 respectively. As the initial
condition can be considered as underflow condition, thus we need to check
whether ‘front’ is greater than ‘rear’ or not. This is a necessary condition to be
checked during the retrieve operation.
OVERFLOW: Overflow in queue occurs when the number of elements in the
queue becomes equal to the size of the queue. That is, if there does not exist any
space for further insertion of the elements. We assume the overflow of queue
when the member variable ‘rear’ is at position =size-1. This is a necessary
condition to be checked during the push or insertion operation.
ALGORITHM:
/*ALGORITHM FOR INSERT OPERATION*/
1. START INSERT( int val)
2. IF REAR= SIZE-1 THEN DISPLAY” OVERFLOW”
GOTO END
3. REAR:=REAR+1
4. Q[REAR]:=VAL
5. END
/*ALGORITHM FOR RETRIEVE OPERATION*/
1. START RETRIEVE( )
2. IF FRONT>REAR THEN DISPLAY” UNDERFLOW”
GOTO END
3. VAL:=Q[FRONT];
4. FRONT:=FRONT+1
5. RETURN VAL
6. END
30. /* C IMPLEMENTATION OF QUEUE USING STRUCTURE*/
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define size 5
struct queue
{
int item[size];int rear; int front;
};
/* FUNCTION PROTOTYPE DECLARATIONS */
void insert(struct queue *);
int retrieve(struct queue*);
void main()
{
struct queue q; q.rear=-1; q.front=0;int choice,val;
clrscr();
while(1)
{
printf("n PRESS 1 TO INSERT");
printf("n PRESS 2 TO RETRIEVE");
printf("n PRESS 3 TO EXIT ");
printf("n ENTER YOUR CHOICE:");
scanf("%d",&choice);
switch(choice)
{
case 1:insert(&q); break;
case 2: val= retrieve(&q);
if(val==-9999)
{
printf("n........ UNDERFLOW........n");
break;
}
31. printf("n THE RETRIEVED VALUE=%dn",val);
break;
case 3: exit(0);
default:printf("n WRONG CHOICE");
}// END OF SWITCH
}// END OF WHILE
} // END OF MAIN
/* DEFINITION OF FUNCTION INSERT */
void insert(struct queue * qp)
{
int val;
if (qp-> rear== size-1)
{
printf(" n........OVERFLOW...........n"); return;
}
printf("n ENTER THE VALUE TO BE INSERTED:");
scanf("%d",&val);
qp->rear++;
qp->item[qp->rear]=val;
printf("n END OF INSERT OPERATIONn");
}
/* DEFINITION OF FUNCTION RETRIEVE */
int retrieve(struct queue * qp)
{
int val;
if (qp->front>qp->rear)
return -9999;
val= qp->item[qp->front];
qp->front++;
return val;
}
34. PRIORITY QUEUE
DEFINITION: Priority queue is a queue, where each element is associated
with a priority. A priority is used to indicate the significance or the precedence
of the element. Generally we consider lower the priority value higher the
precedence. This a very useful data structure to implement process scheduling
in various applications. This can be implemented either on a normal queue or in
a circular queue.
OVERFLOW: Overflow in queue occurs when the number of elements in the
queue becomes equal to the size of the queue. That is, if there does not exist any
space for further insertion of the elements. We assume the overflow of queue
when the value of the member variable ‘rear’+1 becomes equal to ‘front’. This
is a necessary condition to be checked during the push or insertion operation.
UNDERFLOW: Underflow in the circular queue occurs when the queue
becomes empty. Obviously initially the queue is empty, and the member
variables ‘rear’ and ‘front’ are both generally initialized by size-1 or to the
upper bound. Thus to check for the underflow condition necessary during the
insertion, we check whether ‘rear’ is equal to ‘front’ or not.
ALGORITHM:
/* ALGORITHM FOR INSERT OPERATION */
1. STRAT INSERT( Data d)
2. IF (REAR+1)%SIZE== FRONT THEN DISPLAY” OVERFLOW”
GOTO END
3. REAR:=(REAR+1)%SIZE
4. d[REAR].name:=NAME
5. d[REAR].priority:= PR
6. d[REAR].order:= ORD
7. END
/* ALGORITHM FOR RETRIEVE OPERATION*/
1. START RETRIEVE( Data d)
2. IF FRONT==REAR THEN DISPLAY” UNDERFLOW”
GOTO END
3. FRONT:=(FRONT+1)%SIZE
4. ORD:=d[FRONT].ord
5. RETURN ORD
6. END
35. /* C IMPLEMENTATION OF PRIORITY QUEUE */
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define size 5
struct data
{
char name[size]; int pr;int ord;
};
struct queue
{
struct data item[size];int rear; int front;
};
int p=1;
/* FUNCTION PROTOTYPE DECLARATIONS */
void insert(struct queue *);
int retrieve(struct queue *);
void maintain(struct queue *);
void display(struct queue *);
void main()
{
struct queue q; q.rear=q.front=size-1;int choice,val;
clrscr();
while(1)
{
printf("nPRESS 1 TO INSERT");
printf("nPRESS 2 TO RETRIEVE");
printf("nPRESS 3 TO DISPLAY");
printf("nPRESS 4 TO EXIT ");
printf("nENTER YOUR CHOICE:");
scanf("%d",&choice);
36. switch(choice)
{
case 1:insert(&q); break;
case 2: val= retrieve(&q);
if(val==-9999)
{
printf("n........ UNDERFLOW........n");
break;
}
printf("nn NAME= %s PRIORITY= %d ORDER
NO=%dn",q.item[q.front].name,q.item[q.front].pr,val);
break;
case 3:display(&q);break;
case 4: exit(0);
default:printf("nWRONG CHOICE");
}// END OF SWITCH
}// END OF WHILE
} // END OF MAIN
/* DEFINING FUNCTION INSERT */
void insert(struct queue * qp)
{
if ((qp->rear+1)%size==qp->front)
{
printf(" n........OVERFLOW...........n"); return;
}
qp->rear=(qp->rear+1)%size;
printf("n ENTER THE DATA NAME:");
scanf("%s",qp->item[qp->rear].name);
printf("n ENTER THE DATA PRIORITY:");
scanf("%d",&qp->item[qp->rear].pr);
37. qp->item[qp->rear].ord=p;
p++;
printf("n END OF INSERT OPERATIONn");
}
/* DEFINING FUNCTION RETRIEVE */
int retrieve(struct queue * qp)
{
int val;
if (qp->front==qp->rear)
return -9999;
//display(qp);
maintain(qp);
qp->front=(qp->front+1)%size;
val= qp->item[qp->front].ord;
return val;
}
/* DEFINING FUNCTION MAINTAIN */
void maintain(struct queue * qp)
{
int i,j,f=1; struct data temp;
if(qp->rear==0)
return;
for(i=0;i<=qp->rear && f==1;i++)
{
f=0;
for(j=0;j<qp->rear-i;j++)
{
if(qp->item[j].pr>qp->item[j+1].pr)
{
//printf("nj=%d",j);
temp=qp->item[j];
qp->item[j]=qp->item[j+1];
qp->item[j+1]=temp;
38. f=1;
}
}
}
}
void display(struct queue * qp)
{
int m;
m=qp->front;
printf("n DISPLAYING ALL THE INFORMATIONS:n");
printf("n*************************************n");
printf(" NAME PRIORITY ORDER NOn");
while(qp->rear!=m)
{
m=(m+1)%size;
printf("nt%st%dt%d",qp->item[m].name,qp->item[m].pr,qp->item[m].ord);
}
printf("nn");
}
OUTPUT:
39.
40.
41. DOUBLE QUEUE
DEFINITION: Double queue or double ended queue is a queue, where
elements can be inserted and retrieved from the either end of the queue
according to our need. To provide the flexibility to insert and retrieve operation
from both ends, the structure of double queue contains two ‘rear’ (rear A, rearB)
and two ‘front’ (frontA, frontB)variables, assuming rearA and frontA at lower
end and rearB and frontB at upper end.
OVERFLOW: As it provides the facility to insert from either end of the queue,
we can assume three cases (i) inserting only from lower end, (ii) inserting only
from upper end,(iii) inserting from either ends. In the first case the overflow of
double queue when the member variable ‘rearA’ is at position =size-1. For case
two, the overflow occurs when the member variable ‘rearB’ is at position=0. We
can generalize these two cases by considering the overflow condition when
‘rearA+1’ become equal to ‘rearB’ that satisfies the third case too. This is a
necessary condition to be checked during the push or insertion operation.
UNDERFLOW: As it provides the facility to retrieve from either end of the
queue, we can assume three cases (i) retrieving only from lower end, (ii)
retrieving only from upper end,(iii) retrieving from either ends. In the first case
the underflow of double queue when the member variable ‘frontA’ is greater
than ‘rearA’. For case two, the underflow occurs when the member variable
‘frontB’ is greater than ‘rearB’. As the third case is nothing but the above two
cases with user choice, thus we will use a flag variable to indicate the particular
end of the operation (lower or upper). Thus the condition say if f=1 and frontA
greater than rearA or if f=2 and frontB greater than rearB then underflow occurs
would satisfy all three cases. This is a necessary condition to be checked during
the pop or retrieve operation.
ALGORITHM:
/* ALGORITHM FOR INSERT OPERATION */
1. START INSERT( int val)
2. IF RearA+1= RearB THEN DISPLAY” OVERFLOW”
GOTO END
3. IF F=1 THEN RearA:=RearA+1 and Q[RearA]:=VAL
4. ELSE IF F=2 THEN RearB:=RearB-1 and Q[RearB]:=VAL
5. END
42. /* ALGORITHM FOR RETRIEVE OPERATION */
1. START RETRIEVE( )
2. IF F=1 AND FrontA>RearA OR F=2 AND FrontB> RearB THEN
DISPLAY” OVERFLOW” GOTO END
3. IF F=1 THEN VAL:=Q[FrontA] and FrontA:=FrontA+1
4. ELSE IF F=2 THEN VAL:=Q[FrontB] and FrontB:=FrontB-1
5. END
/* C IMPLEMENTATION OF DOUBLE QUEUE*/
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define size 3
struct queue
{
int item[size];int rearA,rearB; int frontA,frontB;
};
/* FUNCTION PROTOTYPE DECLARATIONS */
void insert(struct queue *,int);
int retrieve(struct queue *,int);
void main()
{
struct queue q; q.rearA=-1;q.frontA=0;q.rearB=size;q.frontB=size-1;int
choice,val;
clrscr();
while(1)
{
printf("nPRESS 1 TO INSERT INTO LOWER QUEUE");
printf("nPRESS 2 TO INSERT INTO UPPER QUEUE");
printf("nPRESS 3 TO RETRIEVE FROM LOWER QUEUE");
printf("nPRESS 4 TO RETRIEVE FROM UPPER QUEUE");
printf("nPRESS 5 TO EXIT");
printf("nENTER YOUR CHOICE:");
43. scanf("%d",&choice);
switch(choice)
{
case 1:insert(&q,1); break;
case 2:insert(&q,2); break;
case 3: val= retrieve(&q,1);
if(val==-9999)
{
printf("n... UNDERFLOW IN LOWER QUEUE...n");
break;
}
printf("n THE RETRIEVED VALUE=%dn",val);
break;
case 4: val= retrieve(&q,2);
if(val==-9999)
{
printf("n...UNDERFLOW IN UPPER QUEUE...n");
break;
}
printf("n THE RETRIEVED VALUE=%dn",val);
break;
case 5: exit(0);
default:printf("nWRONG CHOICE");
}// END OF SWITCH
}// END OF WHILE
} // END OF MAIN
/* DEFINING FUNCTION INSERT */
void insert(struct queue * qp,int f)
{
int val;
if (qp->rearA+1==qp->rearB)
{
printf(" n........OVERFLOW...........n"); return;
44. }
printf("n ENTER THE VALUE TO BE INSERTED:");
scanf("%d",&val);
if(f==1)
{
qp->rearA++;
qp->item[qp->rearA]=val;
}
else if(f==2)
{
qp->rearB--;
qp->item[qp->rearB]=val;
}
printf("n END OF INSERT OPERATIONn");
}
/* DEFINING FUCTION RETRIEVE */
int retrieve(struct queue * qp,int f)
{
int val;
if ((f==1 && qp->frontA>qp->rearA)||(f==2 && qp->frontB<qp->rearB))
return -9999;
if(f==1)
{
val= qp->item[qp->frontA];
qp->frontA++;
}
else if(f==2)
{
val=qp->item[qp->frontB];
qp->frontB--;
}
return val;
}
47. CIRCULAR QUEUE
DEFINITION: Circular Queue is a queue, consisting of an array that’s upper
and lower bound are adjacent to each other.
UNDERFLOW: Underflow in the circular queue occurs when the queue
becomes empty. Obviously initially the queue is empty, and the member
variables ‘rear’ and ‘front’ are both generally initialized by size-1 or to the
upper bound. Thus to check for the underflow condition necessary during the
insertion, we check whether ‘rear’ is equal to ‘front’ or not.
OVERFLOW: Overflow in queue occurs when the number of elements in the
queue becomes equal to the size of the queue. That is, if there does not exist any
space for further insertion of the elements. We assume the overflow of queue
when the value of the member variable ‘rear’+1 becomes equal to ‘front’. This
is a necessary condition to be checked during the push or insertion operation.
ADVANTAGEOUS OVER QUEUE:
The reusability of the memory spaces makes it more advantageous over normal
queue. The circular queue provides the facility to reuse the spaces for further
insertion of new elements after the removal of the elements from the queue.
This is due to overflow condition that instead of restricting the rear to size-1,
provides the flexibility to follow the front. Thus whenever an element has been
removed, the front moves forward and making space for the rear to insert a new
element.
ALGORITHM:
/*ALGORITHM FOR INSERT OPERATION*/
1. START INSERT( int val)
2. IF (REAR+1)%SIZE== FRONT THEN DISPLAY” OVERFLOW”
GOTO END
3. REAR:=(REAR+1)%SIZE
4. Q[REAR]:=VAL
5. END
/*ALGORITHM FOR RETRIEVE OPERATION*/
1. START RETRIEVE( )
2. IF FRONT==REAR THEN DISPLAY” UNDERFLOW”
GOTO END
3. FRONT:=(FRONT+1)%SIZE
48. 4. VAL:=Q[FRONT]
5. RETURN VAL
6. END
/* C IMPLEMENTATION OF CIRCULAR QUEUE*/
#include<stdio.h>
#include<conio.h>
#include<process.h>
#define size 3
struct queue
{
int item[size];int rear; int front;
};
/* FUNCTION PROTOTYPE DECLARATIONS */
void insert(struct queue *);
int retrieve(struct queue *);
void main()
{
struct queue q; q.rear=q.front=size-1;int choice,val;
clrscr();
while(1)
{
printf("nPRESS 1 TO INSERT");
printf("nPRESS 2 TO RETRIEVE");
printf("nPRESS 3 TO EXIT ");
printf("nENTER YOUR CHOICE:");
scanf("%d",&choice);
switch(choice)
{
case 1:insert(&q); break;
case 2: val= retrieve(&q);
49. if(val==-9999)
{
printf("n........ UNDERFLOW........n");
break;
}
printf("n THE RETRIEVED VALUE=%dn",val);
break;
case 3: exit(0);
default:printf("nWRONG CHOICE");
}// END OF SWITCH
}// END OF WHILE
} // END OF MAIN
/* DEFINING FUNCTION INSERT */
void insert(struct queue * qp)
{
int val;
if ((qp->rear+1)%size==qp->front)
{
printf(" n........OVERFLOW...........n"); return;
}
printf("n ENTER THE VALUE TO BE INSERTED:");
scanf("%d",&val);
qp->rear=(qp->rear+1)%size;
qp->item[qp->rear]=val;
printf("n END OF INSERT OPERATIONn");
}
/* DEFINING FUCTION RETRIEVE */
int retrieve(struct queue * qp)
{
int val;
51. POLISH NOTATION
According to the position of a binary operator, an expression can be of three types:
i) Infix Expression: An expression is said to be infix if the position of the operand is in
between the two operands. Thus the general syntax is “operand1 operator operand2”.
Ex: a+b, a*b, a/b, a$b, a+b*c etc.
ii) Prefix expression: An expression is said to be prefix if the position of the operand is
before the two operands. Thus the general syntax is “operator operand1 operand2”.
Ex: +ab,*ab, /ab, +*abc, *+abc etc.
iii) Postfix expression: An expression is said to be postfix if the position of the operand is
after the two operands. Thus the general syntax is “operand1 operand2 operator”.
Ex: ab+, ab*, ab/, abc+*,abc*+ etc.
Precedence and Associativity of the operators:
OPERATOR ASSOCIATIVITY PRECEDENCE
$ RIGHT TO LEFT HIGHEST
*,/,% LEFT TO RIGHT
+,- LEFT TO RIGHT LOWEST
NOTE: OPERATORS WITH SAME PRECEDENCE EXECUTES ACCORDING TO THEIR
ASSOCIATIVITY
PREFIX AND POSTFIX OF CORRESPONDING INFIX EXPRESSION
INFIX POSTFIX PREFIX
A+B AB+ +AB
A+B-C AB+C- -+ABC
(A+B)*(C-D) AB+CD-* *+AB-CD
A-B/(C*D$E) ABCDE$*/- -A/B*C$DE
A$B*C-D+E/F/(G+H) AB$C*D-EF/GH+/+ +-*$ABCD//EF+GH
((A+B)*C-(D-E))$(F+G) AB+C*DE - - FG+$ $-*+ABC-DE+FG
52. EVALUATION OF A POSTFIX EXPRESSION
ALGORITHM
While (not end of postfix string)
{
symb=next element of the postfix string
if(symb is an operand)
{
push(stack,symb);
}
else if( symb is an operator)
{
val1= pop(stack);
val2= pop(stack);
result= apply symb on val2 and val1;
push(stack,result);
}
}
result= pop(stack);
return result;
Note:
Stack here is a character array having the logic of first in last out or last in first out and push
and pop are the standard insert and retrieve operations in stack.
54. C IMPLEMENTATION OF EVALUATION OF POSTFIX STRING
# include <stdio.h>
# include <conio.h>
# include <stdlib.h>
# include <math.h>
# define SIZE 100
// Declaration of stack structure
typedefstruct stack
{ double item [SIZE] ;
int top ;
} stack ;
// Prototype declaration of functions
void push ( stack * , double) ;
double pop ( stack * ) ;
double evaluate ( char [ ] ) ;
double operate ( double, double, char ) ;
// Function Definitions
void push ( stack * sp , double value )
{
if ( sp -> top == SIZE - 1 )
{
printf (" n stack overflow ……..");
exit (0);
}
sp ->item [ ++sp ->top ] = value ;
}
double pop ( stack *sp )
{
if ( sp->top == - 1 )
{
55. printf (" n stack underflow ……..");
exit (0) ;
}
return (sp->item[sp->top--]) ;
}
// Starting main()
int main ()
{
char postfix [ SIZE ] ;
double value ;
printf(" n Enter postfix string seperated by comma:");
scanf("%s" , postfix ) ;
value = evaluate (postfix);
printf (" n value of the given expression is=%lf",value);
getch();
return 0;
}
// Evaluation of the postfix expression
double evaluate ( char postfix [ ] )
{
stack s ;
int i, j ; double result, value, value1, value2 ;
char temp [20];
s.top =-1; i = 0;
while(postfix[i]!='0')
{
j=0;
while ( postfix [i] != ',' && postfix [i]!='0' )
{
temp[j++] = postfix[i++] ;
}
temp [j] ='0';
value = atof(temp);
if ( value!=0)
{
push (&s, value ) ;
56. }
else if ( value == 0 && temp [0]!= 0)
{
value1 = pop(&s);
value2 = pop(&s);
result = operate(value2,value1, temp[0]);
push(&s, result ) ;
}
if ( postfix [i]!='0')
i++;
}
result= pop(&s);
return result;
}
// Calculating the result on the basis of the operator
double operate (double left, double right, char opr)
{
double result = 0.0;
switch (opr)
{
case '+' : result = left + right ;
break ;
case '-' : result = left - right ;
break ;
case '*' : result = left * right ;
break ;
case '/' : result = left / right ;
break ;
case '$' : result = pow(left,right ) ;
break ;
}
return result ;
}
57. O/P: [EX1, EX2]
INFIX TO POSTFIX CONVERSION
ALGORITHM
1. Create a stack
2. for each character „t‟ in the input stream {
if (t is an operand)
add „t‟ to the output postfix string
else if ( till the stack is not empty and priority of stack top is higher than
the current symbol read){
POP and add it to the output postfix string if not opening parenthesis
}
if (current symbol is not closing parenthesis){ Push the symbol into stack
else{ pop and add it to the output postfix string}
}
3. POP and add the remaining symbols to the output postfix string until the
stack is empty.
58. STACK TRACE
EX:A * B – (C + D) + E
INPUT
CHARACTER OPERATION ON STACK STACK
POSTFIX
EXPRESSION
A Empty A
* Push * A
B * A B
– Check and Push – A B *
( Push – ( A B *
C – ( A B * C
+ Check and Push – ( + A B * C
D – ( + A B * C D
)
Pop and append to postfix till
„(„ – A B * C D +
+ Check and push + A B * C D + –
E + A B * C D + – E
End of Input Pop till Empty Empty A B * C D + – E +
59. C IMPLEMENTATION FOR INFIX TO POSTFIX CONVERSION
//INFIX TO POSTFIX CONVERSION
#include<stdio.h>
#include<conio.h>
#define SIZE 100
struct stack
{
char item[SIZE];
int top;
};
struct stack s;
enumboolean
{
f=0, t=1,
};
void push(struct stack *,char);
char pop(struct stack *);
void convert(char[],char[]);
booleanprec(char,char);
int main()
{
char postfix[SIZE],infix[SIZE];
printf("n ENTER THE INFIX STRING:");
scanf("%s",infix);
convert(infix,postfix);
printf("n THE REQUIRED CONVERTED ANSWER IS:%s",postfix);
getch();
return 0;
}
void convert(char infix[],char postfix[])
{
int i=0,j=0;
s.top=-1;
charsymb;
while(infix[i]!='0')
{
if(infix[i]>='0'&&infix[i]<='9')
63. TREE
DEFINITION: A tree is a finite set of one or more nodes such that,
i. There is a specially designated node known as root
ii. The remaining nodes are partitioned into n>=0 disjoint sets T1,T2,……Tn
where each of these sets is tree. The sets T1,T2,……Tn are the sub- trees of
the root.
The sets are disjoint with each other, since they are not interconnected by
any link or edge.
T1 T2
T3
A Sample Tree T
In the sample tree T there is a set of 11 nodes. Here A is a specially designated
node, root of the tree. The remaining nodes are partitioned into 3 disjoint sets T1,
T2, T3 they are sub-trees of the root. The same tree can be expressed in a string
notation: T= (A(B(E,F),C(G(M)),D(H,K,L))
TERMINOLOGIES:
F
D
A
B
C
G
E
KH
A
B
F
D
LE H KG
C
M
64. TREE
NODE- Each element of the tree is known as node, and represented by a circle.
EDGE- The lines connecting the nodes are called edges or branches.
PARENT- The immediate predecessor of any node is called the parent node. Ex: A
is the parent of nodes B, C, D and C is parent of F.
CHILD- All the immediate successors of a node are its children. Ex: B, C, D is
children of A and G is a child of D and H is a child of E.
SIBLING- Two or more children having same parent are called siblings or brothers.
Ex: B, C, D is siblings, since children of same parent A.
LEAF- A node does not have any child known as leaf node. Ex: H, F, K.
DEGREE- The number of sub-trees or children of any node is called the degree of
a node. Ex: deg (A) =3, deg (B) =1, deg (F) =0.
The degree of a tree is the maximum degree of a node in the tree. Ex: the degree
of the above tree is 3.
LEVEL- level of any node is the distance of that node from the root. The level of
the root is 0 and the level of any node is one more than the level of its parent. Ex:
level (A) =0, level (B) = 0+1=>1, level (E) =1+1=>2, level (H) = 2+1=>3
DEPTH- The maximum level of any node is known as the depth of the tree. Ex: the
depth of the above tree is max (0, 1, 2, 3) =3
HEIGHT- The total number of levels in the tree is known as the height of the tree.
Ex: the height of the above tree is 4, since there are four levels 0, 1, 2, 3.
FOREST-A forest is a set of n>=0 disjoint trees, that is, removing the root of tree,
will make it a forest.
65. PATH- Path of a node is defined as the sequence of nodes N1, N2,….., Nm such that
each node Ni is parent of node Ni+1 where 1<i<m. there is only one path between
two nodes. The path length is the number of edges in the path.
ANCESTERAND DESCENDENT- Any node Na is said to be the ancestor of the node
Nm if Na lies in the unique path from the root to the node Nm. Ex: D is an ancestor
of the node K. if Na is an ancestor of the node Nm then Nm is called the descendent
of node Na.
INTERNAL NODE- All the non leaf nodes are known as internal nodes. Ex: A, B, C,
D, E, G.
EXTERNAL NODE- All the leaf nodes are also known as external nodes. Ex: H, F, K.
INTERNAL PATH LENGTH- Sum of the levels of the internal nodes is known as
internal path length. Ex: level(A)=0, level(B)=1, level(C)= 1, level(D)=1, level(E)=2,
level(G)=2, therefore the internal path length is= 0+1+1+1+2+2=7
EXTERNAL PATH LENGTH- Sum of the levels of the external nodes is known as
external path length. Ex: level (F) =2, level (H) =3, level (K) =3, therefore external
path length is= 2+3+3=8
CHARECTERIZATION
• BINARY TREE:: A binary tree T is a finite set of nodes that is
i. Either empty or
ii. Contains a specially designated node called the root and partitioned
into two disjoint sets T1 and T2 where both of them are binary trees.
T1 and T2 are known as the left and the right sub-trees respectively.
Binary trees
A
A A
A
A
A
A
A A
A
A
A
A A
66. PROPERTIES:
1. The maximum number of nodes possible at level i is 2i
where i>=0
Proof- This can be proved by induction on i. the root node is the only node at
level 0. So the maximum number of node at level i=0 is 1 that is 20
. So the
property is true for i=0. Now let the property is true for level k, thus the
maximum number of nodes at level k is 2k
where k>=0. Each node in the binary
tree can have at most 2 children, so the maximum number of children in the
next level k+1 will be twice the number of nodes at level k that is 2* 2k
= 2k+1
.
So this property is true for any k then it will be true for k+1. Hence proved.
2. The maximum number of nodes possible in a binary tree of height h is
2h
-1
Proof- The maximum number of nodes in a binary tree can be expressed as the
sum of the maximum number of nodes possible at each level. The maximum
level of a tree (depth) is h-1, since starting from level 0 and the maximum
number of nodes at any level i is 2i
. So the total number of nodes possible in a
binary tree of height h is,
N=∑i=0
h-1
2i
= 20
+21
+22
+……+2h-1
(Geometric progression)
=1+2+4+8………
=2(h-1)+1
-1/2-1
=2h
-1
3. The minimum number of nodes possible of height h is equal to h.
Proof – A tree will have minimum number of nodes if each level has minimum
nodes. The minimum number of nodes possible at any level is 1, and there are
67. total h levels, thus the minimum number of nodes possible in a binary tree of
height h is equal to h.
4. A binary tree having n nodes then the minimum height of the tree is
log2 (n+1).
Proof- If each node has exactly two children then the maximum value of
number of nodes (n) will be 2h
-1.
N<=2h
-1
Or, n+1<=2h
or, log2 (n+1) <=h or, h>=log2 (n+1) (proved)
5. For any non empty binary tree if n0 is the number of nodes with no child
and n2 is the number of nodes with two child then n0=n2+1.
Proof- Consider that the relationship holds for n=m. for n=m, Tnull=m+1. Now
for n=m+1, increment of one node means increment of two null nodes and
decrement of null node. So the resultant increment of null nodes is 1. So for
n=m+1, Tnull= (m+1)+2-1=(m+1)+1. Thus for any non empty binary tree n0=n2+1.
6. The total number of binary tree possible with n nodes is 1/n+1* 2n
cn
• COMPLETE BINARY TREE:: A binary tree T is said to be a complete binary
tree if all the levels of the tree have exactly maximum number of nodes
possible at that level. OR
A binary tree T is said to be complete binary tree if all the leaf nodes are at
the same level d, where d is the depth of the tree.
CBT CBT NCBTA
B C
G
C
D
D E F
B
FE
A
CB
A
D E
68. ALMOST COMPLETE BINARY TREE:: A binary tree of depth d is said to be a
almost complete binary tree if it satisfies the following two conditions-
i. Any node n at level less than d-1 must gave two children, where d is
the depth of the tree.
ii. For any node n, having right descendent at level d, must have a left
son, and every left son is either a leaf at level d or must have two
children.
NACBT NACBT
The 1st
tree in the above figure violating the rule (i), since depth=3, so
according to rule (i) all the nodes up to level 1 must have two children. But the
node C at level 1 is a leaf node.
The 2nd
tree in the above figure, satisfying the rule (i), since all the nodes up to
level 1 have two children. But violating the rule (ii), since the node A having a
right descendent (J, K) at level d, but possessing a left son at level 2(E), which is
leaf.
ACBT
A
CB
D
F G
E
A
B C
D E F
K
G
IH J
B
A
C
D E F G
H I
69. The above figure satisfies both rule (i) and rule (ii). Thus it is an almost complete
binary tree.
• STRICTLY BINARY TREE:: A binary tree T is said to be a strictly binary tree or
2-tree if the nodes are either a leaf or having exactly two children.
SBT NSBT NSBT SBT
PROPERTIES:
1) A strictly binary tree with n non leaf nodes has n+1 leaf nodes.
Proof- We can prove this property by induction on the number of non leaf nodes.
If a binary tree only have root node, then it has no non leaf node but have one
leaf node. So it is true for n=0. We will take a strictly binary tree with k non leaf
nodes (k>0) and assume that this property is true for both the left and right sub
trees. Suppose the left sub tree has m no of non leaf nodes, so the right sub tree
will have k-m-1 no of non leaf nodes. Since the property is true for both sub trees,
left sub tree will have m+1 no of leaf nodes and the right sub tree will have k-m-
1+1 no of leaf nodes. So the total no of leaf node are m+1+k-m-1+1=k+1 no of
nodes. Hence the property is true.
2) A strictly binary tree with n leaf nodes has total 2n-1 nodes.
Proof- We know that the strictly binary tree with n no of non leaf nodes will have
n+1 no of leaf nodes. Thus the total no of nodes are n+n-1=2n-1.
3) If E is the external path length and I is the internal path length and n is the
total number of internal node, then E=I+2n.
A
AA
A
A A
A A
A
A
A
A
AA
AA
70. Proof- If a tree contains only its root and no other vertices then E=I=N=0 and it is
trivial. Now let us consider a non leaf vertex v but for which both of the children
are leaves. Let k be the length of the path from the root to the vertex.
Now if we delete the children of v from the 2-tree, then the number of non leaf
node goes down from N to N-1, the internal path length will reduced by the
distance to v that is I=I-k, and the distance to the child of the vertex k is k+1, so
the external path length will be reduced to E=E-2(k+1). But now the vertex v also
a leaf, so the distance of v should be added to the external path length. So the
actual external path length will be, E=E-2(k+1) + k=E-K-2. If the retains the
property, then
E-K-2= (I-K) +2(N-1)
Or, E-K-2=I-k+2N-2
Or, E=I+2N (Proved)
• BINARY SEARCH TREE:: A binary search tree is an import data-structure,
when a two way decision must be made at each point of data insertion,
searching and deletion in a tree. It is-
i. Either empty or
ii. Consist of root, right and left sub-tree where all the keys in the left
sub tree are less than the key of the root and all the keys in the right
sub tree are greater than the key of the root, and the left and right
sub tree both are also binary search tree.
Binary Search Trees
5
2 8
B
A C
5
6
7
C
A
B
71. INSERTION INTO BINARY SEARCH TREE:
Ex1: 4 2 6 1 3 5 7
i.
ii.
iii.
iv.
v.
vi. vii.
4
4
2
4
62
4
2 6
1
4
2 6
1 3
5
2
1 3
6
4 4
2 6
1 53 7
72. Ex2: M B T G P E S
i.
ii.
iii.
iv.
v.
vi. vii.
M
M
B
TB
M
M
T
P
T
G
B
B
G
M
E
P
M
T
G
B T
S
G P
E
M
B
73. • BINARY TREE TRAVERSING:
Traversing in binary tree means visiting each node of the tree exactly once.
Traversing of trees gives the linear order of the nodes. The task of
traversing the tree consists of visiting the root, left and right sub trees.
Among the 3! =6 ways, we generally follow 3 of it. Depending on the
position of the root, a binary tree traversing can be classified into following
three forms-
➢ INORDER- left->root->right
➢ PREORDER-root->left->right
➢ POSTORDER-left->right->root
Ex1:
INORDER—DBEAFCG PREORDER—ABDECFG POSTORDER-- DEBFGCA
Ex2:
A
CB
D E F G
CB
H
F
A
ED
K
G
LI J
74. INORDER—DIGJBAECKHLF PREORDER—ABDGIJCEFHKL POSTORDER—
IJGDBEKLHFCA
Ex3:
INORDER—BFDLJMGAHENKPIC PREORDER—ABDFGJLMCEHIKNP
POSTORDER—FLMJGDBHNPKIECA
In case of preorder traversing of the tree the roots are lies from the left to the
right and in case of postorder traversing the roots are lies from the right to the
left.
• CREATION OF BINARY TREE FROM INORDER AND PREORDER TRAVERSALS
PREORDER: ABDHECFIGJK INORDER: DHBEAIFCJGK
i) The root of the tree is the 1st
element of the preorder. Here it is A. Now
from inorder expression the elements on the left and on the right are
the left and right sub trees of the root respectively.
A
B C
D
F G
J
L M
E
H I
K
N P
A
DHBE IFCJGK
75. ii) Now we will move from the left to the right of the preorder expression
to get the next root. Here it is B. The elements D and H are on the left
and the element E is on the right of B in the inorder expression. Thus we
can conclude,
iii) Next root in the preorder is D. The only element on the right side
between D and the previous root B is H, and no elements on the left
hand side of D. Thus,
iv) The next two roots after D in the expression are H and E that are already
being accessed. The root after E in the expression is C. the left elements
of C are I and F and the right elements are J, G and K. Thus,
IFCJGKB
A
EDH
D E
H
B
A
IFCJGK
E
H
JGK
A
C
D IF
B
76. v) The next root F, having a single element I on the left and no right
element. Thus,
vi) The next root after F is I, and is already being accessed. The next root
after I is G, having left element J, and right element K in the inorder
expression. Thus,
CREATION OF BINARY TREE FROM INORDER AND POSTORDER TRAVERSAL
POSTORDER: HIDJEBKFGCA INORDER: HDIBEJAKFCG
i) The root of the tree is the last element of the postorder expression.
Here it is A. all the elements on the right and left side of A are the right
and the left sub trees respectively.
JGKF
H
ED
CB
A
I
E
B
A
D
H
C
F
I
G
KJ
77. ii) The next root is the 2nd
last element, here it is C. the right and the left
elements in the expression are G and K, F.
iii) The next root is G and already is being accessed. The root after G is F
and has only one left child K.
iv) The next root K is already accessed. The root after K is B, having two left
child E, J and three right children H, D, I in the inorder expression.
A
HDIBEJ KFCG
A
HDIBEJ C
GKF
A
K
F G
CHDIBEJ
C
GHDI
B
A
F
K
EJ
78. v) The next root E having only one right child J.
vi) The next root J is already accessed. The root after J is D and having one
left child H and one right child I.
• EXPRESSION TREES:
Any algebraic expression can be represented by a binary tree, in which the
leaf nodes are the operands, and the non leaf nodes are unary or binary
operators. The left child represents the left operands and the right child
represents the right operands. Although the parentheses do not appear in
the tree, but the tree retains the purpose of parenthesis.
Ex: (A*B) + (C/D)
A
B C
F
K
GHDI E
J
A
B C
F G
K
D E
JH I
+
* /
A B C D
79. TRAVERSING IN EXPRESSION TREES
EXPRESSION—(A-B*C) / (D+E/F)
INORDER—A - B * C / D + E / F PREORDER-- / - A * B C + D / E F
POSTORDER—A B C * - D E F / + /
The inorder, preorder and postorder traversing gives the corresponding infix,
prefix and the postfix expression of an algebraic expression. The inorder
traversing gives the actual order which the expression should be evaluated or the
operations to be performed.
TREE REPRESENTATION OF THE FOLLOWING PREFIX EXPRESSION
i) *A+*B-CDE ii) *A+B*C-DE
/
-- +
A *
B C
D /
FE
*
B
A
+
*
B
--
A
E
*
C
*
C
+
E
--
D
D
80. TREE REPRESENTATION OF THE FOLLOWING POSTFIX EXPRESSION
i) A C D * + ii) C D * A B / +
• ARRAY REPRESENTATION OF BINARY TREE
A binary tree can be represented by using a one dimensional array. Let us
consider the following binary tree. 0
1 2
3 4 5
6 7 8
To represent the above binary tree in an array we store the contents of the
each node in an array named data.
0 1 2 3 4 5 6 7 8
data [ ] =
Now to define the parent child relationship we have to maintain two other arrays,
say left and right, such that left [0] holds the index of the left child of data [0] and
right [0] holds the index of the right child of data [0]. So the right array is,
0 1 2 3 4 5 6 7 8
right [ ] =
And the left array is, 0 1 2 3 4 5 6 7 8
left [ ] =
+
A *
BAC D
/*
+
DC
A
I
E
B
D
C
F
HG
A B C D E F G H I
2 4 -1 6 -1 8 -1 -1 -1
1 3 5 -1 7 -1 -1 -1 -1
81. We have used the value -1 to represent an empty sub tree. The above
representation requires 3*n spaces to represent a binary tree having n number of
nodes. However we can represent the above tree using a single array. To
represent a binary tree using a single one dimensional array, the nodes of the tree
need to be numbered sequentially, level by level, starting with 0. All the nodes are
should be numbered from the left to the right of a level, including the empty
nodes. 0
1 2
3 4 5 6
7 8 9 10 11 12
Now, it can be noted that, if the n umber appearing for any node is n is I, then the
left and the right child of node n has the number 2*i+1 and 2*i+2 respectively. We
can simulate the above tree in an array,
0 1 2 3 4 5 6 7 8 9 10 11 12
tree[ ] =
The size of the array will be minimum, if the height h is minimum, and it will be
maximum if the height h is maximum. The height is minimum for a complete
binary tree, which is log2 (n+1), and total number of nodes are 2log(n+1)
-1.
• LINKED LIST REPRESENTATION OF BINARY TREE
The linked representation overcomes the problems encountered in an array
representation. Unlike the implicit representation in an array, in this
representation the pointers are used explicitly to link the nodes of the tree. In
linked representation we take three members of a node. First member is the left
pointer of node type to store the address of the left sub tree, the second member
A
B C
D E F
HG I
A B C D E F -1 -1 G H -1 -1 I
82. is the data or the information and third member is the right pointer of node type
to store the address of the right sub tree.
struct node{ struct node* left; int info;struct node * right;};
This is a self-referential structure (A structure having members of the same type
as the structure). If any of the children is empty, then the corresponding pointers
will be set to NULL (A macro having value 0).
To store the address of the first node or the root node of the tree, we use a
pointer root of node type. If the content of root pointer is NULL, then we can
conclude that the tree is empty.
C IMPLEMEMTATIONS OF DIFFERENT OPERATIONS
// RECURSIVE FUNCTION FOR INORDER TRAVERSING IN BINARY TREE
void inorder(struct node *root)
{
while (root!=NULL)
{
inorder (root->left);
printf(“%d”,root->info);
50 2 100
150 4 200
NULL 8 NULL NULL 5 NULLNULL 3 NULL
250 6 300
NULL 1 NULL
83. inorder( root->right);
}
}
// RECURSIVE FUNCTION FOR PREORDER TRAVERSING
void preorder (struct node *root)
{
while ( root!=NULL)
{
printf(“%d”,root->info);
preorder(root->left);
preorder(root->right);
}
}
// RECURSIVE FUNCTION FOR THE POSTORDER TRAVERSING
void postorder(struct node*root)
{
while(root!=NULL)
{
postorder (root->left);
postorder (root->right);
printf(“%d”,root->info);
}
}
// NON RECURSIVE INORDER TRAVERSING
void inorder( struct node * * rt)
{
struct node *p;
if(*rt==NULL)
{
printf(“n tree is empty”);return;
86. return;
p=pop(&s);
}
push(&s,p); p=p->right;
}
// RECURSIVE FUNCTION FOR IN SERTION INTO BINARY SEARCH TREE
void insert( struct node **rt, int val)
{
struct node * p;
p=(struct node*) malloc(sizeof(struct node));
if(p==NULL)
{
printf(“n no space in memory”); return;
}
p->info=val;p->right=NULL;p->left=NULL;
if(*rt==NULL)
*rt=p;
else if( val>(*rt)->info)
insert((&(*rt)->right),val);
else if(val<(*rt)->info)
insert((&(*rt)->left),val);
}
// NON RECURSIVE FUNCTION FOR INSERTION INTO BINARY SEARCH TREE
void insert(struct node* rt, int val)
{
struct node * p,* current,*parent;
p=(struct node*) malloc(sizeof(struct node));
if(p==NULL)
{
printf(“n no space in memory”); return;
92. TREE EXTENDED
INTRODUCTION: The first balanced binary search tree was the AVL tree (named after its discoveries,
Adelson Velskii and Landis). The AVL tree is a binary search tree that as an additional balance condition
must be easy to maintain and ensures that the depth of the tree is O (log N). The simplest idea is to
require that the left and right sub-trees have the same height. Recursion dictates that this idea applies
to all nodes in the tree, since each node is itself a root of some sub-tree. This balance condition ensures
that the depth of the tree is logarithmic, but it is too restrictive because it is too difficult to insert new
items while maintaining balance. Thus the AVL trees use a notion of balance that is somewhat weaker
but still strong enough to guarantee logarithmic depth.
12
8 16
4 10 14
2 6
1
EXMPLE: Insert the following keys in order shown to construct an AVI, tree
10, 20, 30, 40, 50
Delete the last two keys in the order of LIFO
: Insert 10, 20
Insert 30 RR-rotation
10
20
10
10
10 10
10
10
93. TREE EXTENDED
Insert 40
Insert 50
RR-rotation
Advantages of an AVL tree :
Since AVL trees are height balanced trees , operations like insertion and deletion have less time
complexity.
Let us consider an example . If we have the following trees with keys 10,20,30,40,50,60,70, then a
binary tree would look like this.
10 40
20
30 20 60
40
50 10 30 50 70
60
(a) BST 70 (b) AVL TREE
10
10 10
10
10
10
10
10
10
10
10 10
10 10
94. TREE EXTENDED
In order to insert a node with a key ‘k’ in the binary tree (a) , the algorithm requires 7 comparisons , but
if we insert the same key in AVL tree(b) ,the algorithm will just require 3 comparisons , which is less than
half of the binary search tree.
Thus ,AVL search trees will increase the efficiency of the programs.
INSERTION IN B-TREE :
the insertion of a key in a B-tree requires first traversal in B-tree. Through traversal it will find that key
to be inserted is already existing or not. Suppose key does not exist in tree then through traversal it will
reach leaf node. Now we have two cases for inserting the key.
1. Node is not full.
2. Node is already full.
If the leaf node in which the key is to be inserted is not full, then the insertion is done in the node. A
node is said to be full if it contains a maximum of ( m-1 ) keys, given the order of the B-tree to be m.
If the node werw to be full, then insert the key in order into the existing set of keys in the node, split
the node at its median into two nodes at the same level, pushing the median up by one
level. Note that the split nodes are only half full. Accommodate the median element in the parent
node if it is not full. Otherwise repeat the same procedure and this may even call for rearrangement
of the keys in the root node or the formation of a roof itself.
Thus a major observation pertaining to insertion in a B-tree is tht, since the leaf nodes are all at the
same level, unlike m-wy search trees, the tree grows upwards.
EXAMPLE . Let us take a list of keys and create a B-tree of order 5.
10, 20, 50, 60, 40, 80, 100, 70, 130, 90, 30, 120, 140, 25, 35, 160, 180
Solution :
1. Insert 10 10
2. Insert 20 10 20
3. Insert 50 10 20 50
4. Insert 60 10 20 50 60
95. TREE EXTENDED
40
5. Insert 40
10 20 50 60
Here node was already full , so after insertion of 40 , it is splitted into two nodes , 40 is the median
key so it will go into parent node and it will become root.
Insert 80 40
10 20 50 60 80
Insert 100 40
10 20 50 60 80 100
Insert 70
Here node was already full, so after insertion of 70 it splitted into two nodes, 70 is the median key, so it
will go to the parent node.
Insert 130
Insert 90
40 70
10 20 50 60 80 100
40 70
10 20 50 60 80 100 130
40 70
10 20 50 60 80 90 100 130
96. TREE EXTENDED
Here after insertion of 90, the keys in node will be sorted.
Insert 30
Insert 120
Here node was already full, so after insertion of 120 it splitted in two nodes, 100 is the median
key so it will go into parent.
Insert 140
DELETION IN B-TREE:
Deletion of key also requires first traversal in B-tree , After reaching on particular node , two cases may
occur :
1. Node is leaf node.
2. Node is non-leaf node
40 70
10 20 30 50 60 80 90 100 130
10 20 30
40 70 100
50 60 80 90 120 130
40 70 100
10 20 30 120 130 14050 60
30
80 90
30
97. TREE EXTENDED
Delete 60.
Here 60 is in no leaf node. So first it will be deleted from the node and then the element of the right
child will come in that node.
Delete 40.
Here first 40 will be deleted from leaf node then left side element in the parent node will come in leaf
node and then last element of the left side node of the parent node will come in parent node.
105
30 70 135 185
5 15 20 40 50 80 90 110 120 140 160 200 250
105
7020 135 185
5 15 30 50 80 90 110 120 140 160 200 250
98. TREE EXTENDED
Delete 140.
But at least two elements should be in child node so it will go in root node.
EXAMPLE : Suppose a B-tree of order-5 is shown in the Fig.
105
20 70 185
5 15 30 50 80 90 110 120 135 160 200 250
20 70 105 185
5 15 30 50 80 90 110 120 135 160 200 250
10
3 6 13 18
1 2 4 5 7 8 9 11 12 14 16 19 20 21 24
99. TREE EXTENDED
Delete 8.
Deletion of 8 is from a leaf node with more than the minimum number of elements and hence leaves no
problem.
Delete-18.
Deletion of 18 is from non-leaf node and therefore the immediate successor is placed at 18, i.e.. 19.
Delete-16.
2
10
3 6 13 18
1 4 5 7 9 11 12 14 16 19 20 21 24
10
3 6 13 19
1 2 4 5 7 9 11 12 14 16 20 21 24
10
3 6 13 20
1 2 4 5 7 9 11 12 14 19 21 24
100. TREE EXTENDED
Deletion of 16 leaves its nodes with too few elements. The element 19 from parent node is therefore
brought down and replaced by the element 20.
Delete- 4
The deletion of 4 leaves the node with less than minimum number of elements and neither of its sibling
nodes can spare an element. The node therefore is combined with one of the siblings and with the
median element from the parent node.
But at least two elements should be in the child of root so it will go in root node.
It reduces the height of tree also.
APPLICATION OF A B-TREE
The main application of a B-tree is the organization of a huge collection of records into a file structure.
The organization should be in such a way that any record in it can be searched very efficiently I.e.,
insertion, deletion and modification operations can be carried out perfectly and efficiently
10
6 13 20
1 2 3 5 7 9 11 12 14 19 21 24
6 10 13 20
1 2 3 5 7 9 11 12 14 19 21 24
101. TREE EXTENDED
B+
-TREES
The B-tree structure is the standard organization for indexes in a database system. There are several
variations of the B-tree, most well known being the B*-tree and the B+ - tree. The B -tree guarantees at
least 50% storage utilization, that is, at any given time, the tree has each of its nodes at least 50% full.
The B+ -tree is a slightly different data structure, which in addition to indexed access, also allows
sequential data processing and stores all data in the lowest level of the tree.
One of the major drawbacks of the B-tree is the difficulty of traversing the keys sequentially.
B+ tree retains the rapid random access property of the B-tree, while also allowing rapid sequential
access. In the B+ tree, all keys are maintained in leaves and keys are replicated in non-leaf nodes to
define paths for locating individual records. The leaves are linked together to provide a sequential path
for traversing the keys in the tree.
The b+ -Tree is called a balanced tree because every path from the root node to a leaf node is
the same length. A balanced tree means that all searches for individual values require the same number
of nodes to be read from the disk.
B+ tree
• Is a structure of nodes linked by pointers
• Is anchored by a special node called the root and bounded by leaves
• Has a unique path to each leaf, and all paths are equal length
• Stores keys only at leaves, and stores reference value in other, internal nodes
• Guides key search, via the reference values, from the root to the leaves
A B + tree of order M (M>3) is an M-ary tree with the following properties:
1. The data items are stored at leaves.
2. The root is either a leaf or has between two and M children.
3. Node :
• The (internal) node (non-leaf) stores up to M – 1 keys (redundant) to guide the
searching; keyi represents the smallest key in subtree i + 1.
• All nodes (except the root) have between M2 and M children
4. Leaf :
• A leaf has between L2 and L data items, for some L(usually L << M, but we will
assume M = L in most example).
• All leaves are at the same depth.
5. Less disk access due to fewer levels in the tree.
6. B*tree provides faster sequential access of data.
102. TREE EXTENDED
Index set
Sequence set
As we can see in the figure, the leaves have been connected to from a linked list of keys is sequential
order. The B+tree has two parts the first part is the index setthat constitutes interior nodes and the
second part is theSequence set that constitutes leaves.
B+ -Tree Structure
B+-tree consists of two parts :
Index Set
• Provides indexes for fast access of data.
• Consist of internal nodes that store only key & sub tree pointers.
Sequence set
• Consists of leaf nodes that contain data pointers.
• Provides efficient sequential access of data (using doubly linked list).
98
36 53 81 10
4
36
8 17 36 42 53 56 65 72 81 83 96 98 102 104 107 112 119 125 127
103. TREE EXTENDED
Sequential search Sequence set
B+ -Tree: Index Node Structure
The basic structure of the B+ -tree index node of order m is same as that of B-tree node of order m.
The root has at least two sub-trees unless it is a leaf.
Each non-root index node holds q – 1 keys and q subtree pointers, where m2 < q<m
Only difference is that index node does not contain data pointers.
B4
- Tree : Sequence Node Structure
The structure of the B+ - tree sequence node is as follows :
K1 D1 KI-1 DI-1 KI DI KQ-1 DQ-1
Index set
P1 K1 P2 Ki-1 Pi Ki Kq-1 Pq
104. TREE EXTENDED
.If an internal node is reached :
.Search KEY among the keys in that node
.Linear search or binary search
.If KEY ≤ smallest key , follow the leftmost child pointer down
.If KEY > largest key , follow the rightmost child pointer down
.If Ki ≤ KEY < Kj ,follow the child pointer between Ki and Kj
.If a leaf is reached :
.Search KEY among the keys stored in that leaf
.Linear search or binary search
.If found , return the corresponding record ; otherwise report not found.
INSERTION INTO A B+
TREE
In order to insert a key into a B+
tree ,first a B+
tree search is performed to find the correct location for
the key . Actually , the procedure to insert a new key value into a B+
- Tree is almost as for B- Tree .
The sequence of steps required to insert a node in a B+ Tree are as follows :
1. The search operation is used to find the leaf node in which the key value of the node has to be
inserted.
2. If the key value already exist in a leaf node , no more insertion is needed . Else if the said key value
does not exist , insert the value in the leaf node in an ordered fashion.
3. When a node is split , the middle key is retained in the left half-node as well as being promoted to
the father.
DELETION FROM A B+ TREE
The sequence of steps required to delete a key value from the B+ Tree is as follows :
1. Search the B+ Tree for the key value.
2. If the key value is in the B+ Tree , remove it from the tree as that of B Tree .
105. TREE EXTENDED
3. When a key value is deleted from a leaf there is no need to delete that key from the index set of
the key. That key value still can direct searches to proper leaves , since it still a valid separator between
the keys in the nodes below .
COMPARISON BETWEEN B- TREE AND B+ TREE
B- TREE B+ TREE
1. Data pointers are stored in all nodes. 1. Data pointers are stored only in leaf nodes .
2. Search can end at any node. 2. Search always ends at leaf node.
3. No redundant keys. 3. Redundant keys may exist.
4. Slow sequential access. 4. Efficient sequential access.
5. Higher trees. 5. Flatter TREES. No data pointers in index set node.
106. GRAPH THEORY
Q1. WHAT IS GRAPH? WHAT ARE THE DIFFERENT MEMORY REPRESENTATIONS OF IT?
A graph G (V, E) is a pair of sets V and E, where V is the finite set of vertices or nodes or points together
with a set of unordered pairs of these vertices for an undirected graph and ordered pairs for a directed
graph and E is the finite set of edges.
The different memory representations of a graph are-
Adjacency Matrix Representation:
A square matrix n*n, where n is the number of vertices that is used to represent the adjacency
relation of the vertices in a graph is known as adjacency matrix representation. In case of directed
graph, A[i,j]= 1 if there is an edge from vertex i to j, otherwise 0 and in case of undirected graph
A[i,j]=1 if there exist an edge between i to j.
Ex1:
Ex2:
Incident Matrix Representation:
A square matrix n*m, where n is the number of vertices and m is the number of edges that is used to
represent the direction or incidence to from relation of the edges in a graph is known as incidence
matrix representation.
A[i,j]=1 if there is an outgoing edge j from vertex i, and A[i,j]=-1 if if there is an incoming edge j to
vertex i.
107. Ex:
Adjacency List Representation:
A linked list representation of the list of adjacent vertices of a vertex is known as the Adjacency List
Representation.
Ex:
Q2. WHAT IS SPANNING TREE OF A GRAPH? WHAT DOU YOU MEAN BY MINIMUM SPANNING TREE?
A spanning tree of a graph G (V,E) is a sub-graph of G let G1(V1,E1), which has all the set of vertices
covered with minimum number of possible edges. Hence a spanning tree does not have any cycle and
cannot be disconnected.
A spanning tree (as there could be more than one spanning trees) is said to be the minimum spanning tree of
a graph, if it is having the minimum possible total edge weight among the other spanning trees.
108. Q3. EXPLAIN THE KRUSKALS ALGORITHM TO FIND THE MINIMUM SPANNING TREE OF A GRAPH.
Kruskal's algorithm:
Step1: sort the edges of G in increasing order by weight
Step2: keep a subgraph S of G, initially empty
Step3: for each edge e in sorted order until n-1 no. of edges are encountered
if the endpoints of e are disconnected in S
add e to S
Step4: return S
Example:
Time complexity: O(E logV)
109. Q4. EXPLAIN THE PRIMS ALGORITHM TO FIND THE MINIMUM SPANNING TREE OF A GRAPH.
Prims Algorithm:
Step1: Construct a matrix of order n*n where n is the no. of vertices and assign the weight of the edges in
the respective cells.
Step2: keep a subgraph S of G, initially empty
Step3: for each edge e in the matrix until n-1 no. of edges are encountered
Step4: Select the next minimum cost edge from the rows of the already selected vertices
if the endpoints of e are disconnected in S
then add it to S.
Step4: Return S.
Example:
Time Complexity: O((V+E)log V)
110. Q5. WHAT IS GRAPH TRAVERSAL? DEFINE THE DIFFERENT GRAPH TRAVERSAL TECHNIQUES.
Graph traversal means visiting of every vertex and edges of a graph exactly once in a well defined order.
The order in which the vertices are visited is important and may depend upon the algorithm being used.
The general ways of traversing a graph are-
Breadth First Search:
In BFS we start traversing from a selected node and traverse the graph layer-wise or breadth-wise
thus exploring the neighboring nodes.
Mechanism:
BFS Algorithm:
Step1: Set the status of all the nodes to 1.
Step 2: Insert the source node in the rear of the queue and change the status to 2.
Step3: Repeat step 4 to 5 until the queue is empty
Step4: Retrieve the node from the front of the queue and change its status to 3
Step 5: Insert all the neighbors having status 1 into the rear of the queue and change their status
to 2.
Example:
111. S1: Adjacency list
S: 1,2 1: 3,4,5 2:6 6:7
S2: Queue status & Output
S 1 2 3 4 5 6 7
BFS O/P: s,1, 2,3,4,5,6,7
Depth First Search:
In DFS we start traversing from a selected node and traverse the graph depth-wise or height-wise
thus exploring all the children nodes of the source node.
Mechanism:
Algorithm:
Step1: Set the status of all the nodes to 1.
Step 2: Insert the source node in the top of the stack and change the status to 2.
Step3: Repeat step 4 to 5 until the stack is empty
Step4: Retrieve the node from the top of the stack and change its status to 3
Step 5: Insert all the neighbors having status 1 into the top of the stack and change their status to
2.
Example:
112. S1: Adjacency list
S: 1, 2 1: 3, 4, 5 2:6 6:7
S2: Queue status & Output
S 1 2 6 7 3 4 5
DFS O/P: s, 2, 6, 7, 1, 3, 4, 5
Q6. EXPLAIN THE DIJKSTRAS ALGORITHM TO FIND THE SHORTEST PATH FROM THE SOURCE TO
DESTINATION.
Algorithm:
Step1: Initialize the cost of the source vertex by 0 and every other vertex to infinity.
Step2: Initialize the S, n*2 matrix by 0.
Step3: Repeat Step 3 to
Step4: Select the next min cost vertex.
Step5:
Update the cost of each vertex by min {previous cost, cost of selected vertex + cost from selected vertex}
If updated, store the updated value and the parent vertex in S.
Step6: Determine the change values and their parent from S and put it in matrix P traversing backward from
the goal state to source vertex.
Step7: Return the matrix P.
Example:
3
4 6
2 6 8
9
1 12
Source Vertex: A
Destination Vertex: F
B D
C E
FA
113. VS A B C D E F
0 ∞ ∞ ∞ ∞ ∞
A 0 4A 1A ∞ ∞ ∞
C 0 3C 1A 7C 13C ∞
B 0 3C 1A 6B 13C ∞
D 0 3C 1A 6B 13C 12D
Therefore the Shortest Path:
F D B C A
12D 6B 3C 1A 0
A->C->B->D->F