0% found this document useful (0 votes)
48 views29 pages

Understanding Stack Data Structure

A stack is a linear data structure that follows the Last In First Out (LIFO) principle, allowing operations such as push, pop, isEmpty, and isFull. Stacks are used in various applications including reversing words, expression evaluation in compilers, and managing browser history. Linked lists, another data structure, consist of nodes that link to one another and can be singly, doubly, or circularly linked, supporting operations like insertion, deletion, and searching.

Uploaded by

antomotongori
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views29 pages

Understanding Stack Data Structure

A stack is a linear data structure that follows the Last In First Out (LIFO) principle, allowing operations such as push, pop, isEmpty, and isFull. Stacks are used in various applications including reversing words, expression evaluation in compilers, and managing browser history. Linked lists, another data structure, consist of nodes that link to one another and can be singly, doubly, or circularly linked, supporting operations like insertion, deletion, and searching.

Uploaded by

antomotongori
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

STACKS.

A stack is an abstract data type that holds an ordered, linear sequence of items. In contrast to a queue,
a stack is a last in, first out (LIFO) structure. A real-life example is a stack of plates: you can only
take a plate from the top of the stack, and you can only add a plate to the top of the stack. If you want
to reach a plate that is not on the top of the stack, you need to remove all of the plates that are above
that one. In the same way, in a stack data structure, you can only access the element on the top of the
stack. The element that was added last will be the one to be removed first. Therefore, to implement a
stack, you need to maintain a pointer to the top of the stack (the last element to be added).

The main stack operations are:


o push(): When we insert an element in a stack then the operation is known as a push. If
the stack is full then the overflow condition occurs.
o pop(): When we delete an element from the stack, the operation is known as a pop. If the
stack is empty means that no element exists in the stack, this state is known as an
underflow state.
o isEmpty(): It determines whether the stack is empty or not.
o isFull(): It determines whether the stack is full or not.' o peek(): It returns the
element at the given position.
o count(): It returns the total number of elements available in a stack. o change(): It
changes the element at the given position.
o display(): It prints all the elements available in the stack.

Some key points related to stack o It is called as stack because it behaves like a real-
world stack, piles of books, etc.
o A Stack is an abstract data type with a pre-defined capacity, which means that it can store
the elements of a limited size. o It is a data structure that follows some order to
insert and delete the elements, and that order can be LIFO or FILO.

LIFO Principle of Stack

In programming terms, putting an item on top of the stack is called push and removing an item is
called pop.
In the above image, although item 3 was kept last, it was removed first. This is exactly how
the LIFO (Last In First Out) Principle works.

Working of Stack Data Structure


The operations work as follows:
1. A pointer called TOP is used to keep track of the top element in the stack.

2. When initializing the stack, we set its value to -1 so that we can check if the stack is empty by
comparing TOP == -1 .

3. On pushing an element, we increase the value of TOP and place the new element in the

position pointed to by TOP .

4. On popping an element, we return the element pointed to by TOP and reduce its value.

5. Before pushing, we check if the stack is already full

6. Before popping, we check if the stack is already empty


Stack implementation using Array (Push and Pop operations in arrays)

push()

• Check if the stack is full.


• If the stack is full, then display "Stack overflow".
• If the stack is not full, increment top to the next location.
• Assign data to the top element.

Algorithm_push()

If TOP >= SIZE – 1 then // Stack Overflow indicating that the Stack is FULL.
TOP = TOP + 1
STACK [TOP] = ELEMENT

pop()

• Check if the stack is empty.


• If the stack is empty, then display "Stack Underflow".
• If the stack is not empty, copy top in a temporary variable.
• Decrement top to the previous location.
• Delete the temporary variable.

Algorithm_pop()
If TOP = -1 then // Stack Underflow indicating that the Stack is EMPTY.
Return STACK [TOP]
TOP = TOP - 1

Stack Implementations in C. #include<stdio.h>


int stack[10],choice,n,top,x,i; // Declaration of variables
void push(); void pop();
void display();

