Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
10 views

stack & queue

Uploaded by

yadubhullar00
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

stack & queue

Uploaded by

yadubhullar00
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 30

Stacks in Data Structures is a linear type of data structure that follows the LIFO (Last-

In-First-Out) principle and allows insertion and deletion operations from one end of
the stack data structure, that is top. Implementation of the stack can be done by
contiguous memory which is an array, and non-contiguous memory which is a linked
list. Stack plays a vital role in many applications.

Introduction to Stack in Data Structures

The stack data structure is a linear data structure that accompanies a principle
known as LIFO (Last In First Out) or FILO (First In Last Out). Real-life examples of a
stack are a deck of cards, piles of books, piles of money, and many more.

This example allows you to perform operations from one end only, like when you
insert and remove new books from the top of the stack. It means insertion and
deletion in the stack data structure can be done only from the top of the stack. You
can access only the top of the stack at any given point in time.

● Inserting a new element in the stack is termed a push operation.

● Removing or deleting elements from the stack is termed pop operation.

Next, you will see how to represent the stacks in data structures in real-time.

Working of Stack in Data Structures

Now, assume that you have a stack of books.

You can only see the top, i.e., the top-most book, namely 40, which is kept top of the
stack.
If you want to insert a new book first, namely 50, you must update the top and then
insert a new text.

And if you want to access any other book other than the topmost book that is 40,
you first remove the topmost book from the stack, and then the top will point to the
next topmost book.

After working on the representation of stacks in data structures, you will see some
basic operations performed on the stacks in data structures.

Basic Operations on Stack in Data Structures

There following are some operations that are implemented on the stack.

Push Operation

Push operation involves inserting new elements in the stack. Since you have only one
end to insert a unique element on top of the stack, it inserts the new element at the
top of the stack.

Pop Operation

Pop operation refers to removing the element from the stack again since you have
only one end to do all top of the stack. So removing an element from the top of the
stack is termed pop operation.

Peek Operation

Peek operation refers to retrieving the topmost element in the stack without
removing it from the collections of data elements.

isFull()
isFull function is used to check whether or not a stack is empty.

isEmpty()

isEmpty function is used to check whether or not a stack is empty.

First, you will learn about the functions:

isFull()

The following is the algorithm of the isFull() function:

begin

If

top equals to maxsize

return true

else

return false

else if

end

The implementation of the isFull() function is as follows:


Bool isFull()

if(top == maxsize)

return true;

else

return false;

isEmpty()

The following is the algorithm of the isEmpty() function:

begin

If

topless than 1

return true

else
return false

else if

end

The implementation of the isEmpty() function is:

Bool isEmpty()

if(top = = -1)

return true;

else

return false;

Push Operation

Push operation includes various steps, which are as follows :

Step 1: First, check whether or not the stack is full

Step 2: If the stack is complete, then exit


Step 3: If not, increment the top by one

Step 4: Insert a new element where the top is pointing

Step 5: Success

The algorithm of the push operation is:

Begin push: stack, item

If the stack is complete, return null

end if

top ->top+1;

stack[top] <- item

end

This is how you implement a push operation:

if(! isFull ())

top = top + 1;

stack[top] = item;
}

