Data Structure Calicut University 2nd Sem
Data Structure Calicut University 2nd Sem
Linked list
A linked list is a linear data structure that stores a collection of data elements
dynamically.
Linked list consist of nodes. Each node consists of two fields, the information stored in a
linked list and a pointer that stores the address of its next node.
The last node contains null in its second field because it will point to no node.
A linked list can grow and shrink its size, as per the requirement.
It does not waste memory space.
Linked-List representation
Single-linked list
2. Double-linked list:
In a doubly linked list, each node contains references to both the next and previous nodes.
This allows for traversal in both forward and backward directions, but it requires additional
memory for the backward reference.
Double-linked list
3. Circular linked list :
In a circular linked list, the last node points back to the head node, creating a circular
structure. It can be either singly or doubly linked.
Allocate memory for new node and initialize its DATA part to 24.
Add the new node as the first node of the list by pointing the NEXT part of the new
node to HEAD.
Make HEAD to point to the first node of the list.
Algorithm
Step 1: IF PTR = NULL
Write OVERFLOW
Go to Step 7
Step 2: SET NEW_NODE = PTR
Step 3: SET PTR = PTR → NEXT
Step 4: SET NEW_NODE → DATA = VAL
Step 5: SET NEW_NODE → NEXT = HEAD
Step 6: SET HEAD = NEW_NODE
Step 7: EXIT
Note that the first step of the algorithm checks if there is enough memory available to create
a new node. The second, and third steps allocate memory for the new node.
C code
struct node *new_node;
new_node = (struct node*) malloc(sizeof(struct node));
new_node->data = 24;
new_node->next = head;
head = new_node;
Algorithm
Step 1: IF PTR = NULL Write OVERFLOW
Go to Step 1
Step 2: SET NEW_NODE = PTR
Step 3: SET PTR = PTR - > NEXT
Step 4: SET NEW_NODE - > DATA = VAL
Step 5: SET NEW_NODE - > NEXT = NULL
Step 6: SET PTR = HEAD
Step 7: Repeat Step 8 while PTR - > NEXT != NULL
Step 8: SET PTR = PTR - > NEXT
[END OF LOOP]
Step 9: SET PTR - > NEXT = NEW_NODE
Step 10: EXIT
C code
struct node *new_node;
new_node = (struct node*) malloc(sizeof(struct node));
new_node->data = 24;
new_node->next = NULL;
struct node *temp = head;
while(temp->next != NULL)
{
temp = temp->next;
}
temp->next = new_node;
Allocate memory for new node and initialize its DATA part to 24.
Traverse the list until the specified node is reached.
Change NEXT pointers accordingly
Algorithm
Make newnode → next = head. This step ensures that the new node is being added
at the beginning of the list.
Then after that, make head = newnode, as the new node is now the first node of the
list, hence the new head.
C code
Struct node* Newnode;
Newnode=malloc(sizeof(struct node));
Newnode-> data=24;
Struct node *temp=head;
For(i=2;i<pos-1;i++)
{
If(temp->next!=NULL)
Temp=temp->next;
}
Newnode->next=temp->next;
Temp->next=Newnode;
Algorithm
C code
if(head == NULL)
printf("Underflow");
else
{
ptr = head;
head = head -> next;
free(ptr);
}
Delete last Node from a Linked list
Suppose we want to delete the last node from the linked list. The linked list has to be
modified as follows
Traverse to the end of the list.
Change value of next pointer of second last node to NULL.
Free last node from memory.
Algorithm
Here we use two pointers PTR and PREPTR to access the last node and the second last node.
This can be implemented in C as follows,
if(head == NULL)
printf("Underflow");
else
{
struct node* ptr = head;
struct node* preptr = NULL;
while(ptr->next!=NULL)
{
preptr = ptr;
ptr = ptr->next;
}
preptr->next = NULL;
free(ptr);
}
Delete the Node after a given Node in a Linked list
Suppose we want to delete the that comes after the node which contains data 9
Traverse the list upto the specified node.
Change value of next pointer of previous node(9) to next pointer of current node(10)
Algorithm
C code
if(head == NULL)
{
printf("Underflow");
} else
{
struct node* ptr = head;
struct node* preptr = ptr;
while(ptr->data!=num)
{
preptr = ptr; ptr = ptr->next;
}
struct node* temp = ptr;
preptr -> next = ptr -> next;
free(temp);
}
Search
Finding an element is similar to a traversal operation. Instead of displaying data, we have to
check whether the data matches with the item to find.
Initialize PTR with the address of HEAD.
Now the PTR points to the first node of the linked list.
A while loop is executed which will compare data of every node with item. If item has
been found then control goes to last step
Algorithm
Step 1: SET PTR = HEAD
Step 2: Repeat Steps 3 and 4 while PTR != NULL
Step 3: If ITEM = PTR -> DATA
SET POS = PTR
Go To Step 5
ELSE
SET PTR = PTR -> NEXT
Step 4: SET POS = NULL
Step 5: EXIT
C code
struct node* ptr = head;
struct node* pos = NULL;
while (ptr != NULL)
{
if (ptr->data == item)
pos = ptr
printf("Element Found");
break;
else ptr = ptr -> next;
}
STACK
A Stack is a linear data structure that follows the LIFO (Last-In-First-
Out) principle. Stack has one end.
It contains only one pointer TOP pointing to the topmost element of the stack.
Whenever an element is added in the stack, it is added on the top of the stack, and the
element can be deleted only from top of the stack.
a stack can be defined as a container in which insertion and deletion can be done
from the one end known as the top of the stack.
It is called as stack because it behaves like a real-world stack, piles of books, etc.
Working of Stack
Stack works on the LIFO pattern. As we can observe in the below figure there are five
memory blocks in the stack; therefore, the size of the stack is 5.
Suppose we want to store the elements in a stack and let's assume that stack is empty. We
have taken the stack of size 5 as shown below in which we are pushing the elements one by
one until the stack becomes full.
When we perform the delete operation on the stack, there is only one way for entry and exit
as the other end is closed. It follows the LIFO pattern, which means that the value entered
first will be removed last. In the above case, the value 1 is entered first, so it will be removed
only after the deletion of all the other elements.
PUSH operation
The steps involved in the PUSH operation is given below:
o Before inserting an element in a stack, we check whether the stack is full.
o If we try to insert the element in a stack, and the stack is full, then
the overflow condition occurs.
o When we initialize a stack, we set the value of top as -1 to check that the stack is
empty.
o When the new element is pushed in a stack, first, the value of the top gets
incremented, i.e., top=top+1, and the element will be placed at the new position of
the top.
o The elements will be inserted until we reach the max size of the stack.
Algorithm:
Step-1: If TOP = Max-1
Print “Overflow”
Goto Step 4
Step-2: Set TOP= TOP + 1
Step-3: Set Stack[TOP]= ELEMENT
Step-4: END
POP operation
The steps involved in the POP operation is given below:
o Before deleting the element from the stack, we check whether the stack is empty.
o If we try to delete the element from the empty stack, then the underflow condition
occurs.
o If the stack is not empty, we first access the element which is pointed by the top
o Once the pop operation is performed, the top is decremented by 1, i.e., top=top-1.
Algorithm:
Step-1: If TOP= NULL
Print “Underflow”
Goto Step 4
Step-2: Set VAL= Stack[TOP]
Step-3: Set TOP= TOP-1
Step-4: END
1. A Stack can be used for evaluating expressions consisting of operands and operators.
2. Stacks can be used for Backtracking, i.e., to check parenthesis matching in an
expression.
3. Infix to Postfix /Prefix conversion
4. Redo-undo features at many places like editors, photoshop.
5. Forward and backward features in web browsers
6. Used in many algorithms like Tower of Hanoi, tree traversals, stock span problems ,
and histogram problems.
7. It can be used for systematic Memory Management.
8. Parsing: Stacks can be used to parse input strings, such as HTML or XML code.
9. Function calls: When a function is called, the arguments to the function are pushed
onto a stack. When the function returns, the arguments are popped off the
stack. This allows the function to access its arguments in the order in which they
were passed.
#include <stdio.h>
int stack[100],i,j,choice=0,n,top=-1;
void push();
void pop();
void show();
void main ()
{
printf("Enter the number of elements in the stack ");
scanf("%d",&n);
printf("*********Stack operations using array*********");
printf("\n----------------------------------------------\n");
while(choice != 4)
{
printf("Chose one from the below options...\n");
printf("\n1.Push\n2.Pop\n3.Show\n4.Exit");
printf("\n Enter your choice \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
push();
break;
case 2:
pop();
break;
case 3:
show();
break;
case 4:
printf("Exiting....");
break;
default:
printf("Please Enter valid choice ");
};
}
}
void push ()
{
int val;
if (top == n )
printf("\n Overflow");
else
{
printf("Enter the value?");
scanf("%d",&val);
top = top +1;
stack[top] = val;
}
}
void pop ()
{
if(top == -1)
printf("Underflow");
else
top = top -1;
}
void show()
{
for (i=top;i>=0;i--)
printf("%d\n",stack[i]);
if(top == -1)
{
printf("Stack is empty");
}
}
Implementation of stack using Linked list
Instead of using array, we can also use linked list to implement stack. Linked list allocates the
memory dynamically. However, time complexity in both the scenario is same for all the
operations i.e. push, pop and peek.
In linked list implementation of stack, the nodes are maintained non-contiguously in the
memory. Each node contains a pointer to its immediate successor node in the stack. Stack is
said to be overflown if the space left in the memory heap is not enough to create a node.
The top most node in the stack always contains null in its address field.
void push ()
{
int val;
struct node *ptr =(struct node*)malloc(sizeof(struct node));
if(ptr == NULL)
printf("not able to push the element");
else
{
printf("Enter the value");
scanf("%d",&val);
if(head==NULL)
{
ptr->val = val;
ptr -> next = NULL;
head=ptr;
}
else
{
ptr->val = val;
ptr->next = head;
head=ptr;
}
printf("Item pushed");
}
}
void pop()
{
int item;
struct node *ptr;
if (head == NULL)
printf("Underflow");
else
{
item = head->val;
ptr = head;
head = head->next;
free(ptr);
printf("Item popped");
}
}
void display()
{
int i;
struct node *ptr;
ptr=head;
if(ptr == NULL)
printf("Stack is empty\n");
else
{
printf("Printing Stack elements \n");
while(ptr!=NULL)
{
printf("%d\n",ptr->val);
ptr = ptr->next;
}
}
}
Expression Parsing in Data Structure
An expression is any word or group of words or symbols that generates a value on evaluation.
Parsing expression means analysing the expression for its words or symbols depending on a
particular criterion.
The way to write arithmetic expression is known as a notation. An arithmetic expression can
be written in three different but equivalent notations, i.e., without changing the essence or
output of an expression. These notations are −
Infix Notation
Prefix (Polish) Notation
Postfix (Reverse-Polish) Notation
Infix Notation
We write expression in infix notation, e.g. a - b + c, where operators are used in-between
operands. It is easy for us humans to read, write, and speak in infix notation but the same
does not go well with computing devices. An algorithm to process infix notation could be
difficult and costly in terms of time and space consumption.
Prefix Notation
In this notation, operator is prefixed to operands, i.e. operator is written ahead of operands.
For example, +ab. This is equivalent to its infix notation a + b. Prefix notation is also known
as Polish Notation.
Postfix Notation
This notation style is known as Reversed Polish Notation. In this notation style, the operator
is postfixed to the operands i.e., the operator is written after the operands. For example, ab+.
This is equivalent to its infix notation a + b.
The following table briefly tries to show the difference in all three notations −
(a + b) ∗ c ∗+abc ab+c∗
a ∗ (b + c) ∗a+bc abc+∗
(a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
Push "(" on to the stack, and add ")" to the end of infix expression.
1.
2. Repeat until each character in the infix notation is scanned
IF a "(" is encountered, push it on the stack.
IF an operand is encountered, add it to the postfix expression.
IF a ")" is encountered, then
1. Repeatedly pop from stack and add it to the postfix
expression until a "(" is encountered.
2. Discard the "(" . That is, remove the "(" from stack and do
not add it to the postfix expression.
IF an operator O is encountered, then
1. Repeatedly pop from stack and add each operator (popped
from the stack) to the postfix expression which has the
same precedence or a higher precedence than O.
2. Push the operator O to the stack.
3. Repeatedly pop from the stack and add it to the postfix expression until
the stack is empty.
Example
A ( A
+ (+ A
( (+( A
B (+( AB
* (+(* AB
C (+(* ABC
) ABC*+
Postfix Evaluation Algorithm
Step 1. Scan the expression from left to right
Step 2. If it is an operand push it to stack
Step 3. If it is an operator pull operand from stack and perform operation
Step 4. Store the output of step 3, back to stack
Step 5. Scan the expression until all operands are consumed
Step 6. Pop the stack and perform operation
Factorial Function
To illustrate recursive functions, consider calculating the factorial of an integer. The product
of the positive integers from 1 to n is called n factorial denoted by n!. To find n!, multiply
the number by the factorial of the number that is one less than the number.
That is, n! = n * (n - 1)!
Assume we need to find the value of 5!.Then,
5! = 5 * 4!, where
4! = 4 * 3!
Therefore,
5! = 5 * 4 * 3!
Expanding further, we get
5! = 5 * 4 * 3 * 2 * 1!
We can now write a recursive function that computes the factorial of a number. Here the base
case is when n = 1
because the result will be 1 as
1! = 1
The recursive case of the factorial function will call itself, but with a smaller value of n, as
factorial(n) = n factorial (n–1).
#include <stdio.h>
int Fact(int);
int main()
{
int num, val;
//print result
printf("Factorial of %d = %d", num, val);
return 0;
}
//function to calculate factorial
int Fact(int n)
{
if (n == 1)
return 1;
else
return (n * Fact(n-1));
}
OUTPUT
Enter the number: 5
Factorial of 5 = 120