int main() {
top = -1; // Initially there is no element in stack
printf("\n Enter the size of STACK : ");
scanf("%d",&n);
printf("\nSTACK IMPLEMENTATION USING ARRAYS\n");
do
{
printf("\[Link]\[Link]\[Link]\[Link]\n");
printf("\nEnter the choice : ");
scanf("%d",&choice);
switch(choice)
{ case
1: {
push();
break; }
case 2: {
pop();
break; }
case 3: {
display();
break; }
case 4: {
break; }
default:
{
printf ("\nInvalid Choice\n");
}
} }
while(choice!=4);
return 0; } void
push() {
if(top >= n - 1)
{
printf("\nSTACK OVERFLOW\n");
}
else
{
printf("Enter a value to be pushed : ");
scanf("%d",&x); top++; // TOP is incremented after an
element is pushed
stack[top] = x; // The pushed element is made as TOP
}
} void pop()
{ if(top <=
-1)
{
printf("\nSTACK UNDERFLOW\n");
}
else
{
printf("\nThe popped element is %d",stack[top]); top-
-; // Decrement TOP after a pop
} } void
display() {
if(top >= 0)
{
// Print the stack
printf("\nELEMENTS IN THE STACK\n\n");
for(i = top ; i >= 0 ; i--)
printf("%d\t",stack[i]);
}
else
{
printf("\nEMPTY STACK\n");
}
}

OUTPUT:
Applications of Stack Data Structure
• To reverse a word - Put all the letters in a stack and pop them out. Because of the LIFO
order of stack, you will get the letters in reverse order.

• In compilers - Compilers use the stack to calculate the value of expressions like 2 + 4 / 5 *
(7 - 9) by converting the expression to prefix or postfix form.
• In browsers - The back button in a browser saves all the URLs you have visited previously
in a stack. Each time you visit a new page, it is added on top of the stack. When you press
the back button, the current URL is removed from the stack, and the previous URL is
accessed.

Other Application of Stack Data Structure:

• Stack is used for evaluating expression with operands and operations.


• Matching tags in HTML and XML • Undo function in any text editor.
• Infix to Postfix conversion.
• Stacks are used for backtracking and parenthesis matching.
• Stacks are used for conversion of one arithmetic notation to another arithmetic notation.
• Stacks are useful for function calls, storing the activation records and deleting them after
returning from the function. It is very useful in processing the function calls.

Application of Stack in real life:

• CD/DVD stand.
• Stack of books in a book shop.
• Undo and Redo mechanism in text editors.
• The history of a web browser is stored in the form of a stack.
• Call logs, E-mails, and Google photos in any gallery are also stored in form of a stack.
• YouTube downloads and Notifications are also shown in LIFO format(the latest appears
first ).

Advantages of Stack:
• Stack helps in managing data that follows the LIFO technique.
• Stacks are be used for systematic Memory Management.
• It is used in many virtual machines like JVM.
• When a function is called, the local variables and other function parameters are stored in
the stack and automatically destroyed once returned from the function. Hence, efficient
function management.
• Stacks are more secure and reliable as they do not get corrupted easily.
• Stack allows control over memory allocation and deallocation.
• Stack cleans up the objects automatically.

Disadvantages of Stack:
• Stack memory is of limited size.
• The total of size of the stack must be defined before.
• If too many objects are created then it can lead to stack overflow.
• Random accessing is not possible in stack.
• If the stack falls outside the memory it can lead to abnormal termination.

Stacks in compilers (Postfix Expression Evaluation)


A postfix expression is a collection of operators and operands in which the operator is placed after
the operands. That means, in a postfix expression the operator follows the operands.

Postfix Expression has following general structure...


Operand1 Operand2 Operator

Example

Postfix Expression Evaluation using Stack Data Structure


A postfix expression can be evaluated using the Stack data structure. To evaluate a postfix expression
using Stack data structure we can use the following steps...

1. Read all the symbols one by one from left to right in the given Postfix Expression
2. If the reading symbol is operand, then push it on to the Stack.
3. If the reading symbol is operator (+ , - , * , / etc.,), then perform TWO pop operations
and store the two popped oparands in two different variables (operand1 and operand2).
Then perform reading symbol operation using operand1 and operand2 and push result
back on to the Stack.
4. Finally! perform a pop operation and display the popped value as final result.

Example
Consider the following Expression...
As Postfix expression is without parenthesis and can be evaluated as two operands and an operator at
a time, this becomes easier for the compiler and the computer to handle.

Evaluation rule of a Postfix Expression states:

1. While reading the expression from left to right, push the element in the stack if it is an
operand.
2. Pop the two operands from the stack, if the element is an operator and then evaluate it.
3. Push back the result of the evaluation. Repeat it till the end of the expression.

Algorithm

1) Add ) to postfix expression.


2) Read postfix expression Left to Right until ) encountered
3) If operand is encountered, push it onto Stack
[End If]
4) If operator is encountered, Pop two elements i) A -> Top element ii) B-> Next to Top element iii)
Evaluate B operator A push B operator A onto Stack
5) Set result = pop
6) END