else {

printf(“stack is full”);

Pop Operation

Step 1: First, check whether or not the stack is empty

Step 2: If the stack is empty, then exit

Step 3: If not, access the topmost data element

Step 4: Decrement the top by one

Step 5: Success

The following is the algorithm of the pop operation:

Begin pop: stack

If the stack is empty

return null

end if
item -> stack[top] ;

Top -> top - 1;

Return item;

end

Implementing a pop operation is as follows:

int pop( int item){

If isEmpty()) {

item = stack[top];

top = top - 1;

return item;

else{

printf(“stack if empty”);

}
Peek Operation

The algorithm of a peek operation is:

begin to peek

return stack[top];

end

The implementation of the peek operation is:

int peek()

return stack[top];

Implementation of Stack in Data Structures

You can perform the implementation of stacks in data structures using two data
structures that are an array and a linked list.
● Array: In array implementation, the stack is formed using an array. All the
operations are performed using arrays. You will see how all operations can be
implemented on the stack in data structures using an array data structure.

● Linked-List: Every new element is inserted as a top element in the linked list
implementation of stacks in data structures. That means every newly inserted
element is pointed to the top. Whenever you want to remove an element from
the stack, remove the node indicated by the top, by moving the top to its previous
node in the list.

Application of Stack in Data Structures


Here are the top 7 applications of the stack in data structure:

● Expression Evaluation and Conversion

● Backtracking

● Function Call

● Parentheses Checking

● String Reversal

● Syntax Parsing

● Memory Management

Now you will understand all the applications one at a time.

1. Expression Evaluation and Conversion

There are three types of expression that you use in programming, they are:

Infix Expression: An infix expression is a single letter or an operator preceded by one


single infix string followed by another single infix string.
● X

● X+Y

● (X + Y ) + (A - B)

Prefix Expression: A prefix expression is a single letter or an operator followed by two


prefix strings.

● X

● +XY

● ++XY-AB

Postfix Expression: A postfix expression (also called Reverse Polish Notation) is a


single letter or an operator preceded by two postfix strings.

● X

● XY+

● XY+CD-+

Similarly, the stack is used to evaluate these expressions and convert these
expressions like infix to prefix or infix to postfix.

2. Backtracking

Backtracking is a recursive algorithm mechanism that is used to solve optimization


problems.

To solve the optimization problem with backtracking, you have multiple solutions; it
does not matter if it is correct. While finding all the possible solutions in
backtracking, you store the previously calculated problems in the stack and use that
solution to resolve the following issues.

The N-queen problem is an example of backtracking, a recursive algorithm where the


stack is used to solve this problem.
3. Function Call

Whenever you call one function from another function in programming, the
reference of calling function stores in the stack. When the function call is terminated,
the program control moves back to the function call with the help of references
stored in the stack.

So stack plays an important role when you call a function from another function.

import java.util.Scanner;

class GetInputData
{
public static void main(String args[])
{
int num;
float fnum;
String str;

Scanner in = new Scanner(System.in);

//Get input String


System.out.println("Enter a string: ");
str = in.nextLine();
System.out.println("Input String is: "+str);

//Get input Integer


System.out.println("Enter an integer: ");
num = in.nextInt();
System.out.println("Input Integer is: "+num);

//Get input float number


System.out.println("Enter a float number: ");
fnum = in.nextFloat();
System.out.println("Input Float number is: "+fnum);
}
}
Output:

Enter a string:
Chaitanya
Input String is: Chaitanya
Enter an integer:
27
Input Integer is: 27
Enter a float number:
12.56
Input Float number is: 12.56

4. Parentheses Checking

Stack in data structures is used to check if the parentheses like ( ), { } are valid or not
in programing while matching opening and closing brackets are balanced or not.

So it stores all these parentheses in the stack and controls the flow of the program.

For e.g ((a + b) * (c + d)) is valid but {{a+b})) *(b+d}] is not valid.

5. String Reversal

Another exciting application of stack is string reversal. Each character of a string gets
stored in the stack.

The string's first character is held at the bottom of the stack, and the last character of
the string is held at the top of the stack, resulting in a reversed string after
performing the pop operation.

6. Syntax Parsing

Since many programming languages are context-free languages, the stack is used for
syntax parsing by many compilers.

7. Memory Management

Memory management is an essential feature of the operating system, so the stack is


heavily used to manage memory.
Queue
A queue is a linear data structure that stores the elements sequentially. It uses the FIFO
approach (First In First Out) for accessing elements. Queues are typically used to manage
threads in multithreading and implementing priority queuing systems. In this article, we will
learn about different types of queue data structure, basic operations performed on it,
implementation, and queue applications. A queue is an important data structure
in programming. A queue follows the FIFO (First In First Out) method and is open at both of
its ends. Data insertion is done at one end rear end or the tail of the queue while deletion is
done at the other end called the front end or the head of the queue.

Real Life example of a queue data structure


Let’s consider a line of people waiting to buy a ticket at a cinema hall. A new person will join
the line from the end and the person standing at the front will be the first to get the ticket
and leave the line. Similarly in a queue data structure, data added first will leave the queue
first.

Some other applications of the queue in real-life are:

● People on an escalator
● Cashier line in a store
● A car wash line
● One way exits

Operations performed on queue


The fundamental operations that can be performed on queue are listed as follows -

● Enqueue: The Enqueue operation is used to insert the element at the rear end of
the queue. It returns void.
● Dequeue: It performs the deletion from the front-end of the queue. It also
returns the element which has been removed from the front-end. It returns an
integer value.
● Peek: This is the third operation that returns the element, which is pointed by the
front pointer in the queue but does not delete it.
● Queue overflow (isfull): It shows the overflow condition when the queue is
completely full.
● Queue underflow (isempty): It shows the underflow condition when the Queue
is empty, i.e., no elements are in the Queue.

peek()

This function helps to see the data at the front of the queue. The algorithm of peek()
function is as follows −

Algorithm

begin procedure peek

return queue[front]

end procedure

Implementation of peek() function in C programming language −

Example

int peek() {

return queue[front];

isfull()

As we are using single dimension array to implement queue, we just check for the rear
pointer to reach at MAXSIZE to determine that the queue is full. In case we maintain the
queue in a circular linked-list, the algorithm will differ. Algorithm of isfull() function −

Algorithm

begin procedure isfull

if rear equals to MAXSIZE

return true

else
return false

endif

end procedure

Implementation of isfull() function in C programming language −

Example

bool isfull() {

if(rear == MAXSIZE - 1)

return true;

else

return false;

isempty():

As we are using single dimension array to implement queue, we just check for the rear
pointer to reach at MINSIZE to determine that the queue is empty. In case we maintain
the queue in a circular linked-list, the algorithm will differ.

Algorithm of isempty() function −

Algorithm

begin procedure isempty

if front is less than MIN OR front is greater than rear

return true

else

return false

endif

end procedure
If the value of front is less than MIN or 0, it tells that the queue is not yet initialized,
hence empty.

Here's the C programming code −

Example

bool isempty() {

if(front < 0 || front > rear)

return true;

else

return false;

Enqueue Operation

Queues maintain two data pointers, front and rear. Therefore, its operations are
comparatively difficult to implement than that of stacks.

The following steps should be taken to enqueue (insert) data into a queue −

Step 1 − Check if the queue is full.

Step 2 − If the queue is full, produce overflow error and exit.

Step 3 − If the queue is not full, increment rear pointer to point the next empty space.

Step 4 − Add data element to the queue location, where the rear is pointing.

Step 5 − return success.

Sometimes, we also check to see if a queue is initialized or not, to handle any


unforeseen situations.

Algorithm for enqueue operation

procedure enqueue(data)
if queue is full

return overflow

endif

rear ← rear + 1

queue[rear] ← data

return true

end procedure

Implementation of enqueue() in C programming language −

Example

int enqueue(int data)

if(isfull())

return 0;

rear = rear + 1;

queue[rear] = data;

return 1;

end procedure

Dequeue Operation

Accessing data from the queue is a process of two tasks − access the data where front is
pointing and remove the data after access. The following steps are taken to
perform dequeue operation −

Step 1 − Check if the queue is empty.

Step 2 − If the queue is empty, produce underflow error and exit.


Step 3 − If the queue is not empty, access the data where front is pointing.

Step 4 − Increment front pointer to point to the next available data element.

Step 5 − Return success.

Algorithm for dequeue operation

procedure dequeue

if queue is empty

return underflow

end if

data = queue[front]

front ← front + 1

return true

end procedure

Implementation of dequeue() in C programming language −

Example

int dequeue() {

if(isempty())

return 0;

int data = queue[front];


front = front + 1;

return data;

Types of Queues in Data Structure


There are four different types of queues in data structures:

● Simple Queue
● Circular Queue
● Priority Queue
● Double-Ended Queue (Deque)

Simple Queue

It is the most basic queue in which the insertion of an item is done at the front of the queue
and deletion takes place at the end of the queue.

● Ordered collection of comparable data kinds.


● Queue structure is FIFO (First in, First Out).
● When a new element is added, all elements added before the new element must be
deleted in order to remove the new element.

Circular Queue

A circular queue is a special case of a simple queue in which the last member is linked to the
first. As a result, a circle-like structure is formed.

● The last node is connected to the first node.


● Also known as a Ring Buffer as the nodes are connected end to end.
● Insertion takes place at the front of the queue and deletion at the end of the queue.
● Application of circular queue: Insertion of days in a week.

Now let’s take a look at the priority queue in the data structure.

Priority Queue
In a priority queue, the nodes will have some predefined priority in the priority queue. The
node with the least priority will be the first to be removed from the queue. Insertion takes
place in the order of arrival of the nodes.

Some of the applications of priority queue:

● Dijkstra’s shortest path algorithm


● Prim’s algorithm
● Data compression techniques like Huffman code

Below diagram shows how an application use priority queue for the items consumed by the
user.

Deque (Double Ended Queue)

In a double-ended queue, insertion and deletion can take place at both the front and rear
ends of the queue.

**queue** is a linear data structure that follows the First-In-First-Out (FIFO) principle. This
means that the first element added to the queue will be the first one to be removed. Think of it
like a line at a grocery store: the person who arrives first is the first one to be served.

Basic Operations of Queue Data Structure


● Enqueue (Insert): Adds an element to the rear of the queue.

● Dequeue (Delete): Removes and returns the element from the front of the queue.

● Peek: Returns the element at the front of the queue without removing it.

● Empty: Checks if the queue is empty.

● Full: Checks if the queue is full.

### Definition

A queue is defined as a collection of elements with two main operations:


1. **Enqueue**: Add an element to the end of the queue.
2. **Dequeue**: Remove an element from the front of the queue.
In addition to these, queues often support:
- **Peek/Front**: Retrieve the element at the front of the queue without removing it.
- **IsEmpty**: Check if the queue is empty.
- **Size**: Get the number of elements in the queue.

### Real-Time Examples

1. **Print Queue**: When multiple documents are sent to a printer, they are placed in a queue.
The first document sent is printed first, while the others wait their turn.

2. **Task Scheduling**: Operating systems use queues to manage processes. Tasks or processes
are added to a queue and executed in the order they arrive.

3. **Call Centers**: Incoming calls are placed in a queue and are attended to in the order they
are received.

### Applications

1. **Breadth-First Search (BFS)**: Queues are used in BFS algorithms to explore nodes in a
graph level by level.

2. **Task Scheduling**: Operating systems and real-time systems use queues to schedule tasks
and manage process execution.

3. **Buffering**: In data streaming or IO operations, queues are used to manage data being read
from or written to hardware devices.
4. **Handling Requests**: Web servers often use queues to manage incoming client requests,
processing them one by one.

### Operations

1. **Enqueue**: Insert an element at the end of the queue.


- **Time Complexity**: O(1)

2. **Dequeue**: Remove an element from the front of the queue.


- **Time Complexity**: O(1)

3. **Peek/Front**: Access the element at the front of the queue without removing it.
- **Time Complexity**: O(1)

4. **IsEmpty**: Check if the queue has no elements.


- **Time Complexity**: O(1)

5. **Size**: Get the number of elements in the queue.


- **Time Complexity**: O(1)
Queues can be implemented using arrays or linked lists, with each having its own advantages and
trade-offs depending on the context in which the queue is used.
#include <stdio.h>
#include <stdlib.h>

#define MAX 5 // Define maximum size of the queue

// Global variables
int front = 0;
int rear = -1;
int size = 0;
int arr[MAX];

// Function prototypes
int isEmpty();
int isFull();
void enqueue(int value);
int dequeue();
int peek();
int queueSize();
void displayQueue();

int main() {
int choice, value;

do {
printf("\nQueue Operations Menu:\n");
printf("1. Enqueue\n");
printf("2. Dequeue\n");
printf("3. Peek\n");
printf("4. Check if Empty\n");
printf("5. Check Size\n");
printf("6. Display Queue\n");
printf("7. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);

switch (choice) {
case 1:
if (isFull()) {
printf("Queue is full. Cannot enqueue.\n");
} else {
printf("Enter value to enqueue: ");
scanf("%d", &value);
enqueue(value);
printf("Enqueued %d\n", value);
}
break;

case 2:
if (isEmpty()) {
printf("Queue is empty. Cannot dequeue.\n");
} else {
value = dequeue();
printf("Dequeued %d\n", value);
}
break;

case 3:
if (isEmpty()) {
printf("Queue is empty. Nothing to peek.\n");
} else {
value = peek();
printf("Front element is %d\n", value);
}
break;

case 4:
if (isEmpty()) {
printf("Queue is empty.\n");
} else {
printf("Queue is not empty.\n");
}
break;

case 5:
printf("Queue size is %d\n", queueSize());
break;

case 6:
displayQueue();
break;

case 7:
printf("Exiting...\n");
break;
default:
printf("Invalid choice. Please try again.\n");
break;
}
} while (choice != 7);

return 0;
}
// Check if the queue is empty
int isEmpty() {
return (size == 0);
}
// Check if the queue is full
int isFull() {
return (size == MAX);
}
// Enqueue an element
void enqueue(int value) {
rear = (rear + 1) % MAX;
arr[rear] = value;
size++;
}
// Dequeue an element
int dequeue() {
int value = arr[front];
front = (front + 1) % MAX;
size--;
return value;
}
// Peek at the front element
int peek() {
return arr[front];
}
// Get the current size of the queue
int queueSize() {
return size;
}
// Display the elements of the queue
void displayQueue() {
if (isEmpty()) {
printf("Queue is empty.\n");
return;
}
printf("Queue elements: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[(front + i) % MAX]);
} printf("\n"); }

### Queue Operations Algorithms


#### 1. Initialize the Queue
**Algorithm:**
1. Set `front` to 0.
2. Set `rear` to -1.
3. Set `size` to 0.
4. Initialize the array `arr` of size `MAX`.

**Pseudo-code:**
InitializeQueue:
front = 0
rear = -1
size = 0
arr = array of size MAX
#### 2. Enqueue (Add an Element to the Queue)

**Algorithm:**
1. Check if the queue is full by comparing `size` with `MAX`.
- If full, print "Queue is full" and exit.
2. Increment `rear` by 1 and wrap around using modulo `MAX`.
3. Insert the new element at `arr[rear]`.
4. Increment `size` by 1.

**Pseudo-code:**
Enqueue(value):
if size == MAX:
print "Queue is full"
return
rear = (rear + 1) % MAX
arr[rear] = value
size = size + 1
#### 3. Dequeue (Remove an Element from the Queue)

**Algorithm:**
1. Check if the queue is empty by comparing `size` with 0.
- If empty, print "Queue is empty" and exit.
2. Retrieve the element from `arr[front]`.
3. Increment `front` by 1 and wrap around using modulo `MAX`.
4. Decrement `size` by 1.
5. Return the retrieved element.

**Pseudo-code:**

Dequeue():
if size == 0:
print "Queue is empty"
return
value = arr[front]
front = (front + 1) % MAX
size = size - 1
return value
#### 4. Peek (View the Front Element of the Queue)
**Algorithm:**
1. Check if the queue is empty by comparing `size` with 0.
- If empty, print "Queue is empty" and exit.
2. Retrieve and return the element at `arr[front]`.

**Pseudo-code:**
```plaintext
Peek():
if size == 0:
print "Queue is empty"
return
return arr[front]

#### 5. Check if the Queue is Empty

**Algorithm:**
1. Return `true` if `size` is 0; otherwise, return `false`.

**Pseudo-code:**
```plaintext
IsEmpty():
return (size == 0)

#### 6. Check if the Queue is Full

**Algorithm:**
1. Return `true` if `size` is equal to `MAX`; otherwise, return `false`.

**Pseudo-code:**
```plaintext
IsFull():
return (size == MAX)

#### 7. Get the Size of the Queue

**Algorithm:**
1. Return the current `size` of the queue.
**Pseudo-code:**
```plaintext
QueueSize():
return size

#### 8. Display the Queue Elements


**Algorithm:**
1. Check if the queue is empty by comparing `size` with 0.
- If empty, print "Queue is empty" and exit.
2. Iterate from `front` to `front + size - 1` (modulo `MAX`) and print each element.

**Pseudo-code:**
```plaintext
DisplayQueue():
if size == 0:
print "Queue is empty"
return
for i from 0 to size - 1:
index = (front + i) % MAX
print arr[index]

You might also like