Data Structure Module - 1
Data Structure Module - 1
A data structure is a way of storing and organizing data in a computer’s memory that it could make the
data quickly available to the processor for required computation.
A data structure should be seen as a logical concept that must address two fundamental concerns.
It can be classified as
Linear data structures can be constructed as a continuous arrangement of data elements in the memory.
For example : Array, Stack, Queue, Tables, List, and Linked Lists.
1. Insert an element
2. Delete an element
3. Traverse
Non-linear data structure can be constructed as a collection of randomly distributed set of data item
joined together by using a special pointer (tag).
1. Insert elements
2. Delete elements
Array:
An array is a linear data structure that collects elements of the same data type and stores them
in contiguous and adjacent memory locations. Arrays work on an index system starting from 0 to
(n-1), where n is the size of the array.
One-Dimensional Arrays:
You can imagine a 1d array as a row, where elements are stored one after another.
Multi-Dimensional Arrays:
These multi-dimensional arrays are again of two types. They are:
Two-Dimensional Arrays:
You can imagine it like a table where each cell contains elements.
o Each element in an array is of the same data type and carries the same size that is
4 bytes.
o Elements in the array are stored at contiguous memory locations from which the
first element is stored at the smallest memory location.
o Elements of the array can be randomly accessed since we can calculate the address
of each element of the array with the given base address and the size of the data
element.
Arrays are typically defined with square brackets with the size of the arrays as its argument and
specifying its type.
Operations on an Array:
• Insertion
• Deletion
• Searching
• Sorting
Insertion operation
This operation is performed to insert one or more elements into the array. As per the
requirements, an element can be added at the beginning, end, or at any index of the array.
Now, let's see the implementation of inserting an element into the array.
1. #include <stdio.h>
2. int main()
3. {
4. int arr[20] = { 18, 30, 15, 70, 12 };
5. int i, x, pos, n = 5;
6. printf("Array elements before insertion\n");
7. for (i = 0; i < n; i++)
8. printf("%d ", arr[i]);
9. printf("\n");
10.
11. x = 50; // element to be inserted
12. pos = 4;
13. n++;
14.
15. for (i = n-1; i >= pos; i--)
16. arr[i] = arr[i - 1];
17. arr[pos - 1] = x;
18. printf("Array elements after insertion\n");
19. for (i = 0; i < n; i++)
20. printf("%d ", arr[i]);
21. printf("\n");
22. return 0;
23. }
Output
Deletion operation
As the name implies, this operation removes an element from the array and then
reorganizes all of the array elements.
1. #include <stdio.h>
2.
3. void main() {
4. int arr[] = {18, 30, 15, 70, 12};
5. int k = 30, n = 5;
6. int i, j;
7.
8. printf("Given array elements are :\n");
9.
10. for(i = 0; i<n; i++) {
11. printf("arr[%d] = %d, ", i, arr[i]);
12. }
13.
14. j = k;
15.
16. while( j < n) {
17. arr[j-1] = arr[j];
18. j = j + 1;
19. }
20.
21. n = n -1;
22.
23. printf("\nElements of array after deletion:\n");
24.
25. for(i = 0; i<n; i++) {
26. printf("arr[%d] = %d, ", i, arr[i]);
27. }
28. }
Output
Search operation
This operation is performed to search an element in the array based on the value or index.
1. #include <stdio.h>
2.
3. void main() {
4. int arr[5] = {18, 30, 15, 70, 12};
5. int item = 70, i, j=0 ;
6.
7. printf("Given array elements are :\n");
8.
9. for(i = 0; i<5; i++) {
10. printf("arr[%d] = %d, ", i, arr[i]);
11. }
12. printf("\nElement to be searched = %d", item);
13. while( j < 5){
14. if( arr[j] == item ) {
15. break;
16. }
17.
18. j = j + 1;
19. }
20.
21. printf("\nElement %d is found at %d position", item, j+1);
22. }
Output
Update operation
This operation is performed to update an existing array element located at the given
index.
1. #include <stdio.h>
2.
3. void main() {
4. int arr[5] = {18, 30, 15, 70, 12};
5. int item = 50, i, pos = 3;
6.
7. printf("Given array elements are :\n");
8.
9. for(i = 0; i<5; i++) {
10. printf("arr[%d] = %d, ", i, arr[i]);
11. }
12.
13. arr[pos-1] = item;
14. printf("\nArray elements after updation :\n");
15.
16. for(i = 0; i<5; i++) {
17. printf("arr[%d] = %d, ", i, arr[i]);
18. }
19. }
Output
Advantages of Array
o Array provides the single name for the group of variables of the same type. Therefore, it is
easy to remember the name of all the elements of an array.
o Traversing an array is a very simple process; we just need to increment the base address
of the array in order to visit each element one by one.
o Any element in the array can be directly accessed by using the index.
Disadvantages of Array
o Array is homogenous. It means that the elements with similar data type can be stored in
it.
o In array, there is static memory allocation that is size of an array cannot be altered.
o There will be wastage of memory if we store less number of elements than the declared
size.
Sparse Matrix
A matrix is a two-dimensional data object made of m rows and n columns,
therefore having total m x n values. If most of the elements of the matrix have 0
value, then it is called a sparse matrix.
Example:
0 0 3 0 4
0 0 5 7 0
0 0 0 0 0
0 2 6 0 0
Representing a sparse matrix by a 2D array leads to wastage of lots of memory
as zeroes in the matrix are of no use in most of the cases. So, instead of storing
zeroes with non-zero elements, we only store non-zero elements. This means
storing non-zero elements with triples- (Row, Column, value).
Sparse Matrix Representations can be done in many ways following are two
common representations:
1. Array representation
2. Linked list representation
Stack:
A stack is an Abstract Data Type (ADT), commonly used in most programming languages. It is
named stack as it behaves like a real-world stack, for example – a deck of cards or a pile of
plates, etc. A real-world stack allows operations at one end only.
This feature makes it LIFO data structure. LIFO stands for Last-in-first-out. Here, the element
which is placed (inserted or added) last, is accessed first. In stack terminology, insertion
operation is called PUSH operation and removal operation is called POP operation.
Stack Representation
The following diagram depicts a stack and its operations −
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.
Basic Operations
Stack operations may involve initializing the stack, using it and then de-initializing it. Apart
from these basic stuffs, a stack is used for the following two primary operations −
• push() − Pushing (storing) an element on the stack.
• pop() − Removing (accessing) an element from the stack.
When data is PUSHed onto stack.
To use a stack efficiently, we need to check the status of stack as well. For the same
purpose, the following functionality is added to stacks −
• peek() − get the top data element of the stack, without removing it.
• isFull() − check if stack is full.
• isEmpty() − check if stack is empty.
At all times, we maintain a pointer to the last PUSHed data on the stack. As this pointer
always represents the top of the stack, hence named top. The top pointer provides top
value of the stack without actually removing it.
First we should learn about procedures to support stack functions −
peek()
Algorithm of peek() function −
begin procedure peek
return stack[top]
end procedure
isfull()
Algorithm of isfull() function −
begin procedure isfull
end procedure
isempty()
Algorithm of isempty() function −
begin procedure isempty
end procedure
Push Operation
The process of putting a new data element onto stack is known as a Push Operation.
Push operation involves a series of steps −
• Step 1 − Checks if the stack is full.
• Step 2 − If the stack is full, produces an error and exit.
• Step 3 − If the stack is not full, increments top to point next empty space.
• Step 4 − Adds data element to the stack location, where top is pointing.
• Step 5 − Returns success.
void push(int data) {
if(!isFull()) {
top = top + 1;
stack[top] = data;
} else {
printf("Could not insert data, Stack is full.\n");
}
}
Pop Operation
Accessing the content while removing it from the stack, is known as a Pop Operation. In
an array implementation of pop() operation, the data element is not actually removed,
instead top is decremented to a lower position in the stack to point to the next value. But
in linked-list implementation, pop() actually removes data element and deallocates
memory space.
A Pop operation may involve the following steps −
• Step 1 − Checks if the stack is empty.
• Step 2 − If the stack is empty, produces an error and exit.
• Step 3 − If the stack is not empty, accesses the data element at which top is
pointing.
• Step 4 − Decreases the value of top by 1.
• Step 5 − Returns success.
int pop(int data) {
if(!isempty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Could not retrieve data, Stack is empty.\n");
}
}
Queue :
The Queue in data structure is an ordered, linear sequence of items. It is a FIFO (First In
First Out) data structure, which means that we can insert an item to the rear end of the
queue and remove from the front of the queue only. A Queue is a sequential data type,
unlike an array, in an array, we can access any of its elements using indexing, but we can
only access the element at the front of the queue at a time.
Queue Representation
A Queue in data structure can be accessed from both of its sides (at the front for
deletion and back for insertion).
The following diagram tries to explain the queue representation as a data structure-
Working of Queue
The Queue in data structure uses the FIFO (First In First Out) approach. Initially, we will
set a front pointer to keep track of the front most element of the queue. Then the queue
is initialized to -1 as its front, as we will add (enqueue) elements to the queue, the front
gets updated to point to its front most element and if we remove (dequeue) elements
from the queue, the front gets reduced.
We can use queue to perform its main two operations: Enqueue and Dequeue, other
operations being Peek, isEmpty and isFull.
Queue operations
Enqueue
The Enqueue operation is used to add an element to the front of the queue.
Dequeue
The Dequeue operation is used to remove an element from the rear of the queue.
Peek
The Peek operation is used to return the front most element of the queue.
isFull
1. Check if the number of elements in the queue (size) is equal to the capacity, if
yes, return True.
2. Return False.
isEmpty
1. Check if the number of elements in the queue (size) is equal to 0, if yes, return
True.
2. Return False.
Program/Source Code
Here is source code of the C Program to implement a queue using array.
1. /*
2. * C Program to Implement a Queue using an Array
3. */
4. #include <stdio.h>
5.
6. #define MAX 50
7.
8. void insert();
9. void delete();
10. void display();
11. int queue_array[MAX];
12. int rear = - 1;
13. int front = - 1;
14. main()
15. {
16. int choice;
17. while (1)
18. {
19. printf("1.Insert element to queue \n");
20. printf("2.Delete element from queue \n");
21. printf("3.Display all elements of queue \n");
22. printf("4.Quit \n");
23. printf("Enter your choice : ");
24. scanf("%d", &choice);
25. switch (choice)
26. {
27. case 1:
28. insert();
29. break;
30. case 2:
31. delete();
32. break;
33. case 3:
34. display();
35. break;
36. case 4:
37. exit(1);
38. default:
39. printf("Wrong choice \n");
40. } /* End of switch */
41. } /* End of while */
42. } /* End of main() */
43.
44. void insert()
45. {
46. int add_item;
47. if (rear == MAX - 1)
48. printf("Queue Overflow \n");
49. else
50. {
51. if (front == - 1)
52. /*If queue is initially empty */
53. front = 0;
54. printf("Inset the element in queue : ");
55. scanf("%d", &add_item);
56. rear = rear + 1;
57. queue_array[rear] = add_item;
58. }
59. } /* End of insert() */
60.
61. void delete()
62. {
63. if (front == - 1 || front > rear)
64. {
65. printf("Queue Underflow \n");
66. return ;
67. }
68. else
69. {
70. printf("Element deleted from queue is : %d\n",
queue_array[front]);
71. front = front + 1;
72. }
73. } /* End of delete() */
74.
75. void display()
76. {
77. int i;
78. if (front == - 1)
79. printf("Queue is empty \n");
80. else
81. {
82. printf("Queue is : \n");
83. for (i = front; i <= rear; i++)
84. printf("%d ", queue_array[i]);
85. printf("\n");
86. }
87. } /* End of display() */
Linked list
A linked list is a linear data structure that includes a series of connected nodes. Here,
each node stores the data and the address of the next node. For example,
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.
Linked lists can be of multiple types: singly, doubly, and circular linked list.
Let's see how each node of the linked list is represented. Each node consists:
• A data item
We wrap both the data item and the next node reference in a struct as:
struct node
{
int data;
struct node *next;
};
Each struct node has a data item and a pointer to another struct node. A
single linked list of three items can be formed by following code.
#include <stdio.h>
#include <stdlib.h>
// Creating a node
struct node {
int value;
struct node *next;
};
int main()
{
// 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;
// printing node-value
head = one;
printLinkedlist(head);
}
Many applications use LinkedList in computer science, let’s discuss basic LinkedList
functions.
create()
display()
• This function is used to display the entire LinkedList using a while loop
• We first check, if the head node is pointing to NULL or not, if the head node is
pointing to NULL, then it indicates that LinkedList is empty, so we return
• If LinkedList is not empty, we assign head node to a temp node and we use this
temp node to traverse over the LinkedList using a loop and print them
insert_begin()
• Initially, we create a temp node to scan the value then we check if LinkedList is
empty or not
• If LinkedList is empty, then the newly created node would be treated as a head
node
• If LinkedList is not empty, then we make the temp node point towards the current
head node and the head node to point towards the newly created node
insert_end()
• Firstly, we create a temp node to scan the value then we check if LinkedList is
empty or not
• If LinkedList is empty, then the newly created node would be inserted to
LinkedList
• If LinkedList is not empty, then we create a new node say ptr, by using ptr we
traverse till the end of LinkedList and insert the temp node at the end of
LinkedList
insert_pos()
• Here, we create a temp node to scan the value then we check if LinkedList is
empty or not
• If LinkedList empty, then we return
• If LinkedList is not empty, then we take input of node position from the user, if the
input is greater than the length of LinkedList, then we return
• If the input is in the range of length of LinkedList then, let's assume we have four
nodes A, B, C, D and we need to insert a node next to B, so, we just traverse till
node C and make node B point to node E and node E to point to node C.
delete_begin()
• This function checks if nodes are present in LinkedList or not, if nodes are not
present then we return
• If nodes are present then we make ahead node to point towards the second node
and store the address of the first node in a node say, temp
• By using the address stored in temp, we delete the first node from the memory
delete_end()
• This function checks if nodes are present in LinkedList or not, if nodes are not
present in LinkedList, then we return
• If nodes are present in LinkedList, then we create a temp node and assign a
head node value in it.
• By using this temp node, we traverse till last but one node of the LinkedList, and
then we store the address present in the next field in a node say ptr.
• Now, we delete the ptr from memory, such that the last node is deleted from
LinkedList
delete_pos()
Stack can also be represented by using a linked list. We know that in the case of arrays we face
a limitation , i.e , array is a data structure of limited size. Hence before using an array to
represent a stack we will have to consider an enough amount of space to suffice the memory
required by the stack.
However, a Linked List is a much more flexible data structure. Both the push and pop
operations can be performed on either ends.. But We prefer performing the Push and
pop operation at the beginning.
The Stack operations occur in constant time. But if we perform the push and pop
operations at the end of the linked list it takes time O(n).
• Head = 200.
• Top = 33.
struct n
{
int element;
struct n *nxt;
};
struct n *hd;
void main ()
{
int option=0;
while(option != 4)
{
printf("\nSelect from the following options\n1.Push\n2.Pop\n3.Show\n4.Exit
\nEnter one of your choices:");
scanf("%d",&option);
switch(option)
{
case 1:
{
Push();
break;
}
case 2:
{
pop();
break;
}
case 3:
{
display();
break;
}
case 4:
{
printf("Exit");
break;
}
default:
{
printf("\nKindly enter a valid option\n");
}
};
}
}
void Push ()
{
int element;
struct n *ptr = (struct n*)malloc(sizeof(struct n));
if(ptr == NULL)
{
printf("Stack full. Operation failed");
}
else
{
printf("Enter the element you want to insert: ");
scanf("%d",&element);
if(hd==NULL)
{
ptr->element = element;
ptr -> nxt = NULL;
hd=ptr;
}
else
{
ptr->element = element;
ptr->nxt = hd;
hd=ptr;
}
printf("Element is inserted");
}
}
void pop()
{
int num;
struct n *ptr;
if (hd == NULL)
{
printf("Not enough elements. Underflow!");
}
else
{
num = hd->element;
ptr = hd;
hd = hd->nxt;
free(ptr);
printf("Element deleted: %d",num);
}
}
void display()
{
int i;
struct n *ptr;
ptr=hd;
if(ptr == NULL)
{
printf("The stack is empty\n");
}
else
{
printf("The stack elements are as follows: \n");
while(ptr!=NULL)
{
printf("%d\n",ptr->element);
ptr = ptr->nxt;
}
}
}
Enqueue function
Enqueue function will add the element at the end of the linked list.
Using the rear pointer, we can track the last inserted element.
1. Declare a new node and allocate memory for it.
2. If front == NULL,
make both front and rear points to the new node.
3. Otherwise,
add the new node in rear->next.
make the new node as the rear node. i.e. rear = new node
/*
* Program : Queue using linked list
* Language : C
*/
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
void dequeue()
{
//used to free the first node after dequeue
struct node *temp;
if(front == NULL)
printf("Queue is Empty. Unable to perform dequeue\n");
else
{
//take backup
temp = front;
}
void printList()
{
struct node *temp = front;
while(temp)
{
printf("%d->",temp->data);
temp = temp->next;
}
printf("NULL\n");
}
int main()
{
enqueue(10);
enqueue(20);
enqueue(30);
printf("Queue :");
printList();
dequeue();
printf("After dequeue the new Queue :");
printList();
dequeue();
printf("After dequeue the new Queue :");
printList();
return 0;
}
Doubly Linked List
A doubly linked list is a type of linked list in which each node consists of 3
components:
• *prev - address of the previous node
• data - data item
• *next - address of next node
struct node {
int data;
struct node *next;
struct node *prev;
}
Let's add a node with value 6 at the beginning of the doubly linked list we
made above.
1. Create a new node
• allocate memory for newNode
• assign the data to newNode.
2. Set prev and next pointers of new node
• point next of newNode to the first node of the doubly linked list
• point prev to null
Let's add a node with value 6 after node with value 1 in the doubly linked list.
3. Set the prev pointer of new node and the next node
• assign the value of prev of next node to the prev of newNode
• assign the address of newNode to the prev of next node
The final doubly linked list is after this insertion is:
Let's add a node with value 6 at the end of the doubly linked list.
Finally, free the memory of del_node . And, the linked will look like this
Finally, we will free the memory of del_node . And, the final doubly linked list
looks like this.
In this case, we are deleting the last node with value 3 of the doubly linked list.
Here, we can simply delete the del_node and make the next of node
before del_node point to NULL.
// node creation
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
// if del_node is the head node, point the head pointer to the next of del_node
if (*head == del_node)
*head = del_node->next;
// if del_node is not at the last node, point the prev of node next to del_node
to the previous of del_node
if (del_node->next != NULL)
del_node->next->prev = del_node->prev;
// if del_node is not the first node, point the next of the previous node to
the next node of del_node
if (del_node->prev != NULL)
del_node->prev->next = del_node->next;
int main() {
// initialize an empty node
struct Node* head = NULL;
insertEnd(&head, 5);
insertFront(&head, 1);
insertFront(&head, 6);
insertEnd(&head, 9);
displayList(head);
displayList(head);
}
Each node consists of a data value and a Each node consists of a data value, a pointer to the next node,
pointer to the next node. and a pointer to the previous node.
• store the address of the current first node in the newNode (i.e. pointing
the newNode to the current first node)
• point the last node to newNode (i.e making newNode as head)
• store the address of the head node to next of newNode (making newNode the
last node)
• point the current last node to newNode
• make newNode as the last node
• store the address of the node next to the last node in temp
• free the memory of last
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
return last;
}
return last;
}
return last;
}
p = last->next;
do {
// if the item is found, place newNode after it
if (p->data == item) {
// allocate memory to the new node
newNode = (struct Node*)malloc(sizeof(struct Node));
p = p->next;
} while (p != last->next);
// delete a node
void deleteNode(struct Node** last, int key) {
// if linked list is empty
if (*last == NULL) return;
// if last is to be deleted
if ((*last)->data == key) {
// find the node before the last node
while (temp->next != *last) temp = temp->next;
if (last == NULL) {
printf("The list is empty");
return;
}
p = last->next;
do {
printf("%d ", p->data);
p = p->next;
} while (p != last->next);
}
int main() {
struct Node* last = NULL;
deleteNode(&last, 8);
printf("\n");
traverse(last);
return 0;
}
Polynomial
A polynomial p(x) is the expression in variable x which is in the form (axn + bxn-1 + …. +
jx+ k), where a, b, c …., k fall in the category of real numbers and 'n' is non negative
integer, which is called the degree of polynomial.
Example:
10x2 + 26x, here 10 and 26 are coefficients and 2, 1 is its exponential value.
• The sign of each coefficient and exponent is stored within the coefficient and the
exponent itself
• Additional terms having equal exponent is possible one
• The storage allocation for each term in the polynomial must be done in
ascending and descending order of their exponent
Polynomial can be represented in the various ways. These are:
There may arise some situation where you need to evaluate many polynomial
expressions and perform basic arithmetic operations like addition and subtraction with
those numbers. For this, you will have to get a way to represent those polynomials. The
simple way is to represent a polynomial with degree 'n' and store the coefficient of n+1
terms of the polynomial in the array. So every array element will consist of two values:
• Coefficient and
• Exponent
A polynomial can be thought of as an ordered list of non zero terms. Each non zero
term is a two-tuple which holds two pieces of information:
#include<stdio.h>
#include<malloc.h>
#include<conio.h>
struct link{
int coeff;
int pow;
struct link *next;
};
struct link *poly1=NULL,*poly2=NULL,*poly=NULL;
void create(struct link *node)
{
char ch;
do
{
printf("\n enter coeff:");
scanf("%d",&node->coeff);
printf("\n enter power:");
scanf("%d",&node->pow);
node->next=(struct link*)malloc(sizeof(struct link));
node=node->next;
node->next=NULL;
printf("\n continue(y/n):");
ch=getch();
}
while(ch=='y' || ch=='Y');
}
void show(struct link *node)
{
while(node->next!=NULL)
{
printf("%dx^%d",node->coeff,node->pow);
node=node->next;
if(node->next!=NULL)
printf("+");
}
}
void polyadd(struct link *poly1,struct link *poly2,struct link *poly)
{
while(poly1->next && poly2->next)
{
if(poly1->pow>poly2->pow)
{
poly->pow=poly1->pow;
poly->coeff=poly1->coeff;
poly1=poly1->next;
}
else if(poly1->pow<poly2->pow)
{
poly->pow=poly2->pow;
poly->coeff=poly2->coeff;
poly2=poly2->next;
}
else
{
poly->pow=poly1->pow;
poly->coeff=poly1->coeff+poly2->coeff;
poly1=poly1->next;
poly2=poly2->next;
}
poly->next=(struct link *)malloc(sizeof(struct link));
poly=poly->next;
poly->next=NULL;
}
while(poly1->next || poly2->next)
{
if(poly1->next)
{
poly->pow=poly1->pow;
poly->coeff=poly1->coeff;
poly1=poly1->next;
}
if(poly2->next)
{
poly->pow=poly2->pow;
poly->coeff=poly2->coeff;
poly2=poly2->next;
}
poly->next=(struct link *)malloc(sizeof(struct link));
poly=poly->next;
poly->next=NULL;
}
}
main()
{
char ch;
do{
poly1=(struct link *)malloc(sizeof(struct link));
poly2=(struct link *)malloc(sizeof(struct link));
poly=(struct link *)malloc(sizeof(struct link));
printf("\nenter 1st number:");
create(poly1);
printf("\nenter 2nd number:");
create(poly2);
printf("\n1st Number:");
show(poly1);
printf("\n2nd Number:");
show(poly2);
polyadd(poly1,poly2,poly);
printf("\nAdded polynomial:");
show(poly);
printf("\n add two more numbers:");
ch=getch();
}
while(ch=='y' || ch=='Y');
}