Data Structures and Algorithms For GATE Sample PDF
Data Structures and Algorithms For GATE Sample PDF
AND
Copyright by
All rights reserved.
Designed by
Acknowledgements
I would like to express my gratitude to many people who saw me through this book, to all those who provided
support, talked things over, read, wrote, offered comments, allowed me to quote their remarks and assisted in
the editing, proofreading and design. In particular, I would like to thank the following individuals.
[
.
[
],
[
spending their valuable time in reviewing the book, suggestions and encouragement.
&
[Founders of
at their training centers.
] for
,
and
for your help and suggestions.
of
,
],
[
[
],
my family during our studies.
[
,
of
],
],
]&
M-Tech,
Founder of
A stone is broken by the last stroke. This does not mean that first stroke was useless.
Success is a result of continuous daily effort. -Stand up, be bold, be strong. Take the whole responsibility on your own shoulders,
and know that you are the creator of your own destiny. --
Preface
Dear Reader,
Please Hold on! I know many people do not read preface. But I would like to strongly recommend reading
preface of this book at least. This preface has
from regular prefaces.
This book assumes you have some basic knowledge about computer science. Main objective of the book is not to
give you the theorems and proofs about
and
. I have followed a pattern of
improving the problem solutions with different complexities (for each problem, you observe multiple solutions
with different improved complexities). Basically, its an enumeration of possible solutions. With this approach,
even if we get a new question it gives us a way to think about all possible solutions. For all other topics, it will
act as a refreshment. This book is very much useful for interview preparation, competitive exams preparation,
campus preparations.
This book is aimed for GATE students. We have tried to solve all problems related to
and
from the last twenty years papers. Each solution has explanation associated with it and this gives
the confidence for readers about the correctness of the solutions. As a
if you read complete book
with good understanding, I am sure you will challenge the interviewers and that is the objective of this book.
This book is very much useful for the
of
and
during their academic
preparations. All the chapters of this book contain theory and their related problems as many as possible. If you
read as a
preparing for competition exams for Computer Science/Information Technology], the content
of this book covers
the
topics in full details. While writing the book, an intense care has been
taken to help students who are preparing for these kinds of exams.
In all the chapters you will see more importance given to
and analyzing them instead of
concentrating more on theory. For each chapter, first you will see the basic required theory and then followed
by problems.
For many of the problems,
solutions are provided with different complexities. We start with
solution and slowly move towards the
possible for that problem. For each problem
we will try to understand how much time the algorithm is taking and how much memory the algorithm is
taking.
It is
that, at least one complete reading of this book is required to get full understanding of all
the topics. In the subsequent readings, you can directly go to any chapter and refer. Even though, enough
readings were given for correcting the errors, due to human tendency there could be some minor typos in the
book. If any such typos found, they will be updated at
. I request you to constantly
monitor this site for any corrections, new problems and solutions. Also, please provide your valuable
suggestions at:
.
Wish you all the best. Have a nice reading.
M-Tech,
Founder of
Foreword
With the availability of different books on Data Structures and/or Algorithms, their design and analysis with a
general or language based orientation; one would be in gross error to think that this book is one more to the list.
Keeping in view the GATE and other competitive exams perspective in mind and critical time management
requirement, the author has taken the approach of embedding theoretical concepts through efficient problem
solving.
The different topics related to data structures and algorithms and their intricate interdependency have been
dealt with comprehensive eloquence and subtle clarity.
The topics coverage in the book spans from primitive to advanced data structures, their characteristics, their
space and time complexity analysis, the different algorithmic paradigms/classifications, application areas and
problems and their analysis.
Each topic is explained through a problem solving approach so that at the end, the reader is well equipped to be
able to apply to any type of problem solving requirement and distinctly choose one strategy or type from the
other.
The book also includes solved GATE questions of last twenty years which works as a mock exam practice plane
for the reader. It is a very handy and must have book for any reader aiming for competitive exams of all
universities and boards and as well as for campus recruitment. It can also serve as a reference text-book for
software developers, who wanted to design and implement efficient algorithms.
,
.
Table of Contents
1. Programming Basics ---------------------------------------------------------------------- 9
2. Introduction ----------------------------------------------------------------------------- 30
3. Recursion and Backtracking ------------------------------------------------------------ 52
4. Linked Lists ----------------------------------------------------------------------------- 57
5. Stacks ------------------------------------------------------------------------------------ 93
6. Queues---------------------------------------------------------------------------------- 113
7. Trees ------------------------------------------------------------------------------------ 123
8. Priority Queue and Heaps ------------------------------------------------------------- 193
9. Disjoint Sets ADT ---------------------------------------------------------------------- 211
10. Graph Algorithms ---------------------------------------------------------------------- 220
11. Sorting ---------------------------------------------------------------------------------- 259
12. Searching ------------------------------------------------------------------------------- 280
13. Selection Algorithms ------------------------------------------------------------------- 304
14. Symbol Tables -------------------------------------------------------------------------- 311
15. Hashing --------------------------------------------------------------------------------- 313
16. String Algorithms ---------------------------------------------------------------------- 329
17. Algorithms Design Techniques -------------------------------------------------------- 350
18. Greedy Algorithms --------------------------------------------------------------------- 353
19. Divide and Conquer Algorithms ------------------------------------------------------ 363
20. Dynamic Programming ---------------------------------------------------------------- 377
21. Complexity Classes --------------------------------------------------------------------- 415
22. Miscellaneous Concepts --------------------------------------------------------------- 422
Other Titles by
Success keys for Big Job Hunters
PROGRAMMING BASICS
Programming Basics
Chapter-1
The objective of this chapter is to explain the importance of analysis of algorithms, their notations, relationships and
solving as many problems as possible. We first concentrate on understanding the basic elements of algorithms,
importance of analysis and then slowly move towards analyzing the algorithms with different notations and finally the
problems. After completion of this chapter you should be able to find the complexity of any given algorithm
(especially recursive functions).
1.1 Variables
Before going to the definition of variables, let us relate them to old mathematical equations. All of us have solved
many mathematical equations since childhood. As an example, consider the below equation:
We dont have to worry about the use of above equation. The important thing that we need to understand is, the
equation has some names ( and ) which hold values (data). That means, the
( and ) are the place holders
for representing data. Similarly, in computer science we need something for holding data and
are the
facility for doing that.
1.1 Variables
to +
(-
to
(-
Programming Basics
-1). If it takes, bytes (
bits), then the possible values are
-1). Same is the case with remaining data types too.
char data;
};
10
Programming Basics
Memory Value
0
1
2
Memory Value
...
First lets understand the way memory is organized in a computer. We can treat the memory as an array of bytes. Each
location is identified by an address (index to array). In general, the address is not a valid memory location. It is
important to understand that the address of any byte (location) in memory is an integer. In the below diagram value
depends on the main memory size of the system.
To read or write any location, CPU accesses it by sending its address to the memory controller. When we create a
variable (for example, in :
), the compiler allocates a block of contiguous memory locations and its size depends
on the size of the variable. The compiler also keeps an internal tag that associates the variable name with the address
of the first byte allocated to it (sometimes called as
). So when we want to access that variable like this:
, the compiler knows where that variable is located and it writes the value .
Address
Memory Value
0
1
2
2000
Memory Value
X
...
Size of a Variable:
operator is used to find size of the variable (how much memory a variable occupies). For
example, on some computers,
( ) gives the value . This means an integer needs contiguous bytes in memory.
If the address of would be
, then the actual memory locations used by are:
and
.
Address of a Variable: In language, we can get the address of a variable using
operator ( ). The below
code prints the address of variable. In general, addresses are printed in hexadecimal as they are compact and also
easy to understand if the addresses are big.
Address
&XAddress of X
is 2000
0
1
2
2000
Memory Value
Memory Value
...
int X;
printf("The address is: %u\n", &X);
11
Programming Basics
1.6 Pointers
Pointers are also variables which can hold the address of another variable.
Declaration of Pointers: To declare a pointer, we have to specify the type of the variable it will point to. That means
we need to specify the type of the variable whose address its going to hold. The declaration is very simple. Let us see
some examples of pointer declarations below:
int *ptr1;
float *ptr2;
unsigned int *ptr3;
char *ptr4; void *ptr5;
Here
is a pointer that can point to an
variable,
can point to a
,
to an
, and
to a
. Finally
is a pointer that can point to anything. These pointers are called
pointers, and there are
some restrictions on what we can do with void pointers.
Pointers Usage: As we said, pointers hold addresses. That means, we can assign the address of a variable to it. Let us
consider the below sample code:
int X = 10;
int *ptr = &X;
Here, we first declare an integer named and initialize it to the value . Then we create a pointer to
named
and assign the address of to it. This is called,
. A common operation we can do
with a pointer is what is called
and it is a way to access the contents of the memory that it points to. The
indirection operator is represented by the asterisk symbol. Do not confuse this operator with the use of the same
asterisk symbol in the declaration of pointers, they are not the same thing.
Address
&ptrAddress
ptr is 2
of
Memory Value
Memory Value
1
2
ptr
2000
&XAddress of X
is 2000
2000
Lets see a
1.6 Pointers
12
Programming Basics
holds the address of , and changing the contents of the memory at that address changes the value
One limitation of
pointers, i.e. pointers that can point to any type, is that they cannot be
. This is
because of the fact that each variable type takes different amount of memory. On a
-bit computer for example
usually an int needs bytes, while a short bytes. So in order to read the actual value stored there, the compiler has to
know how many consecutive memory locations to read in order to get the full value.
Pointer Manipulation: Another very useful thing we can do with pointers is to perform arithmetic operations on them.
This might be obvious to the careful reader, since we said that pointers are just integers. However, there are a few
small differences on pointer arithmetic that make their use even more intuitive and easy. Try the following code:
char *cptr = (char*)2;
printf("cptr before: %p ", cptr);
cptr++;
printf("and after: %p\n", cptr);
We declare a pointer named
and assign the address to it. We print the contents of the pointer (i.e. the address
), increment it, and print again. Sure enough the first time it prints and then , and that was exactly what we
expected. However try this one as well:
int *iptr = (int*)2;
printf("iptr before: %p ", iptr);
iptr++;
printf("and after: %p\n", iptr);
Now the output, on my computer, is
before: and after: Why does this pointer point to the address 6 after
incremented it by one and not to as the previous pointer? The answer lies with what we said about the
variables. An int is bytes on my computer. This means that if we have an int at the address , then that int occupies
the memory locations
and . So in order to access to the next int we have to look at the address
and .
Thus when we add one to a pointer, it is not the same as adding one to any integer, it means give me a pointer to the
next variable which for variables of type int, in this case, is bytes ahead.
The reason that in the first example with the char pointer, the actual address after incrementing, was one more than
the previous address is because the size of char is exactly . So the next char can indeed be found on the next address.
Another limitation of void pointers is that we cannot perform arithmetic on them, since the compiler cannot know
how many bytes ahead is the next variable located. So void pointers can only be used to keep addresses that we have to
convert later on to a specific pointer type, before using them.
Arrays and Pointers: There is a strong connection between arrays and pointers. So strong in fact, that most of the time
we can treat them as the same thing. The name of an array can be considered just as a pointer to the beginning of a
memory block as big as the array. So for example, making a pointer point to the beginning of an array is done in
exactly the same way as assigning the contents of a pointer to another:
short *ptr;
short array[10];
ptr = array;
and then we can access the contents of the array through the pointer as if the pointer itself was that array. For
example this:
is perfectly legal. Furthermore, we can treat the array itself as a pointer, for example,
is equivalent to
In general
is equivalent to
.
The only difference between an array, and a pointer to the beginning of an array, is that the compiler keeps some extra
information for the arrays, to keep track of their storage requirements. For example if we get the size of both an array
and a pointer using the
operator, sizeof(ptr) will give us how much space does the pointer itself occupies ( on
my computer), while sizeof array will give us, the amount of space occupied by the whole array (on my computer
elements of bytes each).
1.6 Pointers
13
Programming Basics
Dynamic Memory Allocation: In the earlier sections, we have seen that pointers can hold addressed of another
variables. There is another use of pointers: pointers can hold addresses of memory locations that do not have a specific
compile-time variable name, but are allocated dynamically while the program runs (sometimes such memory is called
).
To allocate memory during runtime, language provides us the facility interns of
function. This function
allocates the requested amount of memory, and returns a pointer to that memory. To deallocate that block of memory,
supports it by providing
function. This function takes the pointer as an argument. For example, in the below
code, an array of 5 integers is allocated dynamically, and then deleted.
int count = 5;
int *A = malloc(count * sizeof(int));
free(arr);
In this example, the
calculates the amount of bytes we need to allocate for the array, by
multiplying the number of elements, to the size of each element (i.e. the size of one integer).
Function Pointers: Like data, executable code (including functions) also stored in memory. We can get the address of a
function. But the question is what type of pointers we use for that purpose?
In general, we use function pointers and they store the address of functions. Using function pointers we can call the
function indirectly. But, function pointers manipulation has limitation: limited to assignment and indirection and
cannot do arithmetic on function pointers. Because for function pointers there no ordering (functions can be stored
anywhere in memory). The following example illustrates how to create and use function pointers.
int (*fptr)(int);
fptr = function1;
printf("function1of 0 is: %d\n", fptr(5));
fptr = function2;
printf("function2 of 0 is: %d\n", fptr(10));
First we create a pointer that can point to functions accepting an
as an argument and returning int, named
.
Then we make
point to the
, and proceed to call it through the
pointer, to print the
of
. Finally, we change
to point to
, and call it again in exactly the same manner, to print the
of .
14
Programming Basics
Semantics of Parameter Passing: Logically, parameter passing uses the following semantics:
IN: Passes info from caller to
. Formal arguments can take values from actual arguments, but cannot
send values to actual arguments.
OUT: Callee writes values in the caller. Formal arguments can send values from actual arguments, but cannot
take values from actual arguments.
IN/OUT: Caller tells callee value of variable, which may be updated by callee. Formal arguments can send
values from actual arguments, and also can take values from actual arguments.
Language Support for Parameter Passing Techniques
Passing Technique
Pass by value
Pass by result
Pass by value-result
Pass by reference
Pass by name
Supported by Languages
, sometimes
(achieves through pointers),
Pass by Value: This method uses in-mode semantics. A formal parameter is like a new local variable that exists within
the scope of the procedure/function/subprogram. Value of actual parameter is used to initialize the formal parameter.
Changes made to formal parameter
get transmitted back to the caller. If pass by value is used then the formal
parameters will be allocated on stack like a normal local variable. This method is sometimes called as
.
Advantage of this method is that, it allows the actual arguments not to modify.
In general the pass by value technique is implemented by copy and it has the following disadvantages:
Inefficiency in storage allocation
Inefficiency in copying value
For objects and arrays, the copy semantics are costly
Example: In the following example, main passes func two values: and . The function func receives copies of these
values and accesses them by the identifiers a and b. The function func changes the value of a. When control passes
back to main, the actual values of and are not changed.
void func (int a, int b) {
a += b;
printf("In func, a = %d b = %d\n", a, b);
}
int main(void) {
int x = 5, y = 7;
func(x, y);
printf("In main, x = %d y = %d\n", x, y);
return 0;
}
The output of the program is: In func, a = 12 b = 7. In main, x = 5 y = 7
Pass by Result: This method uses out-mode semantics. A formal parameter is a new local variable that exists within the
scope of the function. No value is transmitted from actual arguments to formal arguments. Just before control is
transferred back to the caller, the value of the formal parameter is transmitted back to the actual parameter. This
method is sometimes called as
Actual parameter
be a variable.
and
or
Parameter collisions can occur: That means, suppose let us assume that there is a function
If the two
formal parameters in write had different names, which value should go into ? Order in which actual parameters are
copied determines their value. In general the pass by result technique is implemented by copy and it has the following
disadvantages:
15