DS Unit 1 and Unit 2
DS Unit 1 and Unit 2
Data Structure is a way of collecting and organising data in such a way that we can
perform operations on these data in an effective way.
1. Primitive Data Structure: The Primitive Data Structures are the Data
Structures that can be manipulated directly by machine instructions. They are
the basic fundamental data types. The C language provides the following
Primitive Data types: integer, character, float, double and pointers.
2. Non Primitive Data Structure: The Non Primitive Data Structures are those
that are not defined by the programming language but instead created by the
programmer. These are again classified into 2 types: a) Linear b) Non Linear
a) Linear Data Structures: Here the data elements are arranged in linear
fashion. These includes array, stack, queue and linked list.
1. Add an element
2. Delete an element
3. Traverse
4. Sort the list of elements
5. Search for a data element.
b) Non Linear Data Structures: Here the data elements are arranged in
nonlinear fashion. These includes Tree and Graph.
1. Add elements
2. Delete elements
3. Display the elements
4. Sort the list of elements
5. Search for a data element.
Every item is related to its previous and Every item is attached with many other
next item. items.
When an application requires special kind of data which is not available as built
in data type, then its programmers responsibility to implement his own kind of
data.
The programmer has to specify how to store a value for data, what are
operations that can meaningfully manipulate variables of that kind of data,
amount of memory required to store a variable.
The programmer has to decide all these things and accordingly implement
them.
Programmers own data type is termed as abstract data type.
It is also called as user defined data type.
Pointers
A pointer is a variable that can hold the address of another variable or address of
memory location.
If you have a variable var in your program, &var will give you its address in the memory,
where & is commonly called the reference operator.
Example:
#include <stdio.h>
int main()
{
int var = 5;
printf("Value: %d\n", var);
printf("Address: %u", &var); //Notice, the ampersand(&) before var.
return 0;
}
Output:
Value: 5
Address: 2686778
Pointer Variables:
In C, there is a special variable that stores just the address of another variable. It is
called Pointer variable or, simply, a pointer.
Declaration of Pointer
data_type* pointer_variable_name;
Example: int* p;
The referencing operator & is used to access the address of the variables. And using
differencing operator * we can access the value from the address.
#include <stdio.h>
int main()
{
int *p;
int var = 10;
/* Assigning the address of variable var to the pointer * p. The p can hold the
address of var because var is an integer type variable*/
p= &var;
Output:
Value of variable var is: 10
Value of variable var is: 10
Address of variable var is: 0x7ffe0005dee4
Address of pointer p is: 0x7ffe0005dee8
Pointer Declaration: Pointer variables should be declared before they are used.
Syntax: data_type *identifier;
Example:
int *pi;
float *pf;
char *pc;
double *pd;
FILE *fb;
1000 1001
3000 3001
a=65;
p=&a;
After the initialization the variable a holds the value 65 and variable p holds the value
of address of a as illustrated below:
65
a
1000 1001
NULL Pointers
It is always a good practice to assign a NULL value to a pointer variable in case you
do not have an exact address to be assigned. This is done at the time of variable
declaration. A pointer that is assigned NULL is called a null pointer.
The NULL pointer is a constant with a value of zero defined in several standard
libraries. Consider the following program −
#include <stdio.h>
int main ()
return 0;
When the above code is compiled and executed, it produces the following result:
The value of ptr is 0
The mechanism in which pointer variable are used as function parameter is known
as call by reference.
Consider the example where 2 numbers are swapped. The function prototype for the
same is as follows.
When the function is called, the addresses of the variables to be modified are
passed as arguments to the pointer parameters.
Thus to exchange the values of variables a and b this function is called as follows.
#include<stdio.h>
int main()
swap(&num1, &num2);
return 0;
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
Output
Number1 = 10
Number2 = 5
In c language pointers can be used to create and handle arrays. Some of the
operations that can be performed on arrays are:
Traversing an array
Accessing array element
Reading an array
Printing and array
int arr[5]={ 1, 2, 3, 4, 5 };
Assuming that the base address of arr is 1000 and each integer requires two bytes,
the five elements will be stored as follows
Here variable arr will give the base address, which is a constant pointer pointing to
the element, arr[0]. Therefore arr is containing the address of arr[0] i.e 1000. In short,
arr has two purpose- it is the name of an array and it acts as a pointer pointing
towards the first element in the array
int *p;
p = arr;
#include<stdio.h>
int main()
Int n,num,I,a[10];
int big;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
big=*a[0];
pos=0;
for(i=0;i<=n-1;i++)
if(*a[i]>big)
big=*a[i];;
pos=i;
printf(“position=%d”,i);
return 0;
#include<stdio.h>
#include<stdlib.h>
void main()
int numArray[10];
int i, sum = 0;
int *ptr;
scanf("%d", &numArray[i]);
ptr++;
Array of Pointers:
There may be a situation when we want to maintain an array, which can store
pointers to an int or char or any other data type available. Following is the
declaration of an array of pointers to an integer −
int *ptr[MAX];
It declares ptr as an array of MAX integer pointers. Thus, each element in ptr, holds
a pointer to an int value. The following example uses three integers, which are stored
in an array of pointers, as follows −
#include <stdio.h>
#include<stdlib.h>
const MAX = 3;
int main ()
{
int i, *ptr[MAX];
return 0;
Output:
We can also use an array of pointers to character to store a list of strings as follows:
#include <stdio.h>
const MAX = 4;
int main ()
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
printf("Value of names[%d]=%s\n",i,names[i]);
return 0;
Output:
Pointer Arithmetic
Similar to the way arithmetic operations are possible on normal variables, it is possible
to perform arithmetic operations on pointers as well. Various Arithmetic operations that
can be carried out are incrementing, decrementing, addition, subtraction and
comparison.
Incrementing a Pointer
We prefer using a pointer in our program instead of an array because the variable
pointer can be incremented, unlike the array name which cannot be incremented
because it is a constant pointer. The following program increments the variable pointer
to access each succeeding element of the array −
#include <stdio.h>
const MAX = 3;
int main ()
int i, *ptr;
ptr = var;
ptr++;
return 0;
Decrementing a Pointer
The same considerations apply to decrementing a pointer, which decreases its value
by the number of bytes of its data type as shown below −
#include <stdio.h>
const MAX = 3;
int main ()
int i, *ptr;
ptr = &var[MAX-1];
ptr--;
return 0;
Pointer Addition:
int *ptr , n;
ptr = &n ;
ptr = ptr + 3;
#include<stdio.h>
int main()
ptr=ptr+3;
return 0;
Pointer Subtraction:
Pointers Comparison
The pointers can be compared with each other only if both the pointers are pointing to
similar type of data. i.e two pointers should point to char or both the pointers should
point to int etc.
Example: if(ptr2==ptr1)
Example: if(ptr2>ptr1)
Pointer ptr2 is far from ptr1
Character Pointer
char *a;
a H E L L O \0
Pointer a
Pgm:
#include<stdio.h>
int main()
char *s=”Hello”;
printf(“%s”,s);
return 0;
Output:
Pointer to Pointer
int **var;
#include <stdio.h>
int main ()
int var;
int *ptr;
int **pptr;
var=3000;
ptr=&var;
pptr=&ptr;
return 0;
Output:
Structure
Structure is used to store the information of one particular object but if we need to
store such 100 objects then Array of Structure is used.
Eg:
struct Bookinfo
char bname[20];
int pages;
float price;
}Book[100];
Explanation:
In case if we need to store the Information of 100 books then Array of Structure is
used.
b1[0] stores the Information of 1st Book , b1[1] stores the information of 2nd Book and
So on We can store the information of 100 books.
Book[1].pages
Example :
#include <stdio.h>
struct Bookinfo
char bname[20];
int pages;
float price;
}book[3];
int i;
for(i=0;i<3;i++)
gets(book[i].bname);
scanf("%d",book[i].pages);
scanf("%f",book[i].price);
for(i=0;i<3;i++)
printf("\nName of Book:%s",book[i].bname);
printf("\nNumber of Pages:%d",book[i].pages);
printf("\nPrice of Book:%f",book[i].price);
return 0;
Push: Adds an item in the stack. If the stack is full, then it is said to be an Overflow
condition.
Pop: Removes an item from the stack. The items are popped in the reversed order in
which they are pushed. If the stack is empty, then it is said to be an Underflow
condition.
Example:
Step 1 Step 2
Step 3 Step 4
Step 5: Stack is empty
Operation Explanation
if (top == (MAX-1))
status = 0;
else
++top;
int ret;
if (top == -1)
{ printf(“Stack is empty”);
else
{ s = a [top];
--top;
return s;
int i;
if (top == -1)
else
printf (“%d”,a[i]);
printf ("\n");
2) Infix to postfix/ prefix conversion. Using stack, we can efficiently convert from infix
to postfix, infix to prefix etc.
5) Recursion: A function which calls itself is called recursion. Used in many algorithms
like tower of Hanoi, tree traversals etc can be implemented very efficiently using
recursion. It is very important facility available in variety of programming languages
such as C, C++ etc.
6) Stack can be used in back tracking problem, Knight tour problem, N queen problem
etc.
7) Other application stack can be used like to find whether string is palindrome or not,
check whether given expression is valid or not.
8) Stacks are also used in syntax parsing for many compilers. In graph algorithm like
topological sorting and strongly connected components.
#include<stdio.h>
#include<stdlib.h>
int top=-1,stack[MAX];
void push();
void pop();
void display();
void main()
{
int ch;
printf("\n\n1.Push\n2.Pop\n3.Display\n4.Exit");
scanf("%d",&ch);
switch(ch)
case 1: push();
break;
case 2: pop();
break;
case 3: display();
break;
case 4: exit(0);
void push()
int val;
if(top==MAX-1)
printf("\nStack is full!!");
}
else
scanf("%d",&val);
void pop()
if(top==-1)
printf("\nStack is empty!!");
else
top=top-1;
void display()
int i;
if(top==-1)
{
printf("\nStack is empty!!");
else
printf("\nStack is...\n");
for(i=top;i>=0;--i)
printf("%d\n",stack[i]);
struct stack
int data[MAX];
int top;
}s;
Push Function
if (stop==(MAX – 1))
printf(“Stack Overflow”);
else
s->top = s->top + 1;
sdata[stop] = num;
}
Pop Function
Display Function
int i;
if (s->top == -1)
else
ss=s->item[i];
printf (“%d\n”,ss);
printf ("\n");
Expression:
Based on the operator position, expressions are divided into THREE types. They are
as follows:
1. Infix Expression
2. Postfix Expression
3. Prefix Expression
Example: a+b
Example: ab+
Example: +ab
Operator precedence
The rule that determine the order in which different operators are evaluated are
called precedence of operators.
It determines which operator is performed first in an expression with more than one
operators with different precedence.
Exponential ^ Highest
Multiplication, Division *, / Next
Remember:
Eg:
Solve 10 + 20 * 30
Operators Associativity:
The order in which the operators with same precedence are evaluated in an
expression is called associativity of the operators. It is used when two operators of
same precedence appear in an expression. Associativity can be either Left to Right
or Right to Left.
For example: ‘*’ and ‘/’ have same precedence and their associativity
is Left to Right, so the expression “100 / 10 * 10” is treated as “(100 / 10) * 10”.
Eg: Solve 100 + 200 / 10 - 3 * 10
What is left associative?
In an expression if 2 or more operators have the same priority and are evaluated
from left to right then it is called left associative.
In an expression if 2 or more operators have the same priority and are evaluated
from right to left then it is called right associative.
Algorithm
3. Else,
a) If the precedence of the scanned operator is greater than the precedence of the
operator in the stack (or the stack is empty), push it.
b) Else, Pop the operator from the stack until the precedence of the scanned
operator is less-equal to the precedence of the operator residing on the top of the
stack. Push the scanned operator to the stack.
5. If the scanned character is an ‘)’, pop and output from the stack until an ‘(‘is
encountered.
Eg: 1) Obtain the postfix expression for ((A+(B-C) *D) ^E+F) by substitution
method:
Empty A+(B*C-(D/E-F)*G)*H -
Empty +(B*C-(D/E-F)*G)*H A
+ (B*C-(D/E-F)*G)*H A
+( B*C-(D/E-F)*G)*H A
+( *C-(D/E-F)*G)*H AB
+(* C-(D/E-F)*G)*H AB
+ *H ABC*DE/F-G*-
+* H ABC*DE/F-G*-
+* End ABC*DE/F-G*-H
Procedure:
2) Scan the given expression and do following for every scanned element.
a) If the element is a number, push it into the stack
b) If the element is a operator, pop 2 operands from the stack and evaluate it
and push the result back to the stack
3) When the expression is ended, the number in the stack is the final answer
Example:
1) Let the given expression be “2 3 1 * + 9 -“.
if ( x is Operator )
{
Operand2 = Pop(Stack S);
Operand2 = Pop(Stack S);
Evaluate (Operand1,Operand2,Operator x);
}
Recursion
A function that calls itself is known as a recursive function. And, this technique is
known as recursion. The recursion continues until some condition is met to prevent
it.
int factorial(int i)
if(i <= 1) {
return 1;
int fibonacci(int i)
if(i == 0)
return 0;
}
if(i == 1)
return 1;
Tower of Hanoi:
Tower of Hanoi is a mathematical puzzle which consists of three towers (pegs) and more than
one rings is as depicted −
These rings are of different sizes and stacked upon in an ascending order, i.e. the
smaller one sits over the larger one. There are other variations of the puzzle where
the number of disks increase, but the tower count remains the same.
Rules
The mission is to move all the disks to some another tower without violating the
sequence of arrangement. A few rules to be followed for Tower of Hanoi are −
Only one disk can be moved among the towers at any given time.
if (n==0) return;
tower(n-1,temp,source,destination);
int main()
int base,power;
scanf("%d",&base);
scanf("%d",&power);
result=getPower(base,power);
return 0;
#include<stdio.h>
int main(){
int n1,n2,gcd;
scanf("%d %d",&n1,&n2);
gcd=findgcd(n1,n2);
printf("\nGCD of %d and %d is: %d",n1,n2,gcd);
return 0;
while(x!=y){
if(x>y)
return findgcd(x-y,y);
else
return findgcd(x,y-x);
return x;
#include <stdio.h>
if(num>0)
count++;
countDigits(num/10);
else
return count;
}
}
int main()
int number;
int count=0;
scanf("%d",&number);
count=countDigits(number);
return 0;
#include <stdio.h>
if(num>0)
sumDigits(num/10);
else
return sum;
}
int main()
int number,sum;
scanf("%d",&number);
sum=sumDigits(number);
return 0;
Recursion makes program elegant and cleaner. All algorithms can be defined
recursively which makes it easier to visualize and prove.
If the speed of the program is vital then, you should avoid using recursion.
Recursions use more memory and are generally slow. Instead, you can use loop.
UNIT 2
It is a linear structure where elements are inserted from one end and elements are
deleted from other end. The end at which new elements are added is called rear and
the end from which elements are deleted is called front. Using the approach, first
element inserted is the first element to be deleted out, hence queue can be called First
in First out (FIFO) data structure. A good example of queue is any queue of consumers
for a resource where the consumer that came first is served first.
The difference between stacks and queues is in removing. In a stack we remove the
item the most recently added; in a queue, we remove the item the least recently
added.
b) Circular queue
c) Priority queue
a) Linear queue:
Here elements will be inserted from one end and elements are deleted from other end.
The end at which new elements are added is called rear and the end from which
elements are deleted is called front.
Eg: Consider the queue having the elements 10, 50 and 20.
10 50 20
0 1 2 3 4
front rear
Here the items are inserted into queue in the order 10, 50 and 20. The variable q is
used as an array to hold these elements. Item 10 is the first element inserted. So,
the variable first is used as index to the first element. Item 20 is the last element
inserted. So, the variable rear is used as index to the last element.
Operations on Queue:
Insertion:
Step 1:
QUEUE_SIZE = 5
10 20 30 40 50
0 1 2 3 4
front rear
We can observe that whenever rear value is equal to “QUEUE_SIZE -1” insertion is
not possible. The code for this can be written as:
if (rear==QUEUE_SIZE -1)
printf(“Queue is full\n”);
return;
Step 2: If the condition QUEUE_SIZE – 1 is not satisfied, it means the queue is not
full and an element can be inserted at the rear end. Observe that item has to be after
30 at position 3. That is, before inserting an item, we have to increment rear by one.
This can be achieved by
Item = 40
10 20 30
0 1 2 3 4
front rear
Step 3: Now the item can be inserted at rear position. This can be achieved by copying
item into q[rear] as: q[rear] = item;
Item = 40
10 20 30 40
0 1 2 3 4
front rear
void Insert_Rear()
printf(“Queue overflow\n”);
return;
Deletion:
10 20 30
0 1 2 3 4
front rear
10 20 30
0 1 2 3 4
front
rear
front == rear
So we can see the above 2 figures that if front is less than or equal to rear some
elements are present. Otherwise, it that is front is greater than rear then queue is
empty. We can check for empty queue using the following statement:
Step 2: When the above condition fails, we can delete an item from a front end of
queue. So for this, we have to access and return the first element and increment
value of front by 1 as:
return q[front++];
int delete_Front()
{
return q[front++];
Display:
if(front>rear)
printf(“Queue is empty”);
return;
Step 2: If elements are present in queue control comes out of the above if
statements. Assume that queue contains 3 elements:
20 25 10
-1 0 1 2 3 4
front rear
printf(“%d\n”,s[0]); Output: 20
printf(“%d\n”,s[1]); 25
printf(“%d\n”,s[2]); 10
for(i=front;i<=rear;i++)
printf(“%d\n”,s[i]);
C function to display:
void display()
printf(“queue is empty\n”);
return;
for(i=front;i<=rear;i++)
printf("%d",q[i]);
The above situation arises when 5 elements say 10, 20,30,40,50 are inserted and
then deleting first 2 items 10 and 20. It is not possible to insert an item. Even if there
is space available insertion cannot be made. Because we have Queue Overflow
condition as QSIZE-1. This is the drawback of an ordinary queue.
Applications of Queue
1. Queues are widely used as waiting lists for a single shared resource like
printer, disk, CPU.
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.
5. Queues are used in operating systems for handling interrupts.
#include <stdio.h>
#include <stdlib.h>
#define que_size 5
int rear,front,item,q[10];
void insertq()
{
if (rear==que_size-1) //check for overflow of queue
printf("QUEUE OVERFLOW \n");
else
{
rear=rear+1; //increment rear and insert item
q[rear]=item;
}
}
int deleteq()
{
if(front>rear) //Queue is empty
return-1;
else
return(q[front++]);
}
void display()
{
int i;
if(front>rear) //check for empty queue
printf("QUEUE UNDERFLOW \n");
else
{
for(i=front;i<=rear;i++)
{
printf("%d\t",q[i]); //here contents of queue is displayed
}
printf("\n");
}
}
int main()
{
int ch, delitem;
front=0;
rear=-1;
while(1)
{
printf("1.INSERT 2.DELETE 3.DISPLAY 4.EXIT \n");
printf("ENTER YOUR CHOICE \n");
scanf("%d",&ch);
switch(ch)
{
case 1:printf("ENTER THE ITEM \n");
scanf("%d",&item);
insertq();
break;
case 2: delitem=deleteq();
if(delitem==-1)
printf("QUEUE UNDERFLOW \n");
else
printf("DELETED ITEM = %d\n",delitem);
break;
case 3: display();
break;
case 4:exit(0);
default :printf("INVALID CHOICE !!! TRY AGAIN\n");
break;
}
}
return 0;
}
Output:
Representation of queue using structure
struct queue
int item[size];
int rear, front;
}q;
The initial value of rear and front when queue is empty is as follows.
b) Circular Queue:
Circular Queue is a linear data structure in which the operations are performed
based on FIFO (First in First Out) principle and the last position is connected back to
the first position to make a circle. It is also called ‘Ring Buffer’.
Two pointers called FRONT and REAR are used to keep track of the first and
last elements in the queue.
When initializing the queue, we set the value of FRONT and REAR to -1.
On enqueing an element, we circularly increase the value of REAR index and
place the new element in the position pointed to by REAR.
On dequeing an element, we return the value pointed to by FRONT and
circularly increase the FRONT index.
Before enqueing, we check if queue is already full.
Before dequeing, we check if queue is already empty.
When enqueing the first element, we set the value of FRONT to 0.
When dequeing the last element, we reset the values of FRONT and REAR to
-1.
Example:
In a normal Queue, we can insert elements until queue becomes full. But once queue
becomes full, we cannot insert the next element even if there is a space in front of
queue. Whenever front is 0 and rear either -1 or Queue_Size – 1, queue is empty.
Whenever item is inserted, rear is incremented by 1. Whenever we have to delete the
elements, then we have to delete at front end.
Steps:
1. Check whether queue is Empty means check (front==-1).
2. If it is empty then display Queue is empty. If queue is not empty then step
3
3. Check if (front==rear) if it is true then set front=rear= -1 else check if
(front==size-1), if it is true then set front=0 and return the element.
When queue is empty, front =0 and rear =-1. But in circular queue just before index 0,
we have index 4. So instead of rear=-1 we can write rear=4 also. So empty queue is
represented by following initialization statements:
front=0;
rear=-1;
The above statements indicate empty queue can also be represented as:
front=0;
Eg: The contents of circular queue after performing each of the following operations:
a) Empty queue
b) Insert 10
c) Insert 20 and 30
d) Insert 40 and 50
e) Insert 60
f) Delete 2 items
g) Insert 60
h) Insert 80
Step 1: Empty queue: Whenever front is 0 and rear is either -1 or QUE_SIZE -1,
queue is empty. An empty queue can be represented as:
Step 3: Insert 20 and 30: Here we have to increment rear by 1 and insert 20. Again
increment rear by 1 and insert 30 as:
Step 4: Insert 40 and 50: Increment rear by 1 and insert 40. Again increment rear by
1 and insert 50 as:
Step 5: Insert 60: Queue is full. It is not possible to insert any element into queue. So,
contents of queue have not been changed here.
Step 6: Delete: An item has to be deleted always from the front end. So, 10 is deleted
and contents of queue after deleting 10 is:
Step 7: Delete: An item has to be deleted always from the front end. So 20 is deleted
and contents of queue after deleting 20 is:
Step 8: Inserting 60: Increment rear by 1, its value is 0 and insert 60 at 0th location
as:
Step 9: Inserting 70: Increment rear by 1 and insert 70 as:
Step 10: Insert 80: Queue is full. It is not possible to insert any element into queue.
So, contents of queue have not been changed.
InsertQ()
Step 1: Check for overflow: Before inserting an item, we check whether sufficient
space is available in the queue.
if(count==Queue_Size)
return;
Step 2: Insert item: Increment rear by 1 and then take the mod operation and then
insert the item as shown below:
rear = (rear+1)%Queue_Size;
q[rear]=item;
Step 3: Update count:
void InsertQ()
if(count==Que_Size)
printf(“Queue overflow”);
return;
rear=(rear+1)%Que_Size;
q[rear]=item;
count++;
DeleteQ():
Step 1: Check for underflow: Before deleting an element from queue, we check
whether sufficient queue is empty or not. This can be achieved using the statement:
When the above condition fails, it means queue is not empty and return the element
present at the front end of queue.
Step 2: Access the first item: This is achieved by accessing the element using index
front and then updating front by adding 1 to it and then take mod value. The equivalent
statements can be written as:
count--;
Step 4: Return the element which was at the front end using the statement:
return item;
int DeleteQ()
item = q[front];
front = (front+1)%Que_Size;
return item;
DisplayQ():
Step 1: Check for underflow: This is achieved using the following statement:
if(count==0)
printf(“Queue is empty\n”);
return;
Step 2: Display: Display starts from the front index. After displaying q[front] we have
to update front by 1. (That is by incrementing front by 1 and then taking the modulus).
The procedure is repeated for count number of times. This is because, count contains
the number of items in queue. The code can be written as:
for (i=1,f=front;i<=count;i++)
printf(“%d\n”,q[f]);
f=(f+1)%Que_Size;
void display()
int i,f;
if(count==0)
printf(“Q is empty\n”);
return;
for(i=1,f=front;i<=count;i++)
printf(“%d\n”,q[f]);
f=(f+1)%Que_Size;
}
c) Priority Queue: A queue in which we are able to insert items or remove items from
any position based on some priority is often referred as Priority queue. Always an
element with highest priority is processed before processing any of the lower priority
elements. If the elements in the queue are of same priority, then the element which is
inserted first into the queue is processed.
In an ascending priority queue elements can be inserted in any order. But, while
deleting an element from the queue, only the smallest element is removed first.
In descending priority queue also elements can be inserted in any order. But, while
deleting an element from the queue, only the largest element is deleted first.
remove_small() – which inserts the smallest item from the queue and at the same time
store maximum number in that location indicating an item has been deleted.
2) The second technique is to insert the item based on the priority. In this technique,
we assume the item to be inserted itself denotes the priority. So, the items with least
value can be considered as the items with highest priority and items with highest value
can be considered as the items with least priority. So, to implement priority queue we
insert the elements in queue in such a way that they are always ordered in ascending
order. With this technique the highest priority elements are at front end of the queue
and lowest priority elements are at rear end of the queue. So while we are deleting an
item, always delete from the front end so that highest priority element is deleted first.
C code for the function to insert an item at the correct place in priority queue:
int j;
printf(“Q is full\n”);
return;
while(j>=0 && item <q[j]) //find appropriate position to allocate space for inserting an
item based on the priority
j--;
}
Linear Data Structures- Singly Linked List
As it can be seen that the length (size) of the array above made is 9. But what if
there is a requirement to change this length (size). For Example,
Now let us see the difference between static memory allocation and dynamic memory
allocation:
static memory allocation dynamic memory allocation
C provides some functions to achieve these tasks. There are 4 library functions
provided by C defined under <stdlib.h> header file to assist dynamic memory
allocation in C programming. They are:
1. malloc()
2. calloc()
3. free()
4. realloc()
Function Description
malloc() allocates requested size of bytes and returns a void pointer pointing to
the first byte of the allocated space
calloc() allocates space for an array of elements, initialize them to zero and then
returns a void pointer to the memory
Malloc ()
malloc () function is used for allocating block of memory at runtime. This function
reserves a block of memory of given size and returns a pointer of type void. This
means that we can assign it to any type of pointer using typecasting. If it fails to allocate
enough space as specified, it returns a NULL pointer.
Syntax:
void* malloc(byte-size)
int *x;
x = (int *)malloc(100*sizeof(int)); //Since the size of int is 4 bytes, this statement will allocate
400 bytes of memory. And, the pointer ptr holds the address of the first byte in the allocated
memory.
free(x);
calloc()
Syntax:
Syntax:
int *x;
x=(int*)malloc(50 * sizeof(int));
“free” method in C is used to dynamically de-allocate the memory. The memory allocated
using functions malloc() and calloc() is not de-allocated on their own. Hence the free() method
is used, whenever the dynamic memory allocation takes place. It helps to reduce wastage of
memory by freeing it.
Syntax: free(ptr);
calloc() malloc()
calloc() initializes the allocated memory malloc() initializes the allocated memory
with 0 value. with garbage values.
Syntax: Syntax:
#include <stdio.h>
#include <stdlib.h>
int main()
int i, n;
int *element;
scanf("%d", &n);
exit(0);
for(i=1;i<n;i++)
*element = *(element+i);
Output:
42153
Smallest element is 1
Linked list:
Definition: A linked list is a sequence of data structures which are connected together
via links. Linked List is a sequence of links which contains items. Each link contains a
connection to another link. A linked list is a non-primitive type of data structure in which
each element is dynamically allocated and in which elements point to each other to
define a linear relationship. If each node in the list has only one link, it is called singly
linked list. If it has two links one containing the address of the next node and other link
containing the address of the previous node it is called doubly linked list. Linked list
require more memory compared to array because along with value it stores pointer to
next node.
Elements of linked list are called nodes where each node in the singly list has 2 fields
namely:
1. A linked list is a dynamic data structure therefore, the primary advantage of linked
lists over arrays is that linked lists can grow or shrink in size during the execution of a
program i.e. runtime but arrays is a static data structure therefore, the size remain
fixed. In arrays we would need to allocate all the storage in starting.
2. There is no need to specify how many number of nodes required so linked list does
not waste memory space. We can allocate and de-allocate memory space at runtime.
3. The most important advantage is that the linked lists provide flexibility is allowing
the items to be rearranged efficiently. In linked list it is easier to insert or delete items
by rearranging the pointers but in arrays insertion and deletion requires large
movement of data.
1. A linked list will use more memory storage than arrays with the same number of
elements is used because each time linked list has more memory for an additional
linked field or next pointer field.
2. Arrays elements can be randomly accessed by giving the appropriate index, while
linked list elements cannot randomly accessed.
Insertion
Deletion
Display
Insertion: In a single linked list, the insertion operation can be performed in three
ways. They are as follows:
int info;
Here in the above structure we can see that keyword typedef the type “struct node *”
can also be written as NODE. So wherever we use struct node * can be replaced with
NODE.
struct node
int info;
};
NULL
first
Create a node:
We can use malloc () function to allocate memory explicitly as and when required and
exact amount of memory space needed during execution. This can be done by:
x=(data_type *) malloc(size);
After doing the allocation, the function returns the address of 1st byte of allocated
memory. Since the address is returned, the return type is a void pointer. If the
specified memory is not available, then there will be condition called overflow of
memory. In such case functions returns NULL. So it is users responsibility to check
whether there is a sufficient memory.
if(x==NULL)
printf(“Insufficient memory\n”);
exit(0);
If x is not null, it means a node is successfully created and we can return the node by
the statement return x;
NODE getnode()
NODE x;
exit(0);
A node which is identified by variable first with 2 fields: info and link fields can be
created using getnode() function:
first = getnode();
first info
first link
The data item 10 can be stored in the info field using the following statement:
firstinfo=10;
After executing above statement, the data item 10 is stored in info field of first
firstlink=NULL;
So by using above 3 steps we can create a node with specified data item as shown in
this figure:
Delete a node:
A node which is no longer used or required can be deleted using free() function as:
free(variable);
For eg: when above statement is executed, the memory space allocated for the node,
is deallocated and returned to OS so that it can be used by some other program. The
memory deallocated after executing:
free(first);
1) Insert a node at the front end: Let us consider a linked list with 4 nodes. Here,
pointer variable first contains address of the first node of the list as:
Now let us try to insert the item 50 at the front end of the above list.
temp=getnode()
tempinfo=item;
Step 3: Copy the address of the first node of the list stored in pointer variable first into
link field of temp using:
templink=first;
Step 4: Now, a node temp has been already inserted and we can observe from figure
that temp is the first node. Let us return the address of the first node using:
return temp;
NODE temp;
Now let us see how to create linked list? So I is very simple call insert_front()
function.
first=insert_front(item,first);
If first is NULL and item is 10, then above statement is executed, a linked list with
only one node is created as:
If the above statement is executed for 2nd time with item 20, a new node is inserted
at the front end and there by number of nodes in the list is 2:
If the above statement is executed for 3rd time with item 30, a new node is inserted at
the front end and there by number of nodes in the list is 3:
Consider the following singly list where the variable first contains the address of first
node of the list.
We need to find the address of the last node. So we have to start from the first node.
Instead of updating first, let us use another variable say current. The variable current
should contain the address of the first node. So this is done by writing statement:
cur=first;
cur=curlink;
After executing the above statement, current contains address of next node as:
cur=curlink
If we execute the instruction cur=curlink again, cur contains address of next node
as:
If we execute the instruction cur=curlink again, cur contains address of next node
as:
Here we can see current link is NULL then it denoted as it is last node of the list. If
cur contains address of first node, keep updating current as long as link field of
current is not NULL as:
cur=curlink; while(curlink!=NULL)
cur=curlink;
Now variable first contains address of the 1st node, we can find address of last node
as:
while(curlink!=NULL)
cur=curlink;
How to find last node and last but one in the list:
Consider the following list: If current contains address of the 1st node of the list, what
is the previous node? The previous node does not exit and so we say previous is
NULL.
prev=NULL;
cur=first;
Now we have to update current to get address of the last node. So the code can be
written as:
while(curlink!=NULL)
cur=curlink;
Now before updating cur inside the loop using cur=curlink. Let us copy cur to prev.
The code can be modified as:
while(curlink!=NULL)
prev=cur;
cur=curlink;
So after the loop, the variable contains address of the last node and the variable
prev contains the address of the prev node. To find address of last node and last but
one node as:
prev=NULL;
cur=first;
while(curlink!=NULL)
prev=cur;
cur=curlink;
}
After above code is executed we get pictorial representation as this way:
Case 1: List is empty: If the list is empty, it is not possible to display the contents of
the list. The code for this is:
if(first==NULL)
printf(“List is empty\n”);
return;
Case 2: List is exiting: Consider the linked list with 4 nodes where the variable first
contains address of the first node of the list:
Initialization: We have to use another variable cur to point to the beginning of the
list. So this can be done by just copying first to cur as:
cur=first;
Display:
Now display the info field of cur node and update cur as:
printf(“%d”,curinfo); //output=20
cur=curlink; //cur=1008
Now display info field of cur node and update cur as:
printf(“%d”,curinfo); //output=30
cur=curlink; //cur=1048
Now display info field of cur node and update cur as:
printf(“%d”,curinfo); //output=10
cur=curlink; //cur=1026
Now display info field of cur node and update cur as:
printf(“%d”,curinfo); //output=60
cur=curlink; //cur=NULL
printf(“%d”,curinfo); while(cur!=NULL)
cur=curlink; {
printf(“%d”,curinfo);
cur=curlink;
NODE cur;
if(first==NULL)
printf(“List is empty\n”);
return;
}
cur=first;
while(cur!=NULL)
printf(“%d”,curinfo);
cur=curlink;
A node from the front end of list can be deleted by considering various cases
Case 1: List is empty: If the list is empty, it is not possible to delete a node from the
list. In such we have to display list is empty and return NULL.
printf(“List is empty\n”);
return;
Case 2: List is exiting: Consider the list with 5 nodes where the variable first
contains address of the first node of the list.
We know the address of first node, now we need to know the address of the second
node of the list. Because after deleting the first node, the second node will be the first
node of the list. So these of steps we should follow when we delete a node.
Step 1: We have to use pointer variable temp and store the address of first node of
the list by the following statement:
temp=first;
Step 2: Update the pointer temp so that variable temp contains the address of the
second node. So this can be achieved by the following statement:
temp=templink;
Step 3: Here variable first points to first node of the list and temp points to the
second node of the list. Now display info field of the first node that have to be deleted
and deallocate the memory by using these statements:
printf(“item deleted=%d\n”,firstinfo);
free(first);
After executing the above statement, the node pointed by first is deleted and is
returned to OS.
Step 4: Once the first node is deleted, we can observe that node temp is the first
node. So, return temp as the first node to the calling function using the statement:
return temp;
NODE temp;
Step 2: If the list is empty, the above node can be returned as the first node of the
list. So this can be done by following statement:
if(first==NULL)
return temp;
Step 3: If the list is existing, we have to insert temp at the end of the list.
To insert at the end, we have to find address of the last node. So the code to find the
address of last node can be written as:
cur=first;
while(curlink!=NULL)
cur=curlink;
}
Step 4: Insert a node at the end: By looking the above list, we can easily insert
temp at the end of current. So this can be done by copying temp to curlink as:
curlink=temp;
Step 5: We can observe from the above list that first contains address of the first
node of the list. So we return first.
return first;
tempinfo=item;
templink=NULL;
if(first==NULL) //if list is empty return new node as the first node
return temp;
while(curlink!=NULL)
cur=curlink;
Case 1: List is empty: If the list is empty, it is not possible to delete the contents of
the list. In such case we display appropriate message and return. The code is as
follows:
return NULL;
Case 2: List contains only 1 node: Consider s list with single node as:
Note: If link field of first contains NULL, it indicates that there is only one node.
If only one node is present, it can be deleted using free() function. Then we return
NULL indicating list is empty. So the code for this is:
if(firstlink==NULL)
Case 3: List contains more than one node: Consider the list with 5 nodes as:
Step 1: To delete the last node we should know the address of last node and last but
one node. For this, we have to use pointer variables, current and previous. Initially,
current points to the first node and previous points to NULL. So this can be written
as:
prev=NULL;
cur=first;
Step 2: Now update current and previous so that current contains address of last
node and previous contains address of last but one node. This can be achieved by
following statements:
while(curlink!=NULL)
prev=cur;
cur=curlink;
After executing above loop, the variable current contains address of last node and
previous contains address of last but one node as:
Step 3: To delete the last node pointed to by current, the function free() is used.
free(cur);
After executing above statements, the last node is deleted and the list is:
Step 4: Once the last node is deleted, the node pointed to by previous should be the
last node. This is achieved by just copying NULL to link field of previous as:
After executing the above statements, the list can be shown as:
NODE cur,prev;
return first;
}
if(firstlink==NULL)
prev=NULL;
cur=first;
while(curlink!=NULL)
prev=cur;
cur=curlink;
printf(“Item deleted=%d\n”,curinfo);
#include<stdio.h>
#include<stdlib.h>
void create(int);
void search();
struct node
int data;
};
void main ()
int choice,item,loc;
do
scanf("%d",&choice);
switch(choice)
scanf("%d",&item);
create(item);
break;
case 2:search();
case 3: exit(0);
break;
default: printf("\nPlease enter valid choice\n");
}while(choice != 3);
if(ptr == NULL)
printf("\nOVERFLOW\n");
else
ptr->data = item;
ptr->next = head;
head = ptr;
printf("\nNode inserted\n");
void search()
{
struct node *ptr;
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++;
ptr = ptr -> next;
if(flag==1)
If link field of the last node contains starting address of first node. Such a list is called
circular list. In general, a circular list is a variation of ordinary linked list in which link
field of the last node contains address of the first node. This list is primarily used in
structures that allow access to nodes in the middle of the list without starting from the
first node.
a) Every node is accessible from a given node by traversing successively using the
link field.
b) To delete a node current, the address of the first node is not necessary. Search
for the predecessor of node current, can be initiated from current itself.
c) Certain operations on circular list such as concatenation and splitting of list etc will
be more efficient.
Approach 1
A pointer variable first can be used to designate the starting point of the list. Using
this approach, to get the address to get the address of last node, the entire list has to
be traversed from the first node.
Approach 2
In the second technique, a pointer variable last can be used to designate the last
node and the node that follow last, can be designated as the first node of the list.
The pictorial representation of the circular list is:
From the figure we can see that the variable last contains address of last node.
Using link field of last node that is lastlink, we can get address of the first node.
A circular list can be used as a stack or a queue. To implement these data structure,
we require of the following functions:
Consider a list with 4 nodes. Here, pointer last contains address of the last node of
the list. Let us try to insert an item at the front end of list.
Step 1: To insert an item 50 at the front of the list, obtain a free node using malloc()
function with the help of macro MALLOC() and insert the item using the statement:
tempinfo=item;
Step 2: Copy the address of the first node(i.e. lastlink) into link field of newly
obtained node temp and the statement is:
if(last!=NULL)
templink=lastlink;
else //if last is NULL, make temp itself as the last node
temp=last;
Step 3: Make temp as the first node. Establish a link between the node temp and the
last node. This is achieved by copying the address of the node temp into link field of
node last. The code can be written as:
lastlink=temp;
Step 4: Finally, we return address of the last node using the statement:
return last;
NODE temp;
tempinfo=item;
last=temp;
else
Let us consider a list with 4 nodes. Here, pointer last contains address of the last
node of the list. Let us insert an item 80 at the end of the list.
tempinfo=item;
Step 2: Copy the address of the first node (i.e. lastlink) into link field of newly
obtained node temp and the statement is:
if(last!=NULL)
templink=lastlink; //copy the address of first node into link field of temp
else //if last is NULL, make temp itself as the last node
temp=last;
Step 3: Establish a link between the newly created node temp and the node last.
This is achieved by copying the address of the node temp into link field of node last.
The code for this is:
lastlink=temp;
return temp;
NODE temp;
MALLOC(temp,1,struct node); //create a new node to be inserted
tempinfo=item;
last=temp;
else
Let us consider as a list with 5 nodes. Here, pointer last contains address of the last
node of the list. Let us delete an item at the front end of the list.
Step 1: In case if list is empty we cannot delete it So in this situation we can write
code as:
If list is empty:
if(last==NULL)
printf(“list is empty\n”);
return NULL;
}
In case we are deleting only one node, the list will be empty and we have to return
NULL. The code can be written as:
free(last);
Step 2: Make second node as first node. So this can be done by copying firstlink
to lastlink. The code can be written as:
lastlink= firstlink; //link the last node and new first node
Step 3: Now remove the first node by using free(). But before removing the node,
display appropriate message. The code can be written as:
Now the node first is deleted. These steps have been designed by assuming the list
is already existing.
{
NODE temp,first;
printf(“List is empty\n”);
return NULL;
free(last);
return NULL;
Let us consider a list with 5 nodes. Here, pointer last contains address of the last
node of the list. Now let us delete an item at the rear end of the list.
Step 1:
In case if list is empty we cannot delete it So in this situation we can write code as:
If list is empty:
if(last==NULL)
printf(“list is empty\n”);
return NULL;
In case we are deleting only one node, the list will be empty and we have to return
NULL. The code can be written as:
free(last);
}
Obtain the address of the predecessor of the node to be deleted. So this can be
done by traversing from the first node till the link field of a node contains address of
the last node. The code can be written as:
prev=lastlink;
prev=prevlink;
Step 2: The first node and the last but one node (i.e. prev) are linked. So this can be
written as:
prevlink=lastlink;
Step 3: Remove the last node using free(). But before removing a node display
appropriate message. The code can be written as:
printf(“item deleted=%d\n”,lastinfo);
free(last);
Step 4: Return prev itself as the first node of the result using the statement:
return prev;
NODE prev;
printf(“list is empty\n”);
return NULL;
free(last);
return NULL;
while(prevlink!=last)
prev=prevlink;
{
NODE temp;
printf(“list is empty\n”);
return;
printf(“%d”,tempinfo);
temp=templink;