Professional Documents
Culture Documents
Data Structure can be defined as the group of data elements which provides an efficient
way of storing and organising data in the computer so that it can be used efficiently.
Some examples of Data Structures are arrays, Linked List, Stack, Queue, etc. Data
Structures are widely used in almost every aspect of Computer Science i.e. Operating
or
“A data structure is basically a group of data elements that are put together under one
name, and which defines a particular way of storing and organizing data in a computer so
•COMPILER DESIGN
•OPERATING SYSTEM
•DBMS
•ARTIFICIAL INTELLIGENCE
•GRAPHICS
•SIMULATION
•NUMERICAL ANALYSIS etc.
Classification of data Structure PRIMITIVE DATA TYPE –:
Primitive data structures are the fundamental data types which are supported by a
programming language. some basic data types are integer, character, Boolean pointer,
Non-primitive data structures are that data structures that are created using primitive data
If the element of data structures is stored in linear or sequential order then it is called linear
Linear data structures are stored in memory with a linear relationship between elements by
an element of the array. The data type of the element may be any valid data type like char,
Linked List:Linked list is a linear data structure which is used to maintain a list in the
locations. Each node of the list contains a pointer to its adjacent node.
Stack: Stack is a linear list in which insertion and deletions are allowed only at one end,
called top.
Queue: Queue is a linear list in which elements can be inserted only at one end called rear
If the element of data structures is not stored in sequential order, then it is called non-linear
Non-linear data structures are stored in memory with random orders location.
Trees: Trees are multilevel data structures with a hierarchical relationship among its
elements known as nodes. The bottommost nodes in the hierarchy are called leaf node
while the topmost node is called root node. Each node contains pointers to point adjacent
nodes.
Graphs: Graphs can be defined as the pictorial representation of the set of elements
(represented by vertices) connected by the links known as edges. A graph is different from
tree in the sense that a graph can have cycle while the tree cannot have the one.
Data Structure Operations
1) Traversing: Every data structure contains the set of data elements. Traversing the data
structure means visiting each element of the data structure in order to perform some
specific operation like searching or sorting.
Example: If we need to calculate the average of the marks obtained by a student in 6
different subjects, we need to traverse the complete array of marks and calculate the total
sum, then we will divide that sum by the number of subjects i.e. 6, in order to find the
average.
2) Insertion: Insertion can be defined as the process of adding the elements to the data
structure at any location.
If the size of data structure is n then we can only insert n-1 data elements into it.
3) Deletion:The process of removing an element from the data structure is called Deletion.
We can delete an element from the data structure at any random location.
If we try to delete an element from an empty data structure then underflow occurs.
4) Searching: The process of finding the location of an element within the data structure is
called Searching. There are two algorithms to perform searching, Linear Search and
Binary Search.
5) Sorting: The process of arranging the data structure in a specific order is known as
Sorting. There are many algorithms that can be used to perform sorting, for example,
insertion sort, selection sort, bubble sort, etc.
6) Merging: When two lists List A and List B of size M and N respectively, of similar type of
elements, clubbed or joined to produce the third list, List C of size (M+N), then this process
is called merging
What is a Stack?
A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle. Stack
has one end, whereas the Queue has two ends (front and rear). It contains only one
pointer top pointer pointing to the topmost element of the stack. Whenever an element is
added in the stack, it is added on the top of the stack, and the element can be deleted only
from the stack top. In other words, a stack can be defined as a container in which
insertion and deletion can be done from the one end known as the top of the stack.
1. Working of Stack
Stack works on the LIFO pattern. As we can observe in the below figure there are five
Suppose we want to store the elements in a stack and let's assume that stack is empty.
We have taken the stack of size 5 as shown below in which we are pushing the elements
•Pop(): When we delete an element from the stack, the operation is known as a
pop. If the stack is empty means that no element exists in the stack, this state is
known as an underflow state.
3. PUSH operation
•If we try to insert the element in a stack, and the stack is full, then the overflow
condition occurs.
•When we initialize a stack, we set the value of top as -1 to check that the stack is
empty.
•When the new element is pushed in a stack, first, the value of the top gets
incremented, i.e., top=top+1, and the element will be placed at the new position of
the top.
•The elements will be inserted until we reach the max size of the stack.
POP Operation
•Before deleting the element from the stack, we check whether the stack is empty.
•If we try to delete the element from the empty stack, then the underflow condition occurs.
•If the stack is not empty, we first access the element which is pointed by the top
•Once the pop operation is performed, the top is decremented by 1, i.e., top=top-1.
4. Ap
plication
s of
Stack
Balancin
g of
symbols:
Stack is
used for balancing a symbol. For example, we have the following program:
intmain()
1. {
2. cout<<"Poly";
3. cout<<"Technic";
4. }
As we know, each program has an opening and closing braces; when the opening braces
come, we push the braces in a stack, and when the closing braces appear, we pop the
opening braces from the stack. Therefore, the net value comes out to be zero. If any
symbol is left in the stack, it means that some syntax occurs in a program.
String reversal: Stack is also used for reversing a string. For example, we want to reverse
a "Poly Technic" string, so we can achieve this with the help of a stack.
Recursion: The recursion means that the function is calling itself again. To maintain the
previous states, the compiler creates a system stack in which all the previous records of
DFS(Depth First Search):This search is implemented on a Graph, and Graph uses the
the most important applications of stack. The list of the expression conversion is given
below:
Infix to prefix
Infix to postfix
Prefix to infix
Prefix to postfix
Postfix to infix
In array implementation, the stack is formed by using the array. All the operations
Adding an element into the top of the stack is referred to as push operation. Push
operation involves following two steps.
1.Increment the variable Top so that it can now refere to the next memory location.
2.Add element at the position of incremented top. This is referred to as adding new
element at the top of the stack.
Algorithm
begin
end
if (top == n )
printf("\n Overflow");
else
stack[top] = val;
}
1. Deletion of an element from a stack (Pop operation)
Deletion of an element from the top of the stack is called pop operation. The value of the
variable top will be Decrimented by 1 whenever an item is deleted from the stack. 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 as the
result.
The underflow condition occurs when we try to delete an element from an already empty
stack.
Algorithm
begin
item = stack(top);
top = top - 1;
end;
int pop ()
if(top == -1)
printf("Underflow");
return 0;
}
else
return stack[top - - ];
Peek operation involves returning the element which is present at the top of the stack w ithout
deleting it. Underflow condition can occur if we try to return the top element in an already empty
stack.
Begin
if top = -1 then stack empty
item = stack[top]
return item
End
int peek()
{
if (top == -1)
{
printf("Underflow");
return 0;
}
else
{
return stack [top];
}
}
4. Implementation of Stack using Array
#include <stdio.h>
int stack[100],i,j,choice=0,n,top=-1;
void push();
void pop();
void show();
void main ()
{
printf("Enter the number of elements in the stack ");
scanf("%d",&n);
printf("*********Stack operations using array*********");
printf("\n----------------------------------------------\n");
while(choice != 4)
{
printf("Chose one from the below options...\n");
printf("\n1.Push\n2.Pop\n3.Show\n4.Exit");
printf("\n Enter your choice \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
{
push();
break;
}
case 2:
{
pop();
break;
}
case 3:
{
show();
break;
}
case 4:
{
printf("Exiting....");
break;
}
default:
{
printf("Please Enter valid choice ");
}
}
}
}
void push ()
{
int val;
if (top == n )
printf("\n Overflow");
else
{
printf("Enter the value?");
scanf("%d",&val);
top = top +1;
stack[top] = val;
}
}
void pop ()
{
if(top == -1)
printf("Underflow");
else
top = top -1;
}
void show()
{
for (i=top;i>=0;i--)
{
printf("%d\n",stack[i]);
}
if(top == -1)
{
printf("Stack is empty");
}
}
Infix-to-Postfix Conversion
Sample example :
Precedenc
Type Operators Associativity
e
1 Postfix () [] -> . ++ — Left to Right
2 Unary + – ! ~ ++ — (type)* & sizeof Right to Left
3 Multiplicative */% Left to Right
4 Additive +– Left to Right
5 Shift <<, >> Left to Right
6 Relational < <= > >= Left to Right
7 Equality == != Left to Right
8 Bitwise AND & Left to Right
9 Bitwise XOR ^ Left to Right
10 Bitwise OR | Left to Right
11 Logical AND && Left to Right
12 Logical OR || Left to Right
13 Conditional ?: Right to Left
14 Assignment = += -+ *= /= %= >>= <<= &= ^= |= Right to Left
15 Comma , Left to Right
Infix notation is the notation in which operators come between the required
operands. It is the same as the arithmetic notation that we had learned in our
school days.
1. Syntax of infix notation
Example - If we were to add two numbers 3 and 4, the operator that is '+' would come
Postfix Expression, also known as Reverse Polish Notation is the type of notation in which
operator comes after the operand. For eg- If the infix expression is x + y, it's corresponding
postfix notation is x y +.
Initially we have a infix expression given to us to convert to postfix notation. The infix
notation is parsed from left to right, and then converted to postfix. Assume initially the
postfix expression is empty, and we will fill the postfix expression out with the following
steps:
3.If we have a closing parenthesis ")" we keep popping out elements from the top of
the stack and append them to our postfix expression until we encounter an opening
4.1. If the operator has higher precedence than the one on top of the stack
4.2. If the operator has lower or equal precedence than the one on top of the
5.When the last token of infix expression has been scanned, we pop the remaining
+
+
L + KL
- K L+
-
- K L+M
M
-* K L+M
*
-* K L+M N
N
+ K L+M N * -
+
+( K L+M N * -
(
+(^ K L+M N * - O
O
^ K L+M N * - O
+(^
+(^ K L+M N * - O P
P
+ K L+ M N * - O P^
)
+* K L + M N* - O P ^
*
+* K L + M N* - O P ^ W
W
K L + M N* - O P ^ W *
/ +/
U K L + M N* - O P ^W * U
+/
/ K L + M N* - O P ^W * U /
+/
V K L + M N* - O P ^ W * U / V
+/
* K L + M N* - O P ^W * U / V /
+*
T K L + M N* - O P ^W * U / V / T
+*
+ K L + M N* - O P ^W * U / V / T * +
+
+ K L + M N* - O P ^W * U / V / T * + Q
Q
Element Stack contents Postfix Expression
K L + M N* - O P ^W * U / V / T * + Q+
Introduction to Queues
1.A queue can be defined as an ordered list which enables insert operations to be
Appication of Queue
1Queues are widely used as waiting lists for a single shared resource like
2.Queues are used in asynchronous transfer of data (where data is not being
transferred at the same rate between two processes) for eg. pipes, file IO, sockets.
3.Queues are used as buffers in most of the applications like MP3 media player, CD
player, etc.
4.Queue are used to maintain the play list in media players in order to add and
remove the songs from the play-list.
Types of Queues.
insertion is done from one end known as the rear end or the tail of the queue, whereas
the deletion is done from another end known as the front end or the head of the queue.
Types of Queue
There are four different types of queue that are listed as follows -
1. Simple Queue or Linear Queue
2. Circular Queue
3. Priority Queue
4. Double Ended Queue (or Deque)
from another end. The end at which the insertion takes place is known as the rear
end, and the end at which the deletion takes place is known as front end. It strictly
end. If the first three elements are deleted from the Queue, we cannot insert more
elements even though the space is available in a Linear Queue. In this case, the linear
Queue shows the overflow condition as the rear is pointing to the last element of
the Queue.
2. Circular Queue
A circular queue is similar to a linear queue as it is also based on the FIFO (First In First
Out) principle except that the last position is connected to the first position in a
•enQueue(value): This function is used to insert the new value in the Queue. The
new element is always inserted from the rear end.
•DeQueue(): This function deletes an element from the Queue. The deletion in a
Queue always takes place from the front end.
o CPU Scheduling: The operating system also uses the circular queue to insert the processes
and then execute them.
o Traffic system: In a computer-control traffic system, traffic light is one of the best
examples of the circular queue. Each light of traffic light gets ON one by one after every
interval of time. Like red light gets ON for one minute then yellow light for one minute and
then green light. After green light, the red light gets ON.
There was one limitation in the array implementation of Queue. If the rear reaches to the
end position of the Queue, then there might be possibility that some vacant spaces are
left in the beginning which cannot be utilized. So, to overcome such limitations, the
concept of the circular queue was introduced.
when rear reach the end of a queue, start from the beginning of a queue. The circular
incrementation is achievable with the help of the modulo division.
Let’s say the MaxSize of your queue is 5, and the rear pointer has already reached the
end of a queue. There is one empty space at the beginning of a queue, which means
that the front pointer is pointing to location 1.
Step 4: EXIT
Priority queue.
It is a special type of queue in which the elements are arranged based on the
priority.
It is a special type of queue data structure in which every element has a priority
associated with it.
Suppose some elements occur with the same priority, they will be arranged
according to the FIFO principle.
The representation of priority queue is shown in the below image –
Insertion in priority queue takes place based on the arrival, while deletion in the
priority queue occurs based on the priority. Priority queue is mainly used to
implement the CPU scheduling algorithms.
There are two types of priority queue that are discussed as follows –
o
Characteristics of Priority Queue
Priority queue in a data structure is an extension of a linear queue that possesses the
following properties:
• It will delete the element with higher priority before the element with
lower priority.
• If multiple elements have the same priority, it does their removal from the
queue according to the FCFS principle.
understand these properties with the help of an example. Consider you have to insert
7, 2, 45, 32, and 12 in a priority queue. The element with the least value has the
highest property. Thus, you should maintain the lowest element at the front node.
Deque (or double-ended queue)
The deque stands for Double Ended Queue. Deque is a linear data structure where
the insertion and deletion operations are performed from both ends.
Though the insertion and deletion in a deque can be performed on both ends, it does
not follow the FIFO rule. The representation of a deque is given as follows -
1. Types of deque
There are two types of deque -
o Input restricted queue
o Output restricted queue
Input restricted Queue
In input restricted queue, insertion operation can be performed at only one end,
while deletion can be performed from both ends.
Output restricted Queue
In output restricted queue, deletion operation can be performed at only one end, while insertion
can be performed from both ends.
We can easily represent queue by using linear arrays. There are two
variables i.e. front and rear, that are implemented in the case of every
queue. Front and rear variables point to the position from where insertions
and deletions are performed in a queue. Initially, the value of front and
queue containing 5 elements along with the respective values of front and
Check if the queue is already full by comparing rear to max - 1. if so, then
return an overflow error.
If the item is to be inserted as the first element in the list, in that case set
the value of front and rear to 0 and insert the element at the rear end.
Otherwise keep increasing the value of rear and insert each element one
by one having rear as the index.
Algorithm
Step 4: EXIT
C Function
void insert (int queue[], int max, int front, int rear, int item)
{
if (rear + 1 == max)
{
printf("overflow");
}
else
{
if(front == -1 && rear == -1)
{
front = 0;
rear = 0;
} There are various operations which can be performed on singly
linked list. A list of all such operations is given below.
else
{
rear = rear + 1;
}
queue[rear]=item;
}
}
Algorithm
Step 1: IF FRONT = -1 or FRONT > REAR
Write UNDERFLOW
ELSE
SET VAL = QUEUE[FRONT]
SET FRONT = FRONT + 1
[END OF IF]
Step 2: EXIT
C Function
int delete (int queue[], int max, int front, int rear)
{
int y;
if (front == -1 || front > rear)
{
printf("underflow");
}
else
{
y = queue[front];
if(front == rear)
{
front = rear = -1;
else
front = front + 1;
}
return y;
}
}
Menu driven program to implement queue using array
#include<stdio.h>
#include<stdlib.h>
#define maxsize 5
void insert();
void delet();
void display();
int front = -1, rear = -1;
int queue[maxsize];
void main ()
{
int choice=0;
while(choice != 4)
{
printf("\n*************************MainMenu***********************\n");
printf("\n===================================================\n");
printf("\n1.insert an element\n2.Delete an element\n3.Display the queue\n4.Exit\n");
printf("\nEnter your choice ?");
scanf("%d",&choice);
switch(choice)
{
case 1:
insert();
break;
case 2:
delet();
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nEnter valid choice??\n");
}
}
}
void insert()
{
int item;
printf("\nEnter the element\n");
scanf("\n%d",&item);
if(rear == maxsize-1)
{
printf("\nOVERFLOW\n");
return;
}
if(front == -1 && rear == -1)
{
front = 0;
rear = 0;
}
else
{
rear = rear+1;
}
queue[rear] = item;
printf("\nValue inserted ");
}
void delet()
{
int item;
if (front == -1 || front > rear)
{
printf("\nUNDERFLOW\n");
return;
}
else
{
item = queue[front];
if(front == rear)
{
front = -1;
rear = -1 ;
}
else
{
front = front + 1;
}
printf("\nvalue deleted ");
}
}
void display()
{
int i;
if(rear == -1)
{
printf("\nEmpty queue\n");
}
else
{ printf("\nprinting values .....\n");
for(i=front;i<=rear;i++)
{
printf("\n%d\n",queue[i]);
}
}
}
Out Put
*************Main Menu**************
==============================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Value inserted
*************Main Menu**************
==============================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Value inserted
*************Main Menu**************
===================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
value deleted
*************Main Menu**************
==============================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
90
*************Main Menu**************
==============================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Linked List
o Linked List can be defined as collection of objects called nodes that are
o A node contains two fields i.e., data stored at that particular address and
the pointer which contains the address of the next node in the memory.
o You have to start somewhere, so we give the address of the first node a
special name called HEAD. Also, the last node in the linked list can be
identified because its next portion points to NULL.
o Linked lists can be of multiple types: singly, doubly, and circular linked list.
o We can store values of primitive types or objects in the singly linked list.
3. All the elements in the array need to be contiguously stored in the memory.
Inserting any element in the array needs shifting of all its predecessors.
Linked list is the data structure which can overcome all the limitations of an array.
Using linked list is useful because,
1. It allocates the memory dynamically. All the nodes of linked list are non-
contiguously stored in the memory and linked together with the help of
pointers.
2. Sizing is no longer a problem since we do not need to define its size at the time
of declaration. List grows as per the program's demand and limited to the
available memory space.
number of elements may vary according to need of the program. A node in the singly
linked list consists of two parts: data part and link part. Data part of the node
stores actual information that is to be represented by the node while the link
One way chain or singly linked list can be traversed only in one direction. In other
words, we can say that each node contains only next pointer, therefore we cannot
In the above figure, the arrow represents the links. The data part of every node
contains the marks obtained by the student in the different subject. The last node in
the list is identified by the null pointer which is present in the address part of the last
node. We can have as many elements we require, in the data part of the list.
There are various operations which can be performed on singly linked list. A list of
all such operations is given below.
1.
2.
Linked list is the data structure which can overcome all the limitations of an
array. Using linked list is useful because,
3. Node Creation
struct node
{
int data;
struct node *next;
};
/* Initialize nodes */
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
/* Connect nodes */
one->next = two;
two->next = three;
three->next = NULL;
The power of a linked list comes from the ability to break the chain and rejoin it. E.g.
if you wanted to put an element 4 between 1 and 2, the steps would be:
• Point its next pointer to the struct node containing 2 as the data value
int main()
{
//node structure
struct node
{
int data;
struct node *next;
};
//declaring nodes
struct node *head,*middle,*last;
return 0;
}
Output
1->2->3->NULL
Linked List Operations: Traverse, Insert and Delete
Displaying the contents of a linked list is very simple. We keep moving the
temp node to the next one and display its contents.
When temp is NULL, we know that we have reached the end of the linked list
so we get out of the while loop.
while(temp != NULL)
printf("%d --->",temp->data);
temp = temp->next;
}
Output
• Store data
newNode->data = 4;
newNode->next = head;
head = newNode;
2. Insert at the End
• Store data
newNode->data = 4;
newNode->next = NULL;
while(temp->next != NULL)
temp = temp->next;
temp->next = newNode;
3. Insert at the Middle
newNode->data = 4;
if(temp->next != NULL)
temp = temp->next;
newNode->next = temp->next;
temp->next = newNode;
Delete from a Linked List
You can delete either from the beginning, end or from a particular posit ion.
head = head->next;
while(temp->next->next!=NULL)
temp = temp->next;
temp->next = NULL;
3. Delete from middle
if(temp->next!=NULL) {
temp = temp->next;
temp->next = temp->next->next;
You can search an element on a linked list using a loop using the following
steps. We are finding item on a linked list.
• Make head as the current node.
• Run a loop until the current node is NULL because the last element
points to NULL.
• In each iteration, check if the key of the node is equal to item. If it the
#include<stdlib.h>
struct node
int data;
};
void randominsert();
void begin_delete();
void last_delete();
void random_delete();
void display();
void search();
int main ()
while(choice != 9)
printf("\n\n*********Main Menu*********\n");
printf("\n===============================================\n");
scanf("\n%d",&choice);
switch(choice)
case 1:
beginsert();
break;
case 2:
lastinsert();
break;
case 3:
randominsert();
break;
case 4:
begin_delete();
break;
case 5:
last_delete();
break;
case 6:
random_delete();
break;
case 7:
search();
break;
case 8:
display();
break;
case 9:
exit(0);
break;
default:
return (0);
void beginsert()
{
struct node *ptr;
int item;
if(ptr == NULL)
printf("\nOVERFLOW");
else
printf("\nEnter value\n");
scanf("%d",&item);
ptr->data = item;
ptr->next = head;
head = ptr;
printf("\nNode inserted");
void lastinsert()
int item;
if(ptr == NULL)
printf("\nOVERFLOW");
}
else
printf("\nEnter value?\n");
scanf("%d",&item);
ptr->data = item;
if(head == NULL)
head = ptr;
printf("\nNode inserted");
else
temp = head;
temp->next = ptr;
ptr->next = NULL;
printf("\nNode inserted");
}
void randominsert()
int i,loc,item;
if(ptr == NULL)
printf("\nOVERFLOW");
else
scanf("%d",&item);
ptr->data = item;
scanf("\n%d",&loc);
temp=head;
for(i=0;i<loc;i++)
temp = temp->next;
if(temp == NULL)
printf("\ncan't insert\n");
return;
}
}
printf("\nNode inserted");
void begin_delete()
if(head == NULL)
printf("\nList is empty\n");
else
ptr = head;
head = ptr->next;
free(ptr);
void last_delete()
if(head == NULL)
{
printf("\nlist is empty");
head = NULL;
free(head);
else
ptr = head;
while(ptr->next != NULL)
ptr1 = ptr;
ptr1->next = NULL;
free(ptr);
void random_delete()
int loc,i;
printf("\n Enter the location of the node after which you want to perform deletion \n");
scanf("%d",&loc);
ptr=head;
for(i=0;i<loc;i++)
ptr1 = ptr;
ptr = ptr->next;
if(ptr == NULL)
printf("\nCan't delete");
return;
free(ptr);
void search()
int item,i=0,flag;
ptr = head;
if(ptr == NULL)
printf("\nEmpty List\n");
}
else
scanf("%d",&item);
while (ptr!=NULL)
if(ptr->data == item)
flag=0;
else
flag=1;
i++;
if(flag==1)
}
void display()
ptr = head;
if(ptr == NULL)
printf("Nothing to print");
else
while (ptr!=NULL)
printf("\n%d",ptr->data);
}
Circular Singly Linked List
In a circular Singly linked list, the last node of the list contains a pointer to the first
node of the list. We can have circular singly linked list as well as circular doubly
linked list.
We traverse a circular singly linked list until we reach the same node where we
started. The circular singly liked list has no beginning and no ending. There is no null
value present in the next part of any of the nodes.
subjects. However, the image shows a glimpse of how the circular list is being stored
in the memory. The start or head of the list is pointing to the element with the index 1
and containing 13 marks in the data part and 4 in the next part. Which means that it is
linked with the node that is being stored at 4th index of the list .
In Circular linked list last node of the list contains the address of the first node of the
list.
1 Insertion at beginning Adding a node into circular singly linked list at the beginning.
2 Insertion at the end Adding a node into circular singly linked list at the end.
1 Deletion at Removing the node from circular singly linked list at the beginning.
beginning
2 Deletion at the Removing the node from circular singly linked list at the end.
end
3 Searching Compare each element of the node with the given item and return the
location at which the item is present in the list otherwise return null.
4 Traversing Visiting each element of the list at least once in order to perform some
specific operation.
Doubly linked list
Doubly linked list is a complex type of linked list in which a node contains a
pointer to the previous as well as the next node in the sequence. Therefore, in a
doubly linked list, a node consists of three parts: node data, pointer to the next
node in sequence (next pointer), pointer to the previous node (previous
pointer).
The first element of the list that is i.e. 13 stored at address 1. The head pointer points
to the starting address 1. Since this is the first element being added to the list
therefore the prev of the list contains null. The next node of the list resides at address
We can traverse the list in this way until we find any node containing null or -1 in its
next part.
Linked list implementation of stack
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 top most node in the stack always contains null in its address field.
2. If the list is empty then the item is to be pushed as the start node of the list. This includes
assigning value to the data part of the node and assign null to the address part of the node.
3. If there are some nodes in the list already, then we have to add the new element in the
beginning of the list (to not violate the property of the stack). For this purpose, assign the
address of the starting element to the address field of the new node and make the new
node, the starting node of the list.
#include <stdio.h>
#include <stdlib.h>
struct node {
int info;
}*top,*top1,*temp;
int count = 0;
if (top == NULL)
top->ptr = NULL;
top->info = data;
else
temp->ptr = top;
temp->info = data;
top = temp;
count++;
printf("Node is Inserted\n\n");
int pop() {
top1 = top;
if (top1 == NULL)
printf("\nStack Underflow\n");
return -1;
else
top1 = top1->ptr;
free(top);
top = top1;
count--;
return popped;
}
void display() {
top1 = top;
if (top1 == NULL)
printf("\nStack Underflow\n");
return;
printf("%d--->", top1->info);
top1 = top1->ptr;
printf("NULL\n\n");
int main() {
scanf("%d", &choice);
switch (choice) {
case 1:
scanf("%d", &value);
push(value);
break;
case 2:
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nWrong Choice\n");
}
}
Output
Push Operation
1. Push
2. Pop
3. Display
4. Exit
Node is Inserted
1. Push
2. Pop
3. Display
4. Exit
Node is Inserted
1. Push
2. Pop
3. Display
4. Exit
Node is Inserted
1. Push
2. Pop
3. Display
4. Exit
The stack is
56--->45--->12--->NULL
Pop operation
The stack is
56--->45--->12--->NULL
1. Push
2. Pop
3. Display
4. Exit
1. Push
2. Pop
3. Display
4. Exit
1. Push
2. Pop
3. Display
4. Exit
Enter your choice : 3
The stack is
12--->NULL
1. Push
2. Pop
3. Display
4. Exit
1. Push
2. Pop
3. Display
4. Exit
Implementation of Queue using Linked List
#include<stdio.h>
#include<stdlib.h>
int main() {
int choice, value;
printf("\nImplementation of Queue using Linked List\n");
while (choice != 4) {
printf("1.Enqueue\n2.Dequeue\n3.Display\n4.Exit\n");
printf("\nEnter your choice : ");
scanf("%d", & choice);
switch (choice)
{
case 1:
printf("\nEnter the value to insert: ");
scanf("%d", & value);
enqueue(value);
break;
case 2:
printf("Popped element is :%d\n", dequeue());
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nWrong Choice\n");
}
}
return 0;
}
Output
Enqueue Operation
1.Enqueue
2.Dequeue
3.Display
4.Exit
1.Enqueue
2.Dequeue
3.Display
4.Exit
1.Enqueue
2.Dequeue
3.Display
4.Exit
Dequeue Operation
The queue is
12--->45--->56--->NULL
1.Enqueue
2.Dequeue
3.Display
4.Exit
1.Enqueue
2.Dequeue
3.Display
4.Exit
NON-LINEAR DATA STRUCTURES –:
If the element of data structures is not stored in sequential order, then it is called non-
Non-linear data structures are stored in memory with random orders location.
Trees: Trees are multilevel data structures with a hierarchical relationship among its
elements known as nodes. The bottommost nodes in the hierarchy are called leaf
node while the topmost node is called root node. Each node contains pointers to
Graphs: Graphs can be defined as the pictorial representation of the set of elements
different from tree in the sense that a graph can have cycle while the tree cannot have
the one.
Tree
A tree is also one of the data structures that represent hierarchical data. Suppose
we want to show the employees and their positions in the hierarchical form then it
can be represented as shown below:
The above tree shows the organization hierarchy of some company. In the above
structure, john is the CEO of the company, and John has two direct reports named
as Steve and Rohan. Steve has three direct reports named Lee, Bob,
Ella where Steve is a manager. Rohan has two direct reports
named Sal and Emma. Emma has two direct reports named Tom and Raj. Tom has
one direct report named Bill. This particular logical structure is known as a Tree. Its
structure is similar to the real tree, so it is named a Tree. In this structure, the root is
at the top, and its branches are moving in a downward direction. Therefore, we
can say that the Tree data structure is an efficient way of storing the data in a
hierarchical way.
o Root: The root node is the topmost node in the tree hierarchy. In other
words, the root node is the one that doesn't have any parent. In the above
structure, node numbered 1 is the root node of the tree. If a node is directly
linked to some other node, it would be called a parent-child relationship.
o Child node: If the node is a descendant of any node, then the node is known
as a child node.
o Parent: If the node contains any sub-node, then that node is said to be the
parent of that sub-node.
o Sibling: The nodes that have the same parent are known as siblings.
o Leaf Node: - The node of the tree, which doesn't have any child node, is
called a leaf node. A leaf node is the bottom-most node of the tree. There
can be any number of leaf nodes present in a general tree. Leaf nodes can also
be called external nodes.
o Internal nodes: A node has atleast one child node known as an internal
o Ancestor node: - An ancestor of a node is any predecessor node on a path
from the root to that node. The root node doesn't have any ancestors. In the
tree shown in the above image, nodes 1, 2, and 5 are the ancestors of node 10.
o Descendant: The immediate successor of the given node is known as a
descendant of a node. In the above figure, 10 is the descendant of node 5.
Degree
• Degree of node A = 2
• Degree of node B = 3
• Degree of node C = 2
• Degree of node D = 0
• Degree of node E = 2
• Degree of node F = 0
• Degree of node G = 1
• Degree of node H = 0
• Degree of node I = 0
• Degree of node J = 0
• Degree of node K = 0
Level
Height
• Total number of edges that lies on the longest path from any leaf node to a particular
node is called as height of that node.
• Height of a tree is the height of root node.
• Height of all leaf nodes = 0
Here,
• Height of node A = 3
• Height of node B = 2
• Height of node C = 2
• Height of node D = 0
• Height of node E = 1
• Height of node F = 0
• Height of node G = 1
• Height of node H = 0
• Height of node I = 0
• Height of node J = 0
• Height of node K = 0
Depth
• Total number of edges from root node to a particular node is called as depth of that
node.
• Depth of a tree is the total number of edges from root node to a leaf node in the
longest path.
• Depth of the root node = 0
• The terms “level” and “depth” are used interchangeably.
Here,
• Depth of node A = 0
• Depth of node B = 1
• Depth of node C = 1
• Depth of node D = 2
• Depth of node E = 2
• Depth of node F = 2
• Depth of node G = 2
• Depth of node H = 2
• Depth of node I = 3
• Depth of node J = 3
• Depth of node K = 3
Subtree
Forest
The above tree is a binary tree because each node contains the utmost two children.
The logical representation of the above tree is given below:
In the above tree, node 1 contains two pointers, i.e., left and a right pointer
pointing to the left and right node respectively. The node 2 contains both the nodes
(left and right node); therefore, it has two pointers (left and right). The nodes 3, 5
and 6 are the leaf nodes, so all these nodes contain NULL pointer on both left
and right parts.
Types of Binary Trees:
A full binary tree can be defined as a binary tree in which all the nodes have 0 or two children. In
other words, the full binary tree can be defined as a binary tree in which all the nodes have two
children except the leaf nodes.
Complete binary tree
A binary tree is said to be a complete binary tree when all the levels are completely filled
except the last level, which is filled from the left.
The below tree is a complete binary tree:
The complete binary tree is similar to the full binary tree except for the two differences
which are given below:
o The filling of the leaf node must start from the leftmost side.
o It is not mandatory that the last leaf node must have the right sibling.
Let's understand the above points through an example:
Consider the below tree:
The above tree is a complete binary tree, but not a full binary tree as node 6 does not have its right
sibling.
2. The left pointer of this node points to the left child and the right pointer points
to the right child, and if there is no left or right child, we represent that using
a NULL.
Operations on a Binary Search Tree
A binary search tree follows some order to arrange the elements. In a Binary search tree, the value
of left node must be smaller than the parent node, and the value of right node
must be greater than the parent node. This rule is applied recursively to the left and right
subtrees of the root.
In the above figure, we can observe that the root node is 40, and all the nodes of the left subtree are
smaller than the root node, and all the nodes of the right subtree are greater than the root node.
Similarly, we can see the left child of root node is greater than its left child and smaller than its
right child. So, it also satisfies the property of binary search tree. Therefore, we can say that the
tree in the above image is a binary search tree.
Suppose if we change the value of node 35 to 55 in the above tree, check whether the tree will
be binary search tree or not.
In the above tree, the value of root node is 40, which is greater than its left child 30 but smaller than
right child of 30, i.e., 55. So, the above tree does not satisfy the property of Binary search tree.
Therefore, the above tree is not a binary search tree.
o As compared to array and linked lists, insertion and deletion operations are faster in BST.
Example of creating a binary search tree
Now, let's see the creation of binary search tree using an example.
Suppose the data elements are - 45, 15, 79, 90, 10, 55, 12, 20, 50
o First, we have to insert 45 into the tree as the root of the tree.
o Then, read the next element; if it is smaller than the root node, insert it as the root of the left
subtree, and move to the next element.
o Otherwise, if the element is larger than the root node, then insert it as the root of the right
subtree.
As 79 is greater than 45, so insert it as the root node of the right subtree.
Step 4 - Insert 90.
55 is larger than 45 and smaller than 79, so it will be inserted as the left subtree of 79.
Step 7 - Insert 12.
12 is smaller than 45 and 15 but greater than 10, so it will be inserted as the right subtree of 10.
20 is smaller than 45 but greater than 15, so it will be inserted as the right subtree of 15.
Step 9 - Insert 50.
50 is greater than 45 but smaller than 79 and 55. So, it will be inserted as a left subtree of 55 .
Searching means to find or locate a specific element or node in a data structure. In Binary search
tree, searching a node is easy because elements in BST are stored in a specific order. The steps of
searching a node in Binary Search tree are listed as follows –
1. First, compare the element to be searched with the root element of the tree.
2. If root is matched with the target element, then return the node's location.
3. If it is not matched, then check whether the item is less than the root elemen t, if it is smaller
than the root element, then move to the left subtree.
4. If it is larger than the root element, then move to the right subtree.
6. If the element is not found or not present in the tree, then return NULL.
Now, let's understand the searching in binary tree using an example. We are taking the binary search
tree formed above. Suppose we have to find node 20 from the below tree.
Step1:
Step2:
Step3:
4 is not f ound so, traverse through the lef t subtree of 8
Algorithm to search an element in Binary search tree
Search (root, item)
Step 1 - if (item = root → data) or (root = NULL)
return root
else if (item < root → data)
return Search(root → left, item)
else
return Search(root → right, item)
END if
Step 2 - END
Inorder traversal
Postorder traversal
Inorder Algorithm
Post Algorithm
A new key is always inserted at the leaf by maintaining the property of the binary search tree. We
start searching for a key from the root until we hit a leaf node. Once a leaf node is found, the new
node is added as a child of the leaf node. The below steps are followed while we try to insert a
node into a binary search tree:
• Check the value to be inserted (say X) with the value of the current node
(say val) we are in:
• If X is less than val move to the left subtree.
• Otherwise, move to the right subtree.
• Once the leaf node is reached, insert X to its right or left based on the relation
between X and the leaf node’s value.
Let us try to insert a node with value 40 in this tree:
1st step: 40 will be compared with root, i.e., 100.
• 40 is less than 100.
• So move to the left subtree of 100. The root of the left subtree is 20.
2nd step: 40 is now compared with 20.
• It is greater than 20.
• So move to the right subtree of 20 whose root is 30.
3rd step: 30 is a leaf node.
• So we have to insert 40 to the left or right of 30.
• As 40 is greater than 30, insert 40 to the right of 30.
Binary search tree Deletion
Delete function is used to delete the specified node from a binary search tree. However, we must
delete a node from a binary search tree in such a way, that the property of binary search tree
doesn't violate. There are three situations of deleting a node from binary search tree .
It is the simplest case, in this case, replace the leaf node with the NULL and simple free the
allocated space.
In the following image, we are deleting the node 85, since the node is a leaf node, therefore
the node will be replaced with NULL and allocated space will be freed.
It is a bit complexed case compare to other two cases. However, the node which is to be
deleted, is replaced with its in-order successor or predecessor recursively until the node
value (to be deleted) is placed on the leaf of the tree. After the procedure, replace the node
with NULL and free the allocated space.
In the following image, the node 50 is to be deleted which is the root node of the tree. The
in-order traversal of the tree given below.
6, 25, 30, 50, 52, 60, 70, 75.
replace 50 with its in-order successor 52. Now, 50 will be moved to the leaf of the tree,
which will simply be deleted.
binary search tree Deletion algorithm
Graph
A graph is a non-linear data structure that has a finite number of vertices and edges, and these
edges are used to connect the vertices. The vertices are used to store the data elements, while the
edges represent the relationship between the vertices. A graph is used in various real-world
problems like telephone networks, circuit networks, social networks like LinkedIn, Facebook. In
the case of facebook, a single user can be considered as a node, and the conn ection of a user with
others is known as edges.
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.
Graph Terminologies
A graph is a set of points, called nodes or vertices, which are interconnected by a set of lines
called edges.
An edge is the mathematical term for a line that connects two vertices. Many edges can be formed
from a single vertex. Without a vertex, an edge cannot be formed. There must be a starting vertex
and an ending vertex for an edge
Here, ‘a’ and ‘b’ are the two vertices and the link between them is called an edge.
• In a graph, two vertices are said to be adjacent, if there is an edge between the two
vertices. Here, the adjacency of vertices is maintained by the single edge that is
connecting those two vertices.
• In a graph, two edges are said to be adjacent, if there is a common vertex
between the two edges. Here, the adjacency of edges is maintained by the single
vertex that is connecting two edges.
In the above graph, V is a vertex for which it has an edge (V, V) forming a loop.
In this graph, there are two loops which are formed at vertex a, and vertex b .
Parallel edges
In a graph, if a pair of vertices is connected by more than one edge, then those edges are called
parallel edges.
In the above graph, ‘a’ and ‘b’ are the two vertices which are connected by two edges ‘ab’ and ‘ab’
between them. So, it is called as a parallel edge.
Isolated vertex
Here, the vertex 'a' and vertex 'b' has a no connectivity between each other and also to any other
vertices. So, the degree of both the vertices 'a' and 'b' are zero. These are also called as isolated
vertices.
Degree of vertex
In graph theory , the degree of a vertex is the number of edges connecting it. In the example
below, vertex a has degree 5, and the rest have degree 1. A vertex with degree 1 is called an "end
vertex"
In the above Undirected Graph,
• deg(a) = 2, as there are 2 edges meeting at vertex 'a'.
• deg(b) = 3, as there are 3 edges meeting at vertex 'b'.
• deg(c) = 1, as there is 1 edge formed at vertex 'c'
So 'c' is a pendent vertex.
• deg(d) = 2, as there are 2 edges meeting at vertex 'd'.
• deg(e) = 0, as there are 0 edges formed at vertex 'e'.
So 'e' is an isolated vertex.
subgraph
A subgraph G of a graph is graph G’ whose vertex set and edge set subsets of the graph G. In simple
words a graph is said to be a subgraph if it is a part of another graph .
A subgraph with no common vertex is called a vertex disjoint subgraph of the parent graph G.
Since the vertices in a vertex disjoint graph cannot have a common edge, a vertex disjoint
subgraph will always be an edge-disjoint subgraph.
Paths and Cycles
Walk:
A walk can be defined as a sequence of edges and vertices of a graph. When we have a graph
and traverse it, then that traverse will be known as a walk. In a walk, there can be repeated
edges and vertices. The number of edges which is covered in a walk will be known as the
Length of the walk. In a graph, there can be more than one walk.
So, for a walk, the following two points are important, which are described as follows:
In the above graph, there can be many walks, but some of them are described as follows:
1. A, B, C, E, D (Number of length = 4)
2. D, B, A, C, E, D, C (Number of length = 7)
3. E, C, B, A, C, E, D (Number of length = 6)
Open Walk:
A walk will be known as an open walk in the graph theory if the vertices at which the walk starts
and ends are different. That means for an open walk, the starting vertex and ending vertex must
be different. In an open walk, the length of the walk must be more than 0.
Closed Walk:
A walk will be known as a closed walk in the graph theory if the vertices at which the walk starts
and ends are identical. That means for a closed walk, the starting vertex and ending vertex must
be the same. In a closed walk, the length of the walk must be more than 0.
1. Closed walk = A, B, C, D, E, C, A
2. Open walk = A, B, C, D, E, C
Paths
A path is a type of open walk where neither edges nor vertices are allowed to repeat. There is a
possibility that only the starting vertex and ending vertex are not same in a path. In an open walk,
the length of the walk must be more than 0.
So, for a path, the following two points are important, which are described as follows:
Path: F, H, C, A, B, D
Cycle:
A closed path in the graph theory is also known as a Cycle. A cycle is a type of closed walk
where neither edges nor vertices are allowed to repeat. There is a possibility that only the starting
vertex and ending vertex are the same in a cycle.
So, for a cycle, the following two points are important, which are described as follows:
Cycle: A, B, D, C, A
Types of Graphs
Directed Graphs
A graph whose all edges are directed by arrows is known as a directed graph. They are also
known as digraphs .
Undirected Graphs
A graph whose edges are not directed by arrows is known as an undirected graph.
Simple
A graph that is undirected and has no parallel edges or loops is known as a simple graph.
A simple graph with n vertices has the degree of every vertex is at most n-1.
Complete Graphs
A complete graph is a graph in which each pair of graph vertices is connected by an edge. A
complete graph with n number of vertices contains exactly nC2 edges and is represented by Kn.
In the above image we see that each vertex in the graph is connected with all the remaining vertices
through exactly one edge hence both graphs are complete graphs.
Connected Graph
A connected graph is a graph where we can visit from any one vertex to an y other vertex. In a
connected graph, there is at least one edge or path that exists between every pair of vertices.
Disconnected Graphs
A disconnected graph is a graph in which no path exists between every pair of vertices.
Cyclic Graphs
For a graph to be called a cyclic graph, it should consist of at least one cycle. If a graph has a
minimum of one cycle present, it is called a cyclic graph.
The graph shown in the image has two cycles present, satisfying the required condition for a graph
to be cyclic, thus making it a cyclic graph.
Acyclic Graphs
A graph is called an acyclic graph if zero cycles are present, and an acyclic graph is the
complete opposite of a cyclic graph.
The graph shown in the above image is acyclic because it has zero cycles present in it. That means
if we begin traversing the graph from vertex B, then a single path doesn't exist that will traverse all
the vertices and end at the same vertex that is vertex B.
Bipartite Graph
Here,
A bipartite graph where every vertex of set X is joined to every vertex of set Y is called as
complete bipartite graph.
Here,
• A graph in which we can visit f rom any one vertex to any other vertex is called as a connected
graph.
• In connected graph, at least one path exists between every p air of vertices.
Here,
• In this graph, we can visit from any one vertex to any other vertex.
• There exists at least one path between every pair of vertices.
• Therefore, it is a connected graph .
Disconnected Graphs
A graph in which there does not exist any path between at least one pair of vertices is called as a
disconnected graph.
Regular Graphs
• A graph in which degree of all the vertices is same is called as a regular graph.
• If all the vertices in a graph are of degree ‘k’, then it is called as a “ k-regular graph “.
In these graphs,
In the above figure, we can see that there is a linked list or adjacency list for every node of the
graph. From vertex A, there are paths to vertex B and vertex D. These nodes are linked to nodes A
in the given adjacency list.
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 the last node of the list.
Now, consider the directed graph, and let's see the adjacency list representation of that graph .
Now, consider the weighted directed graph, and let's see the adjacency list representation of that
graph.
In the case of a weighted directed graph, each node contains an extra field that is called the weight
of the node.
In graph theory, a graph representation is a technique to store graph into the memory of
computer.
To represent a graph, we just need the set of vertices, and for each vertex the neighbours of
the vertex (vertices which is directly connected to it by an edge). If it is a weighted graph, then
the weight will be associated with each edge.
Adjacency Matrix
o It is used to represent which nodes are adjacent to each other. i.e., is there any edge
connecting nodes to a graph.
o If there is any weighted graph then instead of 1s and 0s, we can store the weight of the
edge.
Example
In the above examples, 1 represents an edge from row vertex to column vertex, and 0 represents no
edge from row vertex to column vertex.
Undirected weighted graph representation
Cons: It takes a lot of space and time to visit all the neighbours of a vertex, we have to traverse all
the vertices in the graph, which takes quite some time.
Incidence Matrix
In Incidence matrix representation, graph can be represented using a matrix of size:
o 1 is used to represent row edge which is connected as outgoing edge to column vertex.
o -1 is used to represent row edge which is connected as incoming edge to column vertex.
Example
Graph traversal is a technique used for searching a vertex in a graph. The graph traversal is also
used to decide the order of vertices is visited in the search process. A graph traversal finds the edges
to be used in the search process without creating loops. That means using graph traversal we visit
all the vertices of the graph without getting into looping path.
There are two graph traversal techniques and they are as follows...
BFS algorithm
A standard BFS implementation puts each vertex of the graph into one of two categories:
1. Visited
2. Not Visited
The purpose of the algorithm is to mark each vertex as visited while avoiding cycles.
1. Start by putting any one of the graph's vertices at the back of a queu e.
2. Take the front item of the queue and add it to the visited list.
3. Create a list of that vertex's adjacent nodes. Add the ones which aren't in the
visited list to the back of the queue.
The graph might have two different disconnected parts so to make sure that we cover
every vertex, we can also run the BFS algorithm on every node
Let's see how the Breadth First Search algorithm works with an example. We use an undirected
graph with 5 vertices.
We start from vertex 0, the BFS algorithm starts by putting it in the Visited list and putting all its
adjacent vertices in the stack.
Next, we visit the element at the front of queue i.e. 1 and go to its adjacent nodes. Since 0 has
already been visited, we visit 2 instead.
Vertex 2 has an unvisited adjacent vertex in 4, so we add that to the back of the queue and visit 3,
which is at the front of the queue.
Visit 2 which was added to queue earlier to add its neighbours
Only 4 remains in the queue since the only adjacent node of 3 i.e. 0 is already visited. We visit it.
Visit last remaining item in the queue to check if it has unvisited neighbours
Depth first Search
Depth first Search or Depth first traversal is a recursive algorithm for searching all the vertices of a
graph or tree data structure. Traversal means visiting all the nodes of a graph.
A standard DFS implementation puts each vertex of the graph into one of two categories:
1. Visited
2. Not Visited
The purpose of the algorithm is to mark each vertex as visited while avoiding cycles.
2. Take the top item of the stack and add it to the visited list.
3. Create a list of that vertex's adjacent nodes. Add the ones which aren't in the visited list to
the top of the stack.
Let's see how the Depth First Search algorithm works with an example. We use an undirected graph
with 5 vertices.
We start from vertex 0, the DFS algorithm starts by putting it in the Visited list and putting all its
adjacent vertices in the stack.
We start from vertex 0, the DFS algorithm starts by putting it in the Visited list and putting all its
adjacent vertices in the stack.
Next, we visit the element at the top of stack i.e. 1 and go to its adjacent nodes. Since 0 has already
been visited, we visit 2 instead.
Vertex 2 has an unvisited adjacent vertex in 4, so we add that to the top of the stack and visit it .
After we visit the last element 3, it doesn't have any unvisited adjacent nodes, so we have completed
the Depth First Traversal of the graph.