An example to better understand the algorithm:

Expression: 456*+
Result: 34

LINKED LISTS.
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. Linked list is the second most-used data structure after array. Following are the important terms
to understand the concept of 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.
• LinkedList − A Linked List contains the connection link to the first link called First.

Linked List Representation

Linked list can be visualized as a chain of nodes, where every node points to the next node.

As per the above illustration, following are the important points to be considered.
• Linked List contains a link element called first.
• 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.
• Last link carries a link as null to mark the end of the list.
Types of Linked List
Following are the various types of linked list.
• Simple Linked List − Item navigation is forward only.
• Doubly Linked List − Items can be navigated forward and backward.
• Circular Linked List − Last item contains link of the first element as next and the first
element has a link to the last element as previous.
Singly Linked List
It is the most common. Each node has data and a pointer to the next node.

Singly linked list


Node is represented as:

struct node
{ int data;
struct node *next;
}

A three-member singly linked list can be created as:

/* 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));
/* Assign data values */
one->data = 1; two-
>data = 2; three->data =
3;

/* Connect nodes */ one-


>next = two; two->next =
three; three->next = NULL;

/* Save address of first node in head */ head


= one;

Doubly Linked List


We add a pointer to the previous node in a doubly-linked list. Thus, we can go in either direction:
forward or backward.

Doubly linked list


A node is represented as

struct node { int


data; struct node
*next; struct node
*prev; }

A three-member doubly linked list can be created as

/* 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));

/* Assign data values */


one->data = 1; two-
>data = 2; three->data =
3;

/* Connect nodes */ one-


>next = two; one->prev =
NULL;

two->next = three; two->prev


= one;

three->next = NULL; three-


>prev = two;

/* Save address of first node in head */ head


= one;

Circular Linked List

A circular linked list is a variation of a linked list in which the last element is linked to the first element.
This forms a circular loop.

Circular linked list


A circular linked list can be either singly linked or doubly linked.
• for singly linked list, next pointer of last item points to the first item

• In the doubly linked list, prev pointer of the first item points to the last item as well.
A three-member circular singly linked list can be created as:
/* 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));

/* Assign data values */


one->data = 1; two-
>data = 2; three->data =
3;

/* Connect nodes */ one-


>next = two; two->next =
three; three->next = one;

/* Save address of first node in head */ head


= one;

Basic Operations

Following are the basic operations supported by a list.


• Insertion − Adds an element at the beginning of the list.
• Deletion − Deletes an element at the beginning of the list.
• Display − Displays the complete list.
• Search − Searches an element using the given key.
• Delete − Deletes an element using the given key.

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 [Link] to C −
[Link] −> RightNode;
It should look like this −

Now, the next node at the left should point to the new node.
[Link] −> NewNode;

This will put the new node in the middle of the two. The new list should look like this −

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.
Insertion
The insertion into a singly linked list can be performed at different positions. Based on the position of
the new node being inserted, the insertion is categorized into the following categories.

There are three positions in the linked list where a data item can be added.

#1) At the beginning of the linked list


A linked list is shown below 2->4->6->8->10. If we want to add a new node 1, as the first node of
the list, then the head pointing to node 2 will now point to 1 and the next pointer of node 1 will
have a memory address of node 2 as shown in the below figure.

Thus, the new linked list becomes 1->2->4->6->8->10.

#2) After the given Node


Here, a node is given and we have to add a new node after the given node. In the below-linked list
a>b->c->d ->e, if we want to add a node f after node c then the linked list will look as follows:

Thus in the above diagram, we check if the given node is present. If it’s present, we create a new
node f. Then we point the next pointer of node c to point to the new node f. The next pointer of the
node f now points to node d.

#3) At the end of the Linked List


In the third case, we add a new node at the end of the linked list. Consider we have the same linked
list a->b->c->d->e and we need to add a node f to the end of the list. The linked list will look as
shown below after adding the node.
Thus we create a new node f. Then the tail pointer pointing to null is pointed to f and the next
pointer of node f is pointed to null.

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 −
[Link] −> [Link];

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.
[Link] −> 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.
Deletion and Traversing

The Deletion of a node from a singly linked list can be performed at different positions. Based on the
position of the node being deleted, the operation is categorized into the following categories.
SN Operation Description

1 Deletion at It involves deletion of a node from the beginning of the list. This is the simplest
beginnin g operation among all. It just need a few adjustments in the node pointers.
2 Deletion at the It involves deleting the last node of the list. The list can either be empty or full.
end of the lis t Different logic is implemented for the different scenarios.

3 Deletion after It involves deleting the node after the specified node in the list. we need to skip the
specified nod e desired number of nodes to reach the node after which the node will be deleted.
This requires traversing through the list.
4 Traversin g In traversing, we simply visit each node of the list at least once in order to perform
some specific operation on it, for example, printing data part of each node present
in the list.

struct node *temp = head;


printf("\n\nList elements are - \n");
while(temp != NULL)
{ printf("%d --->",temp-
>data); temp = temp->next;
}

5 Searchin g In searching, we match each element of the list with the given element. If the
element is found on any of the location, then location of that element is returned
otherwise null is returned.
// Search a node
bool searchNode(struct Node** head_ref, int key)
{
struct Node* current = *head_ref;

while (current != NULL)


{
if (current->data == key) return true;
current = current->next;
}
return false;
}

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.

Applications of Singly Linked List are as following:


1. It is used to implement stacks and queues which are like fundamental needs throughout
computer science.
2. To prevent the collision between the data in the hash map, we use a singly linked list.
3. If we ever noticed the functioning of a casual notepad, it also uses a singly linked list to
perform undo or redo or deleting functions.
4. We can think of its use in a photo viewer for having look at photos continuously in a slide
show.
5. In the system of train, the idea is like a singly linked list, as if you want to add a Boggie, either
you have to take a new boggie to add at last or you must spot a place in between boggies and
add it.
Applications of Circular Linked List are as following:
1. It can also be used to implement queues by maintaining a pointer to the last inserted node and
the front can always be obtained as next of last.
2. Circular Doubly Linked Lists are used for the implementation of advanced data structures like
Fibonacci Heap. Also reference to the previous node can easily be found in this.
3. It is also used by the Operating system to share time for different users, generally uses a
Round-Robin time-sharing mechanism (this algorithm comes from the round-robin principle,
where each person gets an equal share of something in turns. It is the oldest, simplest
scheduling algorithm, which is mostly used for multitasking).
4. Multiplayer games use a circular list to swap between players in a loop.
5. In photoshop, word, or any paint we use this concept in undo function.
Applications of Doubly Linked List are as following:
1. Great use of the doubly linked list is in navigation systems, as it needs front and back
navigation.
2. In the browser when we want to use the back or next function to change the tab, it used the
concept of a doubly-linked list here.
3. Again, it is easily possible to implement other data structures like a binary tree, hash tables,
stack, etc.
4. It is used in music playing system where you can easily play the previous one or next one song
as many times one person wants to. Basically it provides full flexbility to perform functions and
make the system user-friendly.
5. In many operating systems, the thread scheduler (the thing that chooses what processes need
to run at which times) maintains a doubly-linked list of all the processes running at any time.
This makes it easy to move a process from one queue (say, the list of active processes that need
a turn to run) into another queue (say, the list of processes that are blocked and waiting for
something to release them).
6. It is used in a famous game concept which is a deck of cards.

Advantages Of Linked List:


• Dynamic data structure: A linked list is a dynamic arrangement so it can grow and shrink
at runtime by allocating and deallocating memory. So there is no need to give the initial
size of the linked list.
• No memory wastage: In the Linked list, efficient memory utilization can be achieved since
the size of the linked list increase or decrease at run time so there is no memory wastage
and there is no need to pre-allocate the memory.
• Implementation: Linear data structures like stacks and queues are often easily implemented
using a linked list.
• Insertion and Deletion Operations: Insertion and deletion operations are quite easier in
the linked list. There is no need to shift elements after the insertion or deletion of an
element only the address present in the next pointer needs to be updated.

Disadvantages Of Linked List:


• Memory usage: More memory is required in the linked list as compared to an array. Because
in a linked list, a pointer is also required to store the address of the next element and it
requires extra memory for itself.
• Traversal: In a Linked list traversal is more time-consuming as compared to an array. Direct
access to an element is not possible in a linked list as in an array by index. For example,
for accessing a node at position n, one has to traverse all the nodes before it.
• Reverse Traversing: In a singly linked list reverse traversing is not possible, but in the case
of a doubly-linked list, it can be possible as it contains a pointer to the previously connected
nodes with each node. For performing this extra memory is required for the back pointer
hence, there is a wastage of memory.
• Random Access: Random access is not possible in a linked list due to its dynamic memory
allocation.

Linked List Implementations in C.


#include<stdio.h>
#include<stdlib.h> struct
node
{ int data;
struct node *next;
};
struct node *head;
void beginsert ();
void lastinsert ();
void randominsert();
void begin_delete();
void last_delete();
void random_delete();
void display(); void
search(); void main
()
{ int choice =0;
while(choice != 9)
{
printf("\n\n*********Main Menu*********\n");
printf("\nChoose one option from the following list ...\n");
printf("\n===============================================\n")
;
printf("\[Link] in begining\[Link] at last\[Link] at any random
location\[Link] from Beginning\[Link] from last\[Link] node after specified
location\[Link] for an element\[Link]\[Link]\n"); printf("\nEnter your
choice?\n"); scanf("\n%d",&choice); switch(choice)
{ case 1:
beginsert();
break; case 2:
lastinsert();
break; case 3:
randominsert();
break; case 4:
begin_delete();
break; case 5:
last_delete();
break; case 6:
random_delete();
break; case 7:
search();
break; case 8:
display();
break; case 9:
exit(0); break;
default:
printf("Please enter valid choice..");
}
} } void beginsert() { struct node *ptr;
int item; ptr = (struct node *)
malloc(sizeof(struct node *)); if(ptr == NULL)
{
printf("\nOVERFLOW");
}
else
{ printf("\nEnter
value\n");
scanf("%d",&item); ptr-
>data = item; ptr->next
= head; head = ptr;
printf("\nNode inserted");
} } void lastinsert() { struct node
*ptr,*temp; int item; ptr = (struct
node*)malloc(sizeof(struct node)); if(ptr
== NULL)
{
printf("\nOVERFLOW");
}
else
{
printf("\nEnter value?\n");
scanf("%d",&item); ptr->data
= item;
if(head == NULL)
{
ptr -> next = NULL;
head = ptr;
printf("\nNode inserted");
}
else
{ temp = head;
while (temp -> next != NULL)
{
temp = temp -> next;
}
temp->next = ptr;
ptr->next = NULL;
printf("\nNode inserted");
}
}
} void
randominsert()
{ int i,loc,item; struct node *ptr, *temp;
ptr = (struct node *) malloc (sizeof(struct node));
if(ptr == NULL)
{
printf("\nOVERFLOW");
}
else
{
printf("\nEnter element value"); scanf("%d",&item);
ptr->data = item; printf("\nEnter the location after which
you want to insert "); scanf("\n%d",&loc);
temp=head;
for(i=0;i<loc;i++)
{
temp = temp->next;
if(temp == NULL)
{ printf("\ncan't
insert\n"); return;
}
}
ptr ->next = temp ->next;
temp ->next = ptr;
printf("\nNode inserted");
} } void
begin_delete()
{ struct node
*ptr; if(head ==
NULL)
{ printf("\nList is
empty\n");
} else { ptr = head; head =
ptr->next; free(ptr); printf("\nNode
deleted from the begining ...\n");
} } void
last_delete()
{ struct node
*ptr,*ptr1; if(head
== NULL)
{ printf("\nlist is
empty");
}
else if(head -> next == NULL)
{
head = NULL; free(head);
printf("\nOnly node of the list deleted ...\n");
} else { ptr =
head; while(ptr->next !=
NULL)
{ ptr1 =
ptr; ptr = ptr -
>next;
}
ptr1->next = NULL;
free(ptr); printf("\nDeleted Node
from the last ...\n");
}
}
void random_delete()
{ struct node
*ptr,*ptr1; int loc,i;
printf("\n Enter the location of the node after which you want to perform deletion \n");
scanf("%d",&loc); ptr=head; for(i=0;i<loc;i++)
{ ptr1 = ptr;
ptr = ptr->next;
if(ptr == NULL)
{ printf("\nCan't
delete"); return;
}
}
ptr1 ->next = ptr ->next;
free(ptr); printf("\nDeleted node
%d ",loc+1);
} void search() {
struct node *ptr;
int item,i=0,flag;
ptr = head;
if(ptr == NULL)
{
printf("\nEmpty List\n");
}
else
{
printf("\nEnter item which you want to search?\n");
scanf("%d",&item); while (ptr!=NULL)
{ if(ptr->data
== item)
{
printf("item found at location %d ",i+1);
flag=0; } else {
flag=1; } i++; ptr = ptr
-> next;
}
if(flag==1)
{
printf("Item not found\n");
}
}
} void
display()
{ struct node
*ptr; ptr =
head; if(ptr ==
NULL)
{ printf("Nothing to
print");
} else {
printf("\nprinting values . . . . .\n");
while (ptr!=NULL)
{
printf("\n%d",ptr->data);
ptr = ptr -> next;
}
}
}

OUTPUT:

You might also like