Data Structure and Algorithms
Data Structure and Algorithms
If arrays accommodate similar types of data types, linked lists consist of elements with different data
types that are also arranged sequentially.
A linked list is a collection of “nodes” connected together via links. These nodes consist of the data to be
stored and a pointer to the address of the next node within the linked list. In the case of arrays, the size is
limited to the definition, but in linked lists, there is no defined size. Any amount of data can be stored in it
and can be deleted from it.
• Singly Linked List − The nodes only point to the address of the next node in the list.
• Doubly Linked List − The nodes point to the addresses of both previous and next nodes.
• Circular Linked List − The last node in the list will point to the first node in the list. It can
either be singly linked or doubly linked.
As per the above illustration, following are the important points to be considered.
Since the last node and the first node of the circular linked list are connected, the traversal in this linked
list will go on forever until it is broken.
Insertion Operation
Adding a new node in linked list is a more than one step activity. We shall learn this with diagrams here.
First, create a node using the same structure and find the location where it has to be inserted.
Imagine that we are inserting a node B (NewNode), between A (LeftNode) and C (RightNode). Then point
B.next to C −
NewNode.next −> RightNode;
It should look like this −
Now, the next node at the left should point to the new node.
LeftNode.next −> NewNode;
This will put the new node in the middle of the two. The new list should look like this −
Insertion in linked list can be done in three different ways. They are explained as follows −
Insertion at Beginning
In this operation, we are adding an element at the beginning of the list.
n this operation, we are adding an element at the beginning of the list.
Algorithm
1. START
2. Create a node to store the data
3. Check if the list is empty
4. If the list is empty, add the data to the node and assign the head pointer to it.
5 If the list is not empty, add the data to a node and link to the current head. Assign the head to the newly added
node.
6. END
Example
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
}
Output
Linked List:
[ 50 44 30 22 12 ]
Insertion at Ending
In this operation, we are adding an element at the ending of the list.
Algorithm
1. START
2. Create a new node and assign the data
3. Find the last node
4. Point the last node to new node
5. END
Example
Following are the implementations of this operation in various programming languages
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
struct node *linkedlist = head;
// point it to old first node
while(linkedlist->next != NULL)
linkedlist = linkedlist->next;
// print list
printList();
}
Output
Linked List:
[ 12 22 30 44 50 ]
Insertion at a Given Position
In this operation, we are adding an element at any position within the list.
Algorithm
1. START
2. Create a new node and assign data to it
3. Iterate until the node at position is found
4. Point first to new first node
5. END
Example
Following are the implementations of this operation in various programming languages
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
}
Output
Linked List:
[ 22 12 30 ]
Deletion Operation
Deletion is also a more than one step process. We shall learn with pictorial representation. First, locate
the target node to be removed, by using searching algorithms.
The left (previous) node of the target node now should point to the next node of the target node −
LeftNode.next −> TargetNode.next;
This will remove the link that was pointing to the target node. Now, using the following code, we will
remove what the target node is pointing at.
TargetNode.next −> NULL;
We need to use the deleted node. We can keep that in memory otherwise we can simply deallocate
memory and wipe off the target node completely.
Similar steps should be taken if the node is being inserted at the beginning of the list. While inserting it
at the end, the second last node of the list should point to the new node and the new node will point to
NULL.
Deletion in linked lists is also performed in three different ways. They are as follows −
Deletion at Beginning
In this deletion operation of the linked, we are deleting an element from the beginning of the list. For this,
we point the head to the second node.
Algorithm
1. START
2. Assign the head pointer to the next node in the list
3. END
Example
Following are the implementations of this operation in various programming languages
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
deleteatbegin();
printf("\nLinked List after deletion: ");
// print list
printList();
}
Output
Linked List:
[ 55 40 30 22 12 ]
Linked List after deletion:
[ 40 30 22 12 ]
Deletion at Ending
In this deletion operation of the linked, we are deleting an element from the ending of the list.
Algorithm
1. START
2. Iterate until you find the second last element in the list.
3. Assign NULL to the second last element in the list.
4. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
deleteatend();
printf("\nLinked List after deletion: ");
// print list
printList();
}
Output
Linked List:
[ 55 40 30 22 12 ]
Linked List after deletion:
[ 55 40 30 22 ]
Deletion at a Given Position
In this deletion operation of the linked, we are deleting an element at any position of the list.
Algorithm
1. START
2. Iterate until find the current node at position in the list
3. Assign the adjacent node of current node in the list to its previous node.
4. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
deletenode(30);
printf("\nLinked List after deletion: ");
// print list
printList();
}
Output
Linked List:
[ 55 40 30 22 12 ]
Linked List after deletion:
[ 55 40 22 12 ]
Reverse Operation
This operation is a thorough one. We need to make the last node to be pointed by the head node and
reverse the whole linked list.
First, we traverse to the end of the list. It should be pointing to NULL. Now, we shall make it point to its
previous node −
We have to make sure that the last node is not the last node. So we'll have some temp node, which looks
like the head node pointing to the last node. Now, we shall make all left side nodes point to their previous
nodes one by one.
Except the node (first node) pointed by the head node, all nodes should point to their predecessor, making
them their new successor. The first node will point to NULL.
We'll make the head node point to the new first node by using the temp node.
Algorithm
Step by step process to reverse a linked list is as follows −
1 START
2. We use three pointers to perform the reversing: prev, next, head.
3. Point the current node to head and assign its next value to the prev node.
4. Iteratively repeat the step 3 for all the nodes in the list.
5. Assign head to the prev node.
Example
Following are the implementations of this operation in various programming languages
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
reverseList(&head);
printf("\nReversed Linked List: ");
printList();
}
Output
Linked List:
[ 55 40 30 22 12 ]
Reversed Linked List:
[ 12 22 30 40 55 ]
Search Operation
Searching for an element in the list using a key element. This operation is done in the same way as array
search; comparing every element in the list with the key element given.
Algorithm
1 START
2 If the list is not empty, iteratively check if the list contains the key
3 If the key element is not present in the list, unsuccessful search
4 END
Example
Following are the implementations of this operation in various programming languages
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
k = searchlist(30);
if (k == 1)
printf("\nElement is found");
else
printf("\nElement is not present in the list");
}
Output
Linked List:
[ 55 40 30 22 12 ]
Element is found
Traversal Operation
The traversal operation walks through all the elements of the list in an order and displays the elements
in that order.
Algorithm
1. START
2. While the list is not empty and did not reach the end of the list, print the data in each node
3. END
Example
Following are the implementations of this operation in various programming languages
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
// print list
printList();
}
Output
Linked List:
[ 30 22 12 ]
Data Structure Doubly Linked List
Doubly Linked List is a variation of Linked list in which navigation is possible in both ways, either forward
and backward easily as compared to Single Linked List. Following are the important terms to understand
the concept of doubly linked list.
• Link − Each link of a linked list can store a data called an element.
• Next − Each link of a linked list contains a link to the next link called Next.
• Prev − Each link of a linked list contains a link to the previous link called Prev.
• Linked List − A Linked List contains the connection link to the first link called First and to
the last link called Last.
As per the above illustration, following are the important points to be considered.
• Doubly Linked List contains a link element called first and last.
• Each link carries a data field(s) and a link field called next.
• Each link is linked with its next link using its next link.
• Each link is linked with its previous link using its previous link.
• The last link carries a link as null to mark the end of the list.
Basic Operations
Following are the basic operations supported by a list.
Algorithm
1. START
2. Create a new node with three variables: prev, data, next.
3. Store the new data in the data variable
4. If the list is empty, make the new node as head.
5. Otherwise, link the address of the existing first node to the next variable of the new node, and assign null to the
prev variable.
6. Point the head to the new node.
7. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
int key;
struct node *next;
struct node *prev;
};
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if(isEmpty()) {
Output
Doubly Linked List: (6,56) (5,40) (4,1) (3,30) (2,20) (1,10)
Deletion at the Beginning
This deletion operation deletes the existing first nodes in the doubly linked list. The head is shifted to the
next node and the link is removed.
Algorithm
1. START
2. Check the status of the doubly linked list
3. If the list is empty, deletion is not possible
4. If the list is not empty, the head pointer is shifted to the next node.
5. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
int key;
struct node *next;
struct node *prev;
};
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if(isEmpty()) {
Algorithm
1. START
2. If the list is empty, add the node to the list and point the head to it.
3. If the list is not empty, find the last node of the list.
4. Create a link between the last node in the list and the new node.
5. The new node will point to NULL as it is the new last node.
6. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
int key;
struct node *next;
struct node *prev;
};
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if(isEmpty()) {
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if(isEmpty()) {
Output
Doubly Linked List: (4,1) (3,30) (2,20) (1,10) (5,40) (6,56)
Data Structure - Circular Linked List
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.
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 cases of singly as well as doubly
linked list.
• The first link's previous points to the last of the list in case of doubly linked list.
Basic Operations
Following are the important operations supported by a circular list.
Algorithm
1. START
2. Check if the list is empty
3. If the list is empty, add the node and point the head to this node
4. If the list is not empty, link the existing head as the next node to the new node.
5. Make the new node as the new head.
6. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
int key;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
bool isEmpty(){
return head == NULL;
}
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if (isEmpty()) {
head = link;
head->next = head;
} else {
//print list
printList();
}
Output
Circular Linked List:
[ (6,56) (5,40) (4,1) (3,30) (2,20) ]
Deletion Operation
The Deletion operation in a Circular linked list removes a certain node from the list. The deletion operation
in this type of lists can be done at the beginning, or a given position, or at the ending.
Algorithm
1. START
2. If the list is empty, then the program is returned.
3. If the list is not empty, we traverse the list using a current pointer that is set to the head pointer and create
another pointer previous that points to the last node.
4. Suppose the list has only one node, the node is deleted by setting the head pointer to NULL.
5. If the list has more than one node and the first node is to be deleted, the head is set to the next node and the
previous is linked to the new head.
6. If the node to be deleted is the last node, link the preceding node of the last node to head node.
7. If the node is neither first nor last, remove the node by linking its preceding node to its succeeding node.
8. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
int key;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
bool isEmpty(){
return head == NULL;
}
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if (isEmpty()) {
head = link;
head->next = head;
} else {
//print list
printList();
deleteFirst();
printf("\nList after deleting the first item: ");
printList();
}
Output
Circular Linked List: (6,56) (5,40) (4,1) (3,30) (2,20)
List after deleting the first item: (5,40) (4,1) (3,30) (2,20)
Display List Operation
The Display List operation visits every node in the list and prints them all in the output.
Algorithm
1. START
2. Walk through all the nodes of the list and print them
3. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
int key;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;
bool isEmpty(){
return head == NULL;
}
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if (isEmpty()) {
head = link;
head->next = head;
} else {
//print list
printList();
}
Output
Circular Linked List:
[ (6,56) (5,40) (4,1) (3,30) (2,20) ]
Data Structure and Algorithms - Stack
A stack is an Abstract Data Type (ADT), that is popularly used in most programming languages. It is
named stack because it has the similar operations as the real-world stacks, for example – a pack of cards
or a pile of plates, etc.
The stack follows the LIFO (Last in - First out) structure where the last element inserted would be the first
element deleted.
Stack Representation
A Stack ADT allows all data operations at one end only. At any given time, we can only access the top
element of a stack.
A stack can be implemented by means of Array, Structure, Pointer, and Linked List. Stack can either be a
fixed size one or it may have a sense of dynamic resizing. Here, we are going to implement stack using
arrays, which makes it a fixed size stack implementation.
Stack uses pointers that always point to the topmost element within the stack, hence called as
the top pointer.
Insertion: push()
push() is an operation that inserts elements into the stack. The following is an algorithm that describes
the push() operation in a simpler way.
Algorithm
1 − Checks if the stack is full.
2 − If the stack is full, produces an error and exit.
3 − If the stack is not full, increments top to point next empty space.
4 − Adds data element to the stack location, where top is pointing.
5 − Returns success.
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;
/* Main function */
int main(){
int i;
push(44);
push(10);
push(62);
push(123);
push(15);
printf("Stack Elements: \n");
Output
Stack Elements:
44 10 62 123 15 0 0 0
Note − In Java we have used to built-in method push() to perform this operation.
Deletion: pop()
pop() is a data manipulation operation which removes elements from the stack. The following pseudo
code describes the pop() operation in a simpler way.
Algorithm
1 − Checks if the stack is empty.
2 − If the stack is empty, produces an error and exit.
3 − If the stack is not empty, accesses the data element at which top is pointing.
4 − Decreases the value of top by 1.
5 − Returns success.
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;
/* Main function */
int main(){
int i;
push(44);
push(10);
push(62);
push(123);
push(15);
printf("Stack Elements: \n");
Output
Stack Elements:
44 10 62 123 15 0 0 0
Elements popped:
15 123 62 10 44
Note − In Java we are using the built-in method pop().
peek()
The peek() is an operation retrieves the topmost element within the stack, without deleting it. This
operation is used to check the status of the stack with the help of the top pointer.
Algorithm
1. START
2. return the element at the top of the stack
3. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;
/* Main function */
int main(){
int i;
push(44);
push(10);
push(62);
push(123);
push(15);
printf("Stack Elements: \n");
Output
Stack Elements:
44 10 62 123 15 0 0 0
Element at top of the stack: 15
isFull()
isFull() operation checks whether the stack is full. This operation is used to check the status of the stack
with the help of top pointer.
Algorithm
1. START
2. If the size of the stack is equal to the top position of the stack, the stack is full. Return 1.
3. Otherwise, return 0.
4. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;
/* Main function */
int main(){
printf("Stack full: %s\n" , isfull()?"true":"false");
return 0;
}
Output
Stack full: false
isEmpty()
The isEmpty() operation verifies whether the stack is empty. This operation is used to check the status of
the stack with the help of top pointer.
Algorithm
1. START
2. If the top value is -1, the stack is empty. Return 1.
3. Otherwise, return 0.
4. END
Example
Following are the implementations of this operation in various programming languages −
#include <stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;
/* Main function */
int main() {
printf("Stack empty: %s\n" , isempty()?"true":"false");
return 0;
}
Output
Stack empty: true
Data Structure and Algorithms - Hash Table
Hash Table is a data structure which stores data in an associative manner. In a hash table, data is stored
in an array format, where each data value has its own unique index value. Access of data becomes very
fast if we know the index of the desired data.
Thus, it becomes a data structure in which insertion and search operations are very fast irrespective of the
size of the data. Hash Table uses an array as a storage medium and uses hash technique to generate an
index where an element is to be inserted or is to be located from.
Hashing
Hashing is a technique to convert a range of key values into a range of indexes of an array. We're going
to use modulo operator to get a range of key values. Consider an example of hash table of size 20, and
the following items are to be stored. Item are in the (key,value) format.
• (1,20)
• (2,70)
• (42,80)
• (4,25)
• (12,44)
• (14,32)
• (17,11)
• (13,78)
• (37,98)
1 1 1 % 20 = 1 1
2 2 2 % 20 = 2 2
3 42 42 % 20 = 2 2
4 4 4 % 20 = 4 4
5 12 12 % 20 = 12 12
6 14 14 % 20 = 14 14
7 17 17 % 20 = 17 17
8 13 13 % 20 = 13 13
9 37 37 % 20 = 17 17
Linear Probing
As we can see, it may happen that the hashing technique is used to create an already used index of the
array. In such a case, we can search the next empty location in the array by looking into the next cell until
we find an empty cell. This technique is called linear probing.
Sr.No. Key Hash Array Index After Linear Probing, Array Index
1 1 1 % 20 = 1 1 1
2 2 2 % 20 = 2 2 2
3 42 42 % 20 = 2 2 3
4 4 4 % 20 = 4 4 4
5 12 12 % 20 = 12 12 12
6 14 14 % 20 = 14 14 14
7 17 17 % 20 = 17 17 17
8 13 13 % 20 = 13 13 13
9 37 37 % 20 = 17 17 18
Basic Operations
Following are the basic primary operations of a hash table.
DataItem
Define a data item having some data and key, based on which the search is to be conducted in a hash
table.
struct DataItem {
int data;
int key;
};
Hash Method
Define a hashing method to compute the hash code of the key of the data item.
Search Operation
Whenever an element is to be searched, compute the hash code of the key passed and locate the element
using that hash code as index in the array. Use linear probing to get the element ahead if the element is
not found at the computed hash code.
Example
while(hashArray[hashIndex] != NULL) {
if(hashArray[hashIndex]->key == key)
return hashArray[hashIndex];
++hashIndex;
hashIndex %= SIZE;
}
return NULL;
Insert Operation
Whenever an element is to be inserted, compute the hash code of the key passed and locate the index
using that hash code as an index in the array. Use linear probing for empty location, if an element is found
at the computed hash code.
Example
item->data = data;
item->key = key;
++hashIndex;
hashIndex %= SIZE;
hashArray[hashIndex] = item;
Delete Operation
Whenever an element is to be deleted, compute the hash code of the key passed and locate the index
using that hash code as an index in the array. Use linear probing to get the element ahead if an element
is not found at the computed hash code. When found, store a dummy item there to keep the performance
of the hash table intact.
Example
while(hashArray[hashIndex] !=NULL) {
if(hashArray[hashIndex]->key == key) {
hashArray[hashIndex] = dummyItem;
return temp;
++hashIndex;
hashIndex %= SIZE;
return NULL;