BSC 3rdsem Course6 DS Using C
BSC 3rdsem Course6 DS Using C
UNIT-1
Introduction to Data Structures, Arrays
UNIT-2
Linked Lists
UNIT 3
Stacks & Queues
UNIT 4
Searching & Sorting
UNIT 5
Trees & Graphs
Model Paper 1 - 89
Model Paper 2 - 90
UNIT 1
Introduction to Data Structures, Arrays
List ADT
Set ADT
Stack ADT
Queue ADT
The most significant difference between a data type and a data structure is that a data type is the
representation of nature and type of data, whereas a data structure is a collection that holds different types
of data which can be manipulated and used in programming in an efficient manner.
The following are some important differences between Data type & Data structure:
A data type represents the nature and Data structure is the collection that holds
type of data. All the data that belong data which can be manipulated and used in
to a common data type share some programming so that operations and
Definition common properties. algorithms can be more easily applied.
For example an integer data type For example, tree type data structures often
describes every integer that the allow for efficient searching algorithms.
computers can handle.
Data types don't store the value of Data structures hold the data along with
data. their values.
Storage
They represent only the type of data Data structures can hold different types of
that is stored. data within one single object.
Data types represent the type of value In case of data structures, the data is
that can be stored, so values can assigned using some set of algorithms and
Assignment
directly be assigned to the data type operations like push, pop, enqueue,
variables. dequeue etc.
Examples int, float, char, boolean etc. Stack, Queue, Tree, Graph etc.
03. What are the different types of data structures? [or] Explain about primitive, non-
primitive, linear & non-linear data structures.
Data Structures:
A data structure is a particular way of organizing data in a computer so that it can be used
efficiently.
For example, we can store a list of items having the same data-type using an array.
Below is the Array data structure.
Data structure is about providing data elements in terms of some relationship for better organization.
Data structure is just a container for the data that is used to store, manipulate and arrange. It can be
processed by algorithms.
For example, while using a shopping website like Flipkart or Amazon, the users know their last orders and
can track them. The orders are stored in a database as records.
When the program needs them so that it can display it to the user, it loads the data in some form of data
structure.
Primitive data types are the data types available in most of the programming languages.
These data types are used to represent single value.
It is a basic data type available in most of the programming language.
Types Description
Arrays Array is a collection of elements. It is used in mathematical problems like matrix,
algebra etc. each element of an array is referenced by a subscripted variable or
value, called subscript or index enclosed in parenthesis.
Linked Linked list is a collection of data elements. It consists of two parts: Info and Link.
list Info gives information and Link is an address of next node. Linked list can be
implemented by using pointers.
Stack Stack is a list of elements. In stack, an element may be inserted or deleted at one
end which is known as Top of the stack. It performs two operations: Push and
Pop. Push means adding an element in stack and Pop means removing an element
in stack. It is also called Last-in-First-out (LIFO).
Queue Queue is a linear list of element. In queue, elements are added at one end called
rear and the existing elements are deleted from other end called front. It is also
called as First-in-First-out (FIFO).
Type Description
Tree Tree is a flexible, versatile and powerful non-linear data structure. It is used to
represent data items processing hierarchical relationship between the grandfather
and his children & grandchildren. It is an ideal data structure for representing
hierarchical data.
Graph Graph is a non-linear data structure which consists of a finite set of ordered pairs
called edges. Graph is a set of elements connected by edges. Each elements are
called a vertex and node.
Algorithm:
Algorithm refers to the sequence of instructions that must be followed to solve a problem.
It is a logical representation of the instructions which should be executed to perform a task.
An algorithm has some characteristics. These are follows;
Each instruction should be unique.
Each instruction should be relative in nature & should not be repeated infinitely.
Repetition of same task should be avoided.
The result should be available to the user after the algorithm terminates.
After an algorithm has been designed, its efficiency must be analysed.
This involves determining whether the algorithm is economical in the use of computer resources :
CPU time & Memory.
Memory space is the memory required by an algorithm.
Running time is the computational time required to execute the algorithm.
Characteristics of an Algorithm:
Complexity is a characterization of the time or space requirements for solving a problem by a particular
algorithm.
These requirements are expressed in terms of a single parameter that represents the size of the problem.
The analysis of the program requires two main considerations:
Time complexity
Space complexity
The time complexity is the amount of computer time that needs to execute the program.
The space complexity is the amount of memory needs to execute the program.
Time Complexity:
While measuring the time complexity of an algorithm, we concentrate on developing only the frequency
count for all basic instructions of an algorithm.
This is because, it is often difficult to get reliable timing figure because of clock limitations and the
multiprogramming or the sharing environment.
You are given an array A and an integer x and you have to find if x exists in array A. Simple solution to
this problem is traverse the whole array A and check if the any element is equal to x.
for i : 1 to length of A
if A[i] is equal to x
return TRUE
return FALSE
Each of the operation in computer take approximately constant time. Let each operation takes c time. The
number of lines of code executed is actually depends on the value of x. During analysis of algorithm,
mostly we will consider worst case scenario, i.e., when x is not present in the array A. In the worst case,
the if condition will run N times where N is the length of the array A. So in the worst case, total execution
time will be (N*c + c). N*c for the if condition and c for the return statement.
Space Complexity:
The space complexity of an algorithm or a computer program is the amount of memory space required to
solve an instance of the computational problem.
It is the memory required by an algorithm until it executes completely.
The space needed by the program is the sum of the following components.
Fixed Space Requirement: This includes the instruction space, for simple variables, fixed size structured
variables, and constants.
Variable Space Requirement: This consists of space needed by structured variables whose size depends
on particular instance of variables. It also includes the additional space required when the function uses
recursion.
If the complexity of any algorithm is O(1), it means that the computing time of the algorithm is
constant.
If the complexity of any algorithm is O(n), it is called linear time which implies that it is directly
proportional to n.
If the complexity of any algorithm is O(n2), it is called quadratic time.
If the complexity of any algorithm is O(n3), it is called cubic time.
If the complexity of any algorithm is O(2 n), it is called exponential time.
If the complexity of any algorithm is O(log n) or O(n log n), these are called logarithmic times.
The common computing times of algorithms in the order of performance are as follows:
O(1)
O(log n)
O(n)
O(n log n)
O(n2)
O(n3)
O(2n)
Arrays:
Array is a container which can hold a fixed number of items and these items should be of the same
type. Most of the data structures make use of arrays to implement their algorithms. Following are
the important terms to understand the concept of Array.
Element : Each item stored in an array is called an element.
Index : Each location of an element in the array has a numerical index, which is
used to identify the element.
Array Representation:
Basic Operations
Traverse operation:
Algorithm:
Let LA be a Linear Array (unordered) with N elements & I is a positive integer with initial value 0.
Following is the algorithm to display all the elements in the list:
1. Start
2. Repeat step 3 & step 4 until I<N.
3. display LA[I].
4. SET I = I+1.
5 Stop
Insertion operation:
Insert operation is used to insert one or more data elements into an array.
Based on the requirement, a new element can be added at the beginning, end, or at any given
index of array.
Algorithm:
Let LA be a Linear Array (unordered) with N elements and K is a positive integer such that K<N.
Following is the algorithm where ITEM is inserted at index K of LA:
1. Start
2. Set J = N-1
3. Set N = N+1
4. Repeat steps 5 and 6 while J >= K
5. Set LA[J+1] = LA[J]
6. Set J = J-1
7. Set LA[K] = ITEM
8. Stop
Deletion Operation
Deletion refers to removing an existing element from the array and re-organizing all elements of
an array.
Algorithm:
Consider LA is a linear array with N elements and K is a positive integer such that K<N. Following
is the algorithm to delete an element available at index K of LA.
1. Start
2. Set J = K
3. Repeat steps 4 and 5 while J < N-1
4. Set LA[J] = LA[J + 1]
5. Set J = J+1
6. Set N = N-1
7. Stop
Search Operation
You can perform a search for an array element based on its value or its index.
Algorithm
Consider LA is a linear array with N elements. Following is the algorithm to find an element with a
value of ITEM using sequential search.
1. Start
2. Set J = 0
3. Repeat steps 4 and 5 while J < N
4. IF LA[J] is equal ITEM THEN GOTO STEP 6
5. Set J = J +1
6. PRINT J, ITEM
7. Stop
Update Operation
Update operation refers to updating an existing element from the array at a given index.
Algorithm
Consider LA is a linear array with N elements and K is a positive integer such that K<N. Following
is the algorithm to update an element available at the K th position of LA.
1. Start
2. Set LA[K-1] = ITEM
3. Stop
Types of Arrays:
Based on the number of indexes to retrieve an element from an array, we can classify Arrays into
two types:
One dimensional Array (1D Array)
Multi dimensional Array.
If only one subscript (or) index is needed to reference all the elements in the array, then the array
is called ‘1D Array’.
Memory allocation of 1D array is very simple. Suppose, an array A[50] is stored in the memory as
shown below.
If each element requires one word in the memory, then the location for any element A[i] in the
array can be obtained at address M+(i-1).
In general, an array can be written as A[L……U]. Here L is the lower index & U is the upper index.
If the array is stored starting from the memory location M and for each element it requires W
number of words, then the address for the element A[i] will be M+(i-L)*W
The above formula is know as indexing formula, which is used to map the logical representation of
an array to physical representation.
Two-dimensional arrays are the collection of homogeneous elements, where the elements are
ordered in number of rows & columns.
Example: m x n matrix, where m denotes the number of rows & n denotes the number of columns.
. . . ……………….. .
. . . ……………….. .
. . . ……………….. .
The subscript of an array element aij represents the ith row & jth column.
Like 1D arrays, matrices are also stored in contiguous memory locations. The elements of a matrix are stored on a
row by row.
a11 1
a12 2
a13 3
a21 4
a22 5
a23 6
a31 7
a32 8
a33 9
Sparse matrix is a matrix with the majority of its elements equal to zero.
If the majority elements are non-zero elements, then it is called dense matrix.
The below program checks whether given matrix is sparse matrix or not & prints number of zeroes in it.
#include<stdio.h>
void main(){
int a[10][10], i, j, m, n, count=0;
printf("Enter size of matrix...");
scanf("%d %d",&m,&n);
printf("Enter elements of the matrix...");
for(i=0;i<m;i++)
for(j=0;j<n;j++){
scanf("%d",&a[i][j]);
if(a[i][j]==0) count++;
}
if (count>(m*n)/2) printf(" Given matrix is Sparse Matrix...");
else printf("Given matrix is not Sparse Matrix...");
printf(“There are %d number of zeroes”,count);
}
Output:
Enter size of matrix...
2 3
Enter elements of the matrix...
12 0 0
0 0 23
Given matrix is Sparse Matrix...
There are 6 number of zeroes
The concept of dynamic memory allocation in c language enables the C programmer to allocate memory at
runtime.
Dynamic memory allocation in c language is possible by 4 functions of stdlib.h header file.
malloc() - allocates single block of requested memory.
calloc() - allocates multiple block of requested memory.
realloc() - reallocates the memory occupied by malloc() or calloc() functions.
free() - frees the dynamically allocated memory.
Before learning above functions, let's understand the difference between static memory allocation and
dynamic memory allocation.
malloc() function in C
#include<stdio.h>
#include<stdlib.h>
void main(){
int n,i,*ptr,sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)malloc(n*sizeof(int)); //memory allocated using malloc
if(ptr==NULL){
printf("Sorry! unable to allocate memory");
exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i){
scanf("%d",ptr+i);
sum+=*(ptr+i);
}
printf("Sum=%d",sum);
free(ptr);
}
Output:
calloc() function in C
#include<stdio.h>
#include<stdlib.h>
void main(){
int n,i,*ptr,sum=0;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)calloc(n,sizeof(int)); //memory allocated using calloc
if(ptr==NULL)
{
printf("Sorry! unable to allocate memory");
exit(0);
}
printf("Enter elements of array: ");
for(i=0;i<n;++i)
{
scanf("%d",ptr+i);
sum+=*(ptr+i);
}
printf("Sum=%d",sum);
free(ptr);
}
Output:
Enter elements of array: 3
Enter elements of array: 10
10
10
Sum=30
realloc() function in C
If memory is not sufficient for malloc() or calloc(), you can reallocate the memory by realloc()
function. In short, it changes the memory size.
Syntax of realloc() function.
ptr=realloc(ptr, new-size)
free() function in C
The memory occupied by malloc() or calloc() functions must be released by calling free() function.
Otherwise, it will consume memory until program exit.
Syntax of free() function.
free(ptr)
UNIT 2
Linked Lists
Linked Lists:
Linked list is a linear data structure which consists of group of nodes in a sequence.
Each node has data & address of next node.
A node may have any number of data elements.
Linked lists are dynamic in nature which allocates the memory when required.
Insertion & deletion can be implemented easily using linked lists.
We don’t need to know the size of the list in advance.
Linked lists allow us to insert elements at the beginning (or) at the end of the list.
Linked lists are used to implement stacks, queues, trees, graphs etc.
A linked list is represented by a pointer to the first node of the linked list. The first node is
called the head. If the linked list is empty, then the value of the head is NULL.
struct node{
int data;
struct node *next;
};
struct node *head=NULL;
struct node *nn=NULL;
Here nn is new node. This will be created using malloc function as shown below.
nn = (struct node *)malloc(sizeof(struct node));
In a single linked list, each node contains only one link which points to the next node in the
list.
The below figure shows a single linked list with 5 nodes.
1. Static representation:
2. Dynamic representation:
Following are the different operations we can perform on a single linked list:
Traversing the list.
Inserting element into the list.
Delete a node from the list.
Searching for an element in the list.
Merging two linked lists.
While traversing a single linked list, we have to visit every node in the list, starting from the first
node to the last node.
Following is the Algorithm to visit all the nodes in the list:
The new node is always added before the head of the given Linked List.
Newly added node becomes the new head of the Linked List.
For example, if the given Linked List is 10 15 20 25 and we add an item 5 at the front, then
the Linked List becomes 5 10 15 20 25. Let us call the function that adds at the front of the
list is insert(). The insert() must receive a pointer to the head pointer, because push must change
the head pointer to point to the new node.
The new node is always added after the last node of the given Linked List.
For example if the given Linked List is 5 10 15 20 25 and we add an item 30 at the end,
then the Linked List becomes 5 10 15 20 25 30.
Since a Linked List is typically represented by the head of it, we have to traverse the list till end
and then change the next of last node to new node.
The next of new node will be NULL & next of last node will be new node.
To search for an element in the list, we have to traverse through the list starting from first node till
we found the searching element (or) till we reach the end of the list.
For example, if the key to be searched is 11 and linked list is 1421113010,
then the function should return true. If the key to be searched is 25, then the function should
return false.
Following is the code to search an element in the list:
Merging two linked lists is the process of creating link between the last node of first list & first node
of second list.
To do this, we need to traverse through all the nodes in the first list till we find last node.
Replace the NULL (which is at link part of last node) with HEAD of second list.
Following is the code to merge two linked lists:
In a single linked list, we can traverse from starting node to any other node in one direction only.
That’s why it is called one way list.
But, in Doubly Linked Lists, we can traverse through nodes in both directions, either from left to
right (or) right to left.
This can be done by maintain two links instead of one as in single linked list.
The structure of a node in doubly linked list is represented as shown below:
In a doubly linked list, The HEAD node contains NULL in it’s left pointer. The last node contains
NULL in it’s right pointer.
All the remaining nodes contain address of immediate predecessor in Left pointer & address of
immediate successor in Right pointer.
Like in Single Linked List, we can perform insertion in DLL in various cases.
The new node is always added before the HEAD of the given Linked List.
Newly added node becomes the new HEAD of DLL.
For example if the given Linked List is 10152025 and we add an item 5 at the front, then the
Linked List becomes 510152025.
Let us call the function that adds at the front of the list is insert().
The insert() must receive a pointer to the HEAD pointer.
The new node is always added after the last node of the given Linked List.
For example if the given Linked List is 10152025 and we add an item 5 at the end, then the
Linked List becomes 101520255.
To insert element after last node, we need to traverse the list till we find last node.
Traverse through the list until we find given node (Lets call it prev_node).
Put prev_nodenext in New_Nodenext.
Put prev_node in New_Nodeprev.
Put New_Node in prev_nodenext.
Put New_Node in prev_nodenextprev.
When we are deleting a node (let’s call it as del_node), we have to do some adjustments.
We need to change the immediate predecessornext to del_nodenext.
We need to change immediate successorprev to del_nodeprev.
Algorithm:
Example:
Circular Linked List is a variation of Linked list in which the first element points to the last element
and the last element points to the first element. Both Singly Linked List and Doubly Linked List can be
made into a circular linked list.
In singly linked list, the next pointer of the last node points to the first node.
In doubly linked list, the next pointer of the last node points to the first node and the previous pointer
of the first node points to the last node making the circular in both directions.
As per the above illustration, following are the important points to be considered.
- The last link's next points to the first link of the list in both single as well as doubly linked list.
- The first link's previous points to the last of the list in case of doubly linked list.
- Following are the important operations supported by a circular list.
insert − Inserts an element at the start of the list.
delete − Deletes an element from the start of the list.
display − Displays the list.
If proper care is not taken, it is possible to get trapped into an infinite loop.
This problem occurs, when we are unable to detect the end of the list while moving from one node to another
node.
Array elements can be stored in Linked list elements can be stored at any
03 consecutive memory locations. available place as address of node is
stored in previous node.
Insert and delete operation takes Insert and delete operation cannot take
04 more time in array. more time. It performs operation in fast
and in easy way.
Array elements cannot be added, The nodes in the linked list can be added
08
deleted once it is declared. and deleted from the list.
UNIT 3
Stacks & Queues
STACKS:
Stack is a data structure that allows adding and removing elements in a particular order.
Every time an element is added it goes on top of the stack.
The only element can be removed is the element at top of the stack.
Stacks are sometimes called as Last-In-First-Out (LIFO) lists i.e. the element which is inserted first
in the stack, will be deleted last from the stack.
When we want to push an element into the stack, check whether the stack is full (or) not. If not,
‘top’ value is incremented & the element is stored in that position.
When we want to pop an element from the stack, check whether the stack is empty (or) not. If not,
‘top’ value is decremented.
Features of stack:
Applications of Stack
Operations on Stack
Step 1: START
Step 2: if (top=n-1) then display “stack is full”
goto Step 4.
Step 3: top = top+1
stack(top) item
Step 4: STOP
Step 1: START
Step 2: if (top=-1) then display “stack is empty”
goto Step 4.
Step 3: display the removed item at stack(top).
top top-1
Step 4: STOP
The stack is called empty if it doesn't contain any element inside it. At this stage, the value of variable
top is -1.
Value of top will get increased by 1 every time when we add any element to the stack. In the following
stack, After adding three elements, top = 2.
-1 Empty
N stack overflow
Adding an element into the top of the stack is referred to as push operation. Push operation
involves following two steps.
Increment the variable Top so that it can now refer to the next memory location.
Add element at the position of incremented top. This is referred to as adding new element at
the top of the stack.
Stack is overflown when we try to insert an element into a completely filled stack, so our main
function must always avoid stack overflow condition.
Deletion of an element from the top of the stack is called pop operation.
The top most element of the stack is stored in an another variable and then the top is
decremented by 1.
The operation returns the deleted value that was stored in another variable.
The underflow condition occurs when we try to delete an element from an already empty stack.
Data Structures Using C | Sudheer Kumar Kasulanati
37
Instead of using array, we can also use linked list to implement stack.
Linked list allocates the memory dynamically.
However, time complexity in both the scenarios is same for all the operations i.e. push, pop
and peek.
In linked list implementation of stack, the nodes are maintained non-contiguously in the
memory.
Each node contains a pointer to its immediate successor node in the stack. Stack is said to be
overflown if the space left in the memory heap is not enough to create a node.
The last node in the stack always contains null in its address field.
Following are the operations performed on stack using linked list implementation.
Applications of Stack
Expression Evaluation:
Stack is used to evaluate prefix, postfix and infix expressions.
Expression Conversion:
An expression can be represented in prefix, postfix or infix notation. Stack can be used to convert
one form of expression to another.
Syntax Parsing:
Many compilers use a stack for parsing the syntax of expressions, program blocks etc. before
translating into low level code.
Backtracking:
Suppose we are finding a path for solving maze problem. We choose a path and after following it
we realize that it is wrong. Now we need to go back to the beginning of the path to start with new
path. This can be done with the help of stack.
Parenthesis Checking:
Stack is used to check the proper opening and closing of parenthesis.
String Reversal:
Stack is used to reverse a string. We push the characters of string one by one into stack and then
pop character from stack.
Function Call:
Stack is used to keep information about the active functions or sub routines.
04. Write about recursion. Write differences between Recursion & Iteration.
RECURSION:
Some computer programming languages allow a module or function to call itself. This technique is known
as recursion.
In recursion, a function α either calls itself directly or calls a function β that in turn calls the original
function α.
The function α is called recursive function.
int factorial(int n) {
if(n < = 1)
return 1;
else
return n*factorial(n-1);
}
void function1(){
// some code
function2();
// some code
}
void function2(){
// some code
function1();
// some code
}
Principles of Recursion:
Some basic principles which are used while designing algorithms with recursion are:
Find the key step: When beginning with the design of algorithms through recursion, one should try to
find out the ‘key step’ for the solution. Once you have executed the key step, find out whether the
remainder of the problem can be solved in the same way, and modify the step if necessary.
Find a stopping rule: The stopping rule indicates that the problem is done & execution of the algorithm
can be stopped.
Outline your algorithm: After determining the key step for the problem and finding the cases which are
to be handled, the next step is to combine these to using an ‘if’ statement to select between them. The
main program and the procedure for recursion are now to be written to carry the key step through until
the stopping rule applies.
Check termination: Care should be taken to ensure that recursion will always terminate after the finite
number of steps and the stopping rule should also be satisfied.
Recursion Iteration
Control
Function call stack. Looping Constructs (for, while etc.)
Structure
Problem-
Solving Divide and Conquer. Sequential Execution.
Approach
QUEUES:
Queue is a data structure that allows inserting elements from one end (REAR or tail) & deleting
elements from other end (FRONT or head).
Queue is a FIFO data structure, which means that the element inserted first will be removed first.
The process to add an element into queue is called ‘Enqueue’ and the process of removing the
element is called ‘Dequeue’.
When we want to add an element into the queue, we need to check whether the queue is full (or)
not. If the queue is not full, then ‘rear’ is incremented & element is stored in that position.
When we want to remove an element from the queue, we have to check whether the queue is
empty (or) not. If the queue is not empty, ‘front’ is incremented.
Operations on Queue:
Enqueue Operation:
Queues maintain two data pointers, front and rear. Therefore, its operations are
comparatively difficult to implement than that of stacks.
The following steps should be taken to enqueue (insert) data into a queue –
Step 1: START
Step 2: if queue is full display “overflow” goto step 5
Step 3: rear rear+1
Step 4: queue[rear] data
Step 5: STOP
Dequeue operation:
Accessing data from the queue is a process of two tasks − access the data where front is
pointing and remove the data after access.
The following steps are taken to perform dequeue operation:
Step 1 − Check if the queue is empty.
Step 2 − If the queue is empty, produce underflow error and exit.
Step 3 − If the queue is not empty, access the data where front is pointing.
Step 4 − Increment front pointer to point to the next available data element.
Step 5 − Return success.
Step 1: START
Step 2: if queue is empty display “underflow”
goto step 5
Step 3: return queue[front]
Step 4: front front+1
Step 5: STOP
Data Structures Using C | Sudheer Kumar Kasulanati
45
Enqueue: Addition of an element to the queue. Adding an element will be performed after
checking whether the queue is full or not.
If rear < n which indicates that the array is not full then store the element at A[rear] and
increment rear by 1 but if rear = n then it is said to be an Overflow condition as the array is
full.
Dequeue: Removal of an element from the queue. An element can only be deleted when there
is at least one element to delete i.e. rear > 0.
Now, element at A[front] will be deleted & front is incremented.
Display: Print all elements of the queue. If the queue is non-empty, traverse and print all the
elements from index front to rear-1.
Example:
Consider a queue, containing 6 elements as shown below.
Output:
90 33 18 85 98
90 33 18 85
The major problem with the queue implemented using an array is, It will work for an only fixed
number of data values.
That means, the amount of data must be specified at the beginning itself.
Queue using an array is not suitable when we don't know the size of data which we are going to
use.
A queue data structure can be implemented using a linked list data structure. The queue which is
implemented using a linked list can work for an unlimited number of values.
That means, queue using linked list can work for the variable size of data (No need to fix the size at
the beginning of the implementation).
The Queue implemented using linked list can organize as many data values as we want.
In linked list implementation of a queue, the last inserted node is always pointed by 'rear' and the
first node is always pointed by 'front'.
Example:
In above example, the last inserted node is 50 and it is pointed by 'rear' and the first inserted node
is 10 and it is pointed by 'front'.
The order of elements inserted is 10, 15, 22 and 50.
Step 1 - Create a newNode with given value & Check whether queue is Empty or Not.
Step 2 - If it is Empty then, set newnode → next = null,
front = newNode and rear = newNode.
Step 3 - If it is Not Empty then, set newnode → next = rear and rear = newNode
For example, if we add element 83 using Enqueue() operation, the above queue will be as shown
below:
For example, remove element 10 using Dequeue() operation, the above queue will be as
shown below:
We can use the following steps to display the elements (nodes) of a queue...
Circular queues:
Some times, Even if there are empty cells at the beginning of the array, we can’t insert a new item,
because rear reaches end of the array.
To avoid this problem, we use circular queues. In circular queues, front & rear wrap around to the
beginning of the array.
Circular Queue is a linear data structure in which the operations are performed based on FIFO
(First In First Out) principle and the last position is connected back to the first position to make a
circle. It is also called ‘Ring Buffer’.
As shown above, Rear reaches to the end of the array & Front reaches to index 2.
Using circular queue, we can insert element at index 0, even if ‘Rear’ reaches end.
Dequeue(): This function is used to delete an element from the circular queue. In a circular
queue, the element is always deleted from front position.
Steps:
Check whether queue is Empty means check (front==0 && rear==0).
If it is empty then display Queue is empty.
If queue is not empty then Check if (front==rear-1) if it is true then set front=rear= 0 else
check if (front==size-1), if it is true then set front=0.
Example: Assume that d is a deque, that has been created and is currently empty. Following table
shows the result of sequence of deque operations.
Data Structures Using C | Sudheer Kumar Kasulanati
50
Priority queues:
In priority queues, elements are inserted into the queue based on priority.
Whenever we are inserting new element, it is compared with all elements in the queue & will be
inserted at proper position.
In a priority queue, an element with highest priority is served before an element with low priority.
Example:
In the following example, elements are given priority based on ascending order (highest number
given more priority than lowest number).
UNIT 4
Searching & Sorting
Searching:
Algorithm:
Step 1: START
Step 2: declare variables i, n , x, A[]
Step 3: initialize i 0
Step 4: Repeat steps until (i < n)
if (A[i]=x){
display “Element found at index i”
goto Step 6
}
i i+1
Step 5: display “Element not found”
Step 6: STOP
#include<stdio.h>
void main(){
int i,n,x,a[10];
printf("Enter the Number of elements in the Array ");
scanf("%d",&n);
printf("Enter the elements in the Array");
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
printf("Enter the element to search");
scanf("%d",&x);
for(i=0;i<n;i++){
if(a[i]==x){
printf("Element found at index %d",i);
break;
}
}
if(i==n){
printf("Element not found ");
}
}
Output:
Binary Search:
Example:
Algorithm:
Step 1: START
Step 2: declare variables i, n , x, A[], first, last, middle
Step 3: initialize first 0, last n-1, middle (first+last)/2
Step 4: Repeat steps until (first<=last)
if (A[middle]=x){
display “Element found at index middle”
goto Step 6
}
else if(A[middle]<x) first middle+1
else if(A[middle]>x) last middle-1
middle (first+last)/2
Step 5: display “Element not found”
Step 6: STOP
#include<stdio.h>
void main() {
int c, first, last, middle, n, search, array[10];
printf("Enter number of elements");
scanf("%d",&n);
printf("Enter the elements");
for (c = 0; c < n; c++)
scanf("%d",&array[c]);
printf("Enter value to search");
scanf("%d",&search);
first = 0;
last = n - 1;
middle = (first + last)/2;
while( first <= last ){
if ( array[middle] == search ){
printf("Element found at index %d",middle);
break;
}
else if ( array[middle] < search ) first = middle + 1;
else last = middle - 1;
middle = (first + last)/2;
}
if ( first > last )
printf("Element not found");
}
Output:
Steps:
Example 1:
There are 9 elements, so divide the list into 3 groups of 3 elements each.
Starting indices of these 3 groups are 0, 3, 6. Create index array with these elements as shown below.
Now compare first element of the first group with search element. 12<28. Goto next group.
First element of the next group, 21<28. Goto next group.
First element of the next group, 57>28. So apply linear search in previous group.
21!=28, Goto next element 28=28. So display element found.
Example 2:
There are 9 elements, so divide the list into 3 groups of 3 elements each.
Starting indices of these 3 groups are 0, 3, 6. Create index array with these elements as shown below.
Now compare first element of the first group with search element. 12<19. Goto next group.
First element of the next group, 21>19. So apply linear search in previous group.
12!=19, Goto next element 15!=19. Goto next element 17!=19. So display element not found.
Bubble Sort:
Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they
are in wrong order.
It is called bubble sort because the larger element bubbles up towards the last place.
After each iteration, one element will be sorted.
Example:
In the above example, After first iteration, the largest element 6 is placed in the last position.
After second iteration, the largest element in the remaining list 5 is placed before 6.
This process continues until all the elements are placed in their correct positions.
Algorithm:
Step 1: START
Step 2: declare variables i, j, temp, A[]
Step 3: initialize values i4, j0
Step 4: Read 5 elements from the user
Step 5: Repeat until (i>0)
Repeat until (j<i)
if (A[j]>A[j+1]) swap A[j] and A[j+1]
jj+1
ii-1
Step 6: display sorted elements
Step 7: STOP
#include<stdio.h>
void main(){
int i, j,temp;
int A[5];
printf("Enter any 5 elements to sort\n");
// To read elements
for(i=0;i<5;i++)
scanf("%d",&A[i]);
// Bubble sort logic
for (i=4;i>0;i--)
for (j=0;j<i;j++)
if (A[j]>A[j+1]){
temp=A[j];
A[j]=A[j+1];
A[j+1]=temp;
}
// To display sorted elements
printf("\nElements after sorting\n");
for(j=0;j<5;j++)
printf("%d ",A[j]);
}
Output:
Enter any 5 elements to sort
34 51 20 15 37
Elements after sorting
15 20 34 37 51
Insertion Sort:
Insertion sort is a sorting algorithm which sorts the elements in the list by shifting them one by one.
In Insertion sort, a group of items is partially sorted at any given point of time, where as in Bubble sort &
Selection sort, a group of items is fully sorted at any given point of time.
In Insertion sort algorithm, we pick a key element, compare it with the elements before it & insert the key in
the right place.
If there are N number of elements, After N-1 steps we will find the sorted list.
Example:
In the above example, we have 6 elements in the list. So will get the sorted list in 5 steps.
Algorithm:
Step 1:
START
Step 2:
declare variables i, j, temp, A[]
Step 3:
initialize values i1, ji-1
Step 4:
Read 5 elements from the user
Step 5:
Repeat until (i<5)
tempA[i]
Repeat until (j>=0)
if (A[j]>=temp) A[j+1] = A[j];
else break;
jj-1
A[j+1]temp
ii+1
Step 6: display sorted elements
Step 7: STOP
#include<stdio.h>
void main(){
int i, j, temp;
int A[5];
printf("Enter any 5 elements to sort\n");
// Read Elements
for(i=0;i<5;i++)
scanf("%d",&A[i]);
// Insertion Sort logic
for(i=1; i<5; i++) {
temp = A[i];
for (j=i-1;j>=0;j--)
if (A[j]>=temp) A[j+1] = A[j];
else break;
A[j+1] = temp;
} // end for
// display sorted elements
printf("\nElements after sorting\n");
for(j=0;j<5;j++)
printf("%d ",A[j]);
}
Output:
Enter any 5 elements to sort
34 51 20 15 37
Elements after sorting
15 20 34 37 51
Selection Sort:
Selection Sort algorithm first finds the smallest element in the list and swaps it with the element in
the first position, then finds the second smallest element and exchange it with the element in the
second position, and continues in this way until the entire list is sorted.
If we want to sort the elements in descending order, we can do the same above procedure by taking
biggest number instead of smallest number.
Example:
In the above example, there are total 6 elements in the list. So we will get the sorted list after 5
iterations.
In first iteration, 1 is the smallest element. So 1 is placed in the first position after swapping with 3.
In second iteration, 3 is smallest element. So 3 is placed in the second position after swapping with 6.
In third iteration, 4 is smallest element. So 4 is placed in the third position after swapping with 6.
In fourth iteration, 5 is smallest element. So 5 is placed in the fourth position after swapping with 8.
In fifth iteration, 6 is the smallest number which is in fifth position. So, no need to swap.
After fifth iteration, all the elements will be in sorted order.
Algorithm:
Step 1: START
Step 7: STOP
#include<stdio.h>
void main(){
int i,j, temp, min;
int A[5];
for(i=0;i<5;i++){
scanf("%d",&A[i]);
}
//Selection_Sort logic
for (i=0;i<4;i++){
min = i;
for (j=i+1;j<5;j++)
if (A[j]<A[min]) min = j;
temp = A[i];
A[i]=A[min];
A[min]=temp;
}
// display sorted elements
for(j=0;j<5;j++)
printf("%d ",A[j]);
}
Output:
26 67 32 11 54
11 26 32 54 67
Merge Sort:
Merge sort is a “divide and conquer” algorithm wherein we first divide the problem into sub problems. When
the solutions for the sub problems are ready, we combine them together to get the final solution to the
problem.
This is one of the algorithms which can be easily implemented using recursion as we deal with the sub
problems rather than the main problem.
Divide: In this step, we divide the input array into 2 halves, the pivot being the midpoint of the array. This
step is carried out recursively for all the half arrays until there are no more half arrays to divide.
Conquer: In this step, we sort and merge the divided arrays from bottom to top and get the sorted array.
Algorithm:
Step 1: N = high-low
Find the middle point to divide the array into two halves:
mid = low +N/2
Step 2: call mergeSort for first half:
call mergeSort(A, low, mid)
Step 3: call mergeSort for second half:
call mergeSort(A, mid, high)
Step 4: Merge the two halves sorted in step 2 and 3:
#include<stdio.h>
void sort(int[], int, int);
void main(){
int i, n, a[10];
printf("Enter number of elements...");
scanf("%d",&n);
printf("Enter the elements...");
// to read elements
for (i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,0,n);
// to display sorted elements
printf("Elements after sorting…");
for (i=0;i<n;i++)
printf("%d ",a[i]);
}
Output:
Quick Sort:
Quick sort algorithm is very fast & requires less additional space.
This algorithm is based on the rule ‘Divide and Conquer’. This is also called partition exchange sort.
This algorithm divides the list into 3 main parts:
Elements less than pivot element.
Pivot element.
Elements greater than pivot element.
Using this algorithm recursively, we end up with smaller possible partitions. Each partition is then
processed for quick sort. We define recursive algorithm for quicksort as follows −
Following are the steps to follow, when we want to partition in quick sort.
Example:
In the above example, after partition the pivot element 25 is in its correct position.
Now consider 6,8,17,14 & 37,52, 63 as two separate groups and apply the same logic to partition.
This process continues until all the elements are sorted.
#include<stdio.h>
int A[5] = {12, 45, 10, 67, 18};
void display(){
for(int j=0;j<5;j++)
printf("%d ",A[j]);
}
void swap(int m, int n){
int temp = A[m];
A[m] = A[n];
A[n] = temp;
}
void main(){
display();
QSort(0,4);
printf("\n");
display();
}
Output:
12 45 10 67 18
10 12 18 45 67
UNIT 5
Trees & Graphs
Binary Trees:
A binary tree is a special type of tree in which every node or vertex has maximum of two child
nodes.
Child node in a binary tree on the left is termed as 'left child node' and node in the right is
termed as the 'right child node'.
In the below figure, the root node 8 has two children 3 and 10.
The left child node 3 acts as parent node for 1 & 6. The right child node 10 acts as parent node
for 14.
Similarly, 6 has child nodes 4 & 7. 14 has child node 13.
A binary tree is either an empty tree Or a binary tree consists of a node called the root node, a
left subtree and a right subtree, both will act as a binary tree once again.
A binary tree node contains following parts:
data
pointer to left child
pointer to right child
The top most node in the tree is called the root. An empty tree is represented by NULL pointer.
Height of a node : Number of edges from the node to the deepest leaf.
Height of the tree is the height of the root.
Advantages of Trees:
It is a binary tree in which every node in the tree has either 0 or 2 children.
The below shown tree is full binary tree.
The number of leaf nodes in a full binary tree = number of internal nodes + 1
In the above example, there are 4 internal nodes, so leaf nodes are 4+1 = 5.
It is a binary tree in which all internal nodes have two children and all leaves are at same level.
In a perfect binary tree, the number of nodes N = 2L-1, Here L = Number of Leaf nodes
In a perfect binary tree, the number of leaf nodes L = 2H, Here H = Height of the tree
In a perfect binary tree, the number of nodes N = 2H +L-1
It is a binary tree in which every level except the last, is completely filled and all nodes are as
far left as possible.
The number of internal nodes in a complete binary tree = N/2, Here N is total number of nodes.
In the above example, N = 6, So the number of internal nodes = 6/2 = 3
1. Linked Representation
In this representation, the binary tree is stored in the memory, in the form of a linked list where
the number of nodes are stored at non-contiguous memory locations and linked together by
inheriting parent child relationship like a tree.
Each node contains three parts : pointer to the left node, data element and pointer to the
right node.
Each binary tree has a root pointer, which points to the root node of the binary tree.
In an empty binary tree, the root pointer will point to null.
Consider the binary tree given in the figure below.
In the above figure, a tree is seen as the collection of nodes where each node contains three
parts : left pointer, data element and right pointer. Left pointer stores the address of the left
child while the right pointer stores the address of the right child.
Data Structures Using C | Sudheer Kumar Kasulanati
69
The leaf node contains null in its left and right pointers.
The following image shows about how the memory will be allocated for the binary tree by using
linked representation.
There is a special pointer maintained in the memory which points to the root node of the tree.
Every node in the tree contains the address of its left and right child. Leaf node contains null in
its left and right pointers.
2. Sequential Representation
This is the simplest memory allocation technique used to store the tree elements.
It is an inefficient technique since it requires a lot of space to store the tree elements.
A binary tree is shown in the following figure along with its memory allocation.
In this representation, an array is used to store the tree elements. Size of the array will be
equal to the number of nodes present in the tree.
The root node of the tree will be present at the 1st index of the array. If a node is stored at i th
index then its left and right children will be stored at 2i and 2i+1 location.
Binary tree:
So, in a binary tree of height = 3, maximum number of nodes that can be inserted = 15.
Property 03: Total Number of leaf nodes in a Binary Tree = Total Number of nodes with 2
children + 1
In the above binary tree, number of leaf nodes is 3 & number of nodes with 2 children is 2, So
Total Number of leaf nodes in a Binary Tree = Total Number of nodes with 2 children + 1
Property 04: Maximum number of nodes at any level ‘L’ in a binary tree = 2L
There are three ways to traverse a Binary Tree : in-order, pre-order & post-order traversals.
Ex:
Pre-order Traversal:
In Pre-order traversal of a Binary Tree, data will be visited first, then left & right subtrees will be
visited.
Post-order Traversal:
An Post-order traversal of a Binary Tree, after visiting left & right subtrees, data will be visited.
Following are the steps for Postorder traversal:
Step 1: Traverse the node’s left subtree.
Step 2: Traverse the node’s right subtree.
Step 3: Visit the Node.
A Binary search tree is shown in the above figure. As the constraint applied on the BST, we can see that
the root node 30 contain all values less than 30 in its left sub-tree and contain all values greater than 30
in its right sub-tree.
1. Searching become very efficient in a binary search tree since, we get a hint at each step, about
which sub-tree contains the desired element.
2. The binary search tree is considered as efficient data structure in compare to arrays and linked
lists. In searching process, it removes half sub-tree at every step.
3. It also speed up the insertion and deletion operations as compare to that in array and linked
list.
Construction of BST:
Example: Create the BST using the following data elements: 43, 10, 79, 90, 12, 54, 11, 9, 50
The process of creating BST by using the given elements, is shown in the image below.
1 Searching in Finding the location of some specific element in a binary search tree.
BST
2 Insertion in Adding a new element to the binary search tree at the appropriate location
BST so that the property of BST do not violate.
3 Deletion in Deleting some specific node from a binary search tree. However, there can
BST be various cases in deletion depending upon the number of children, the
node have.
Searching in BST:
To search a given key in Binary Search Tree, we first compare it with root, if the key is present
at root, we return root.
If key is greater than root’s key, we follow the same process for right subtree of root node.
Otherwise we follow the same process for left subtree.
1. Start from the root 43. 54 is greater than 43 so we recur right sub-tree.
2. Now, 54 is less than 79, so we recur left sub-tree.
3. Now, 54 is equal to 54. So element is found in the BST.
Example:
1) Node to be deleted is leaf: Simply remove the node from the tree.
2) Node to be deleted has only one child: Copy the child to the node and delete the child.
3) Node to be deleted has two children: Find inorder successor of the node. Copy contents of
the inorder successor to the node and delete the inorder successor. Note that inorder predecessor
can also be used.
Threaded Binary Tree is also a binary tree in which all left child pointers that are NULL (in Linked
list representation) points to their in-order predecessor, and all right child pointers that are NULL
(in Linked list representation) points to their in-order successor.
A binary tree can be represented using array representation or linked list representation. When a
binary tree is represented using linked list representation, the reference part of the node which
doesn't have a child is filled with a NULL pointer.
In any binary tree linked list representation, there is a number of NULL pointers than actual
pointers.
Generally, in any binary tree linked list representation, if there are 2N number of reference fields,
then N+1 number of reference fields are filled with NULL.
This NULL pointer does not play any role except indicating that there is no link (no child).
A. J. Perlis and C. Thornton have proposed new binary tree called "Threaded Binary Tree",
which makes use of NULL pointers to improve its traversal process.
In a threaded binary tree, NULL pointers are replaced by references of other nodes in the tree.
These extra references are called as threads.
If there is no in-order predecessor or in-order successor, then it points to the root node.
To convert the above example binary tree into a threaded binary tree, first find the in-order
traversal of that tree.
In-order traversal of above binary tree: H - D - I - B - E - A - F - J - C – G
When we represent the above binary tree using linked list representation, nodes H, I, E, F,
J and G left child pointers are NULL. This NULL is replaced by address of its in-order predecessor
respectively (I to D, E to B, F to A, J to F and G to C), but here the node H does not have its in-
order predecessor, so it points to the root node A.
The nodes H, I, E, J and G right child pointers are NULL. These NULL pointers are replaced by
address of its in-order successor respectively (H to D, I to B, E to A, and J to C), but here the node
G does not have its in-order successor, so it points to the root node A.
Above example binary tree is converted into threaded binary tree as follows.
Graph
A graph can be defined as group of vertices and edges that are used to connect these vertices.
A graph can be seen as a cyclic tree, where the vertices (Nodes) maintain any complex relationship among
them instead of having parent child relationship.
Definition
A graph G can be defined as an ordered set G(V, E) where V(G) represents the set of vertices and E(G)
represents the set of edges which are used to connect these vertices.
A Graph G(V, E) with 5 vertices (A, B, C, D, E) and six edges ((A,B), (B,C), (C,E), (E,D), (D,B), (D,A)) is
shown in the following figure.
A B C
A A
D E
A
Types of Graphs:
A B C
A A
D E
A
Undirected Graph
A B C
A A
D E
A
Directed Graph
Graph Terminology
Path
A path can be defined as the sequence of nodes that are followed in order to reach some terminal node V from the
initial node U.
Closed Path
A path will be called as closed path if the initial node is same as terminal node. A path will be closed path if V 0=VN.
Simple Path
If all the nodes of the graph are distinct with an exception V0=VN, then such path P is called as closed simple path.
Cycle
A cycle can be defined as the path which has no repeated edges or vertices except the first and last vertices.
Connected Graph
A connected graph is the one in which some path exists between every two vertices (u, v) in V. There are no
isolated nodes in connected graph.
Complete Graph
A complete graph is the one in which every node is connected with all other nodes. A complete graph contain
Weighted Graph
In a weighted graph, each edge is assigned with some data such as length or weight. The weight of an edge e can
be given as w(e) which must be a positive (+) value indicating the cost of traversing the edge.
Digraph:
A digraph is a directed graph in which each edge of the graph is associated with some direction and the traversing
can be done only in the specified direction.
Adjacent Nodes
If two nodes u and v are connected via an edge e, then the nodes u and v are called as neighbours or adjacent
nodes.
A degree of a node is the number of edges that are connected with that node. A node with degree 0 is called as
isolated node.
Graph Representation
Graph representation is the technique which is to be used in order to store some graph into the computer's
memory.
There are two ways to store Graph into the computer's memory.
Sequential Representation
In sequential representation, we use adjacency matrix to store the mapping represented by vertices and
edges.
In adjacency matrix, the rows and columns are represented by the graph vertices.
A graph having n vertices, will have a dimension n x n.
An entry Mij in the adjacency matrix representation of an undirected graph G will be 1 if there exists an
edge between Vi and Vj.
An undirected graph and its adjacency matrix representation is shown in the following figure.
in the above figure, we can see the mapping among the vertices (A, B, C, D, E) is represented by using
the adjacency matrix which is also shown in the figure.
There exists different adjacency matrices for the directed and undirected graph. In directed graph, an
entry Aij will be 1 only when there is an edge directed from Vi to Vj.
A directed graph and its adjacency matrix representation is shown in the following figure.
Representation of weighted directed graph is different. Instead of filling the entry by 1, the Non- zero
entries of the adjacency matrix are represented by the weight of respective edges.
The weighted directed graph along with the adjacency matrix representation is shown in the following
figure.
Linked Representation
In the linked representation, an adjacency list is used to store the Graph into the computer's memory.
Consider the undirected graph shown in the following figure and check the adjacency list representation.
An adjacency list is maintained for each node present in the graph which stores the node value and a
pointer to the next adjacent node to the respective node.
If all the adjacent nodes are traversed then store the NULL in the pointer field of last node of the list.
The sum of the lengths of adjacency lists is equal to the twice of the number of edges present in an
undirected graph.
In the above example, Number of edges is 6 and sum of lengths in adjacency list is 12.
Consider the directed graph shown in the following figure and check the adjacency list representation of
the graph.
In a directed graph, the sum of lengths of all the adjacency lists is equal to the number of edges present in
the graph.
In the above example, the number of edges is 6 & the sum of lengths is 6.
In the case of weighted directed graph, each node contains an extra field that is called the weight of
the node. The adjacency list representation of a directed graph is shown in the following figure.
The DFS algorithm uses a stack to remember where it should go when it reaches dead end.
Ex:
Select a starting point, In the above example, we selected ‘A’. Follow the rules mentioned below.
Rule1 : If possible, visit an adjacent unvisited vertex, mark it, push it on the stack.
Rule 2: If you can’t follow Rule 1, then if possible, pop the vertex from stack.
Rule 3: If you can’t follow Rule 1 (or) Rule 2, then you are finished.
In BFS, all the adjacent vertices are visited first, then goes for remaining vertices.
Ex:
Select a starting point, In the above example, we selected ‘A’. Make it current vertex & follow the rules
mentioned below.
Rule1: Visit the next unvisited vertex, that is adjacent to the current vertex. Mark it & insert into the
queue.
Rule 2: If you can’t follow Rule 1 (There is no unvisited vertex), Remove a vertex from the queue &
make it the current vertex.
Rule 3: If you can’t follow Rule 2 (queue is empty), you are finished.
The MST connects all the vertices with minimum number of edges & with minimum
weightage.
If there are ‘n’ number of vertices in a graph, then the minimum number of edges will
be ‘n-1’.
Following figure is a graph of 7 vertices.
The edges & weights for the above graph are shown below.
Step 1:
Find the edge, which is having minimum weight. In the above example, the edge ‘AC’ is having
minimum weight (5).
Step 2:
Find the minimum in remaining edges. (Make sure that whenever we select an edge, it should not
form cycle with already selected edges).
In the above example, select BD (7), FG (9), CD (13), EG (14) & BE (15).
The connected components of a graph can be found using either a depth-first search (DFS), or a
breadth-first search (BFS).
We start at an arbitrary vertex, and visit every vertex adjacent to it recursively, adding them to
the first component.
Once this search has finished, we have visited all of the vertices in the first connected
component, so we choose another unvisited vertex (if any) and perform the same search
starting from it, adding the vertices we find to the second component.
This process continues until all vertices have been visited, at which point we know the number
of connected components in the graph, and which vertices they contain.
Given an undirected graph g, the task is to print the number of connected components in the
graph.
Approach: The idea is to use a variable count to store the number of connected components
and do the following steps:
There are two types of connected components in directed graph: strongly connected and weakly
connected components.
A directed graph is said to be strongly connected if from any node there’s always a path to
reach any other one. This is the criterion city roads should be designed with.
Example 1: As we can see, In the below component, all nodes can be reached from any
other node. So it is strongly connected.
Example 2: In the below component, Since there are no paths between 3 to any other
nodes, it is not strongly connected.
The way to check for a graph being strongly connected is doing a DFS from a starting node and
check if every other node can be reached.
Do this process for all nodes in the component.
If the graph is strongly connected every node will be reachable from the starting one.
Model Paper 1
DATA STRUCTURES USING C
Time : Three hours Max Marks: 70M
SECTION A – (5 x 4 = 20 marks)
SECTION B – (5 x 10 = 50 marks)
Answer following questions.
UNIT 1 UNIT IV
UNIT II UNIT V
11. Write about Array Operations. 17. Binary trees – Traversal techniques.
(or) (or)
12. Write about single linked list & it’s 18. Graphs - Traversals.
operations.
UNIT III
Model Paper 2
DATA STRUCTURES USING C
Time : Three hours Max Marks: 70M
SECTION A – (5 x 4 = 20 marks)
SECTION B – (5 x 10 = 50 marks)
Answer following questions.
UNIT 1 UNIT IV
UNIT II UNIT V
11. Single Linked List Operations. 17. Binary Search Tree – Operations.
(or) (or)
12. Write about Circular Linked List. 18. Minimal Spanning Trees.
UNIT III