0% found this document useful (0 votes)
15 views

chapter -4 stack & queue

Chapter Four discusses stacks and queues, two fundamental data structures. It explains stack operations (PUSH and POP), their implementations using arrays and linked lists, and introduces linked lists, including dynamic memory allocation and node structure. Additionally, it covers queue operations, their implementations, and various applications of both stacks and queues.

Uploaded by

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

chapter -4 stack & queue

Chapter Four discusses stacks and queues, two fundamental data structures. It explains stack operations (PUSH and POP), their implementations using arrays and linked lists, and introduces linked lists, including dynamic memory allocation and node structure. Additionally, it covers queue operations, their implementations, and various applications of both stacks and queues.

Uploaded by

nafyjabesa1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 25

Chapter Four: Stacks and Queues

4.1 Basic Stack Operations

Stack:- is a an ordered set of items/ a data structure in which addition of new element or deletion
of existing element always takes place from one end known as top.

It is called LIFO (Last in First out)

The operation of insertion and deletion are:-

PUSH:-put an item on the stack and

POP:- delete (get) an item from the stack

Push ( )
{
If there is a room {
Put an item on the top of the stack
Else
Give an error message
}
}
Pop ( )
{
If stack not empty {
return the value of the top item
remove the top item from the stack
}
else {
give an error message
}
}
CreateStack()
{
remove existing items from the stack
initialise the stack to empty
}

1
}

Stack is not in built like array and structure in C++, therefore it will be implemented in two
ways:
1. Static implementation (using arrays)
2. Dynamic implementation (using pointers/linked lists)
4.1.1 Array implementation of Stacks: PUSH & POP operations

int n=10; data[top]=item;

Struct stack{ }

int data[n]; int pop(){

int top; if(top==-1)

}; {cout<<”empty/underflow”;

top=-1; return NULL;}

Void push(int item){ int temp=data[top];

If(top==n-1) top--

Cout<<”stack is full/overflow”; return temp;

Top++; }

2
What is a linked list?
Linked list is a data structure in which each data item points to the
next data item. This "linking" is accomplished by keeping an address
variable (a pointer) together with each data item. This pointer is used
to store the address of the next data item in the list. The structure that
is used to store one element of a linked list is called a node. A node
has two parts: data and next address. The data part contains the
necessary information about the items of the list, the next address part
contains the address of the next node.

Creating Linked Lists:


A special pointer will be used to point to the first node of a linked
list. We will call this pointer head. At the beginning, when there
are no nodes, head will be NULL (pointer pointing to nowhere).
As soon as there is a node in the list, head will contain the
address of this first node.
A list with no nodes is called an empty list or a null list.

A NULL Pointer is used to signal the end of a list. The last node will
have NULL in its next address part.

Dynamic Memory Allocation:


The memory to store a node of a linked list is allocated whenever
needed. This allocation is made by the help of a function
called malloc.
malloc is defined in stdlib.h.

The function prototype for malloc is:


void * malloc(size_t size);
Freeing Allocated Memory: Whenever an allocated memory
block is not necessary, it may be freed by using free function
defined in stdlib.h.
void * free( void *block);
Defining a Node:
Assume that we will keep information about courses in a linked
list. The information consists of the course code, course name,
credits, no. of lecture hours, no. of lab hours. Each course will
point to the course to which it is a prerequisite.
Simple Node Example:
typedef struct node_s
{
int item; /* data consisting of an integer */
3
struct node_s *next; /* pointer to the next node */
} node_t;
Another Node Example:
typedef struct node_s
{
char name[NAMELEN]; /* data: name */
int year; /* data: year */
struct node_s *next; /* pointer to the next node */
} node_t;
More Complex Node Example:
Data part:
typedef struct
{
char code[8]; /* course code */
char name[26];/* course name */
int credits; /* course credits */
int lectures; /* no. of lecture hours */
int labs; /* no. of lab hours */
} course_t;
Node:
typedef struct node_s
{
course_t course; /* course information */
struct node_s *next; /* pointer to the next node */
} node_t;
Typedef for Pointer to a node:
typedef node_t* nodeptr;
Declaring a node:
node_t course_node;
Declaring a pointer to a node:
nodeptr ptr; /* ptr is of type nodeptr */
node_t *ptr; /* This has exactly the same meaning
*/
Allocating space for a node:
ptr = (node_t *) malloc(sizeof(node_t));
Type Casting:
Since malloc returns a void pointer, the return value will be
converted to a type which is necessary for the specisific use of
the pointer. In the above example, the pointer will be used to
point to a memory block of type node_t. Conversion to a
requested type is possible by an action called casting. It is
posiible to convert a value temporarily to a different type by
placing the requested type in paranthesis just to the beginning
of an expression, a value of a fuction call.

4
Examples for casting:
int number = 9;
double result;

result = (double)number / 2;
Getting a new node:
/* allocates memory for a new node */
nodeptr getnode(void)
{
nodeptr ptr;
ptr = (nodeptr) malloc(sizeof(node_t));
return(ptr);
}
Actions Related With Linked Lists: (These will be explained in the
lecture.)

 Adding a node to a Linked List: (a) To the beginning, (b) To the


end, (c) Between two nodes.
 Traversing a Linked List.
 Deleting a node from a Linked List: (a) From the beginning, (b)
From the end, (c) A node between two nodes.
 Searching a node in a Linked List.

Functions Related with Linked Lists:

 Add (insert) a new node to the beginning


 Add (insert) a new node to the end
 Add (insert) a new node after n'th node
 Search: a node with a given data
 Add (insert) a new node after a node with a given data (uses
Search)
 Add (insert) a new node before a node with a given data
 Traverse all nodes
 Delete a node from the beginning
 Delete a node from the end
 Delete a node with a given data
 Delete the n'th node
 Modify the data of all nodes in a linked list
 Modify data of nodes for a given criteria

Examples:

1. Write a program that reads numbers entered by the user and


stores these numbers into a Linked List.
5
2. Write a program that reads names entered by the user and
stores these names into a Linked List.
3. Write a program that reads car information (brand, year, color,
kilometer and price) from a text file (car01.txt), stores these
information into a Linked List. When all information is read, it
displays the contents of the linked list.
(a) Add each new car info to the end of the linked list.
(b) Add each new car info to the beginning of the linked list.
4. Write a program that reads car information (car-number, brand,
year, color, kilometer and price) from a text file (car02.txt),
stores these information into a Linked List, displays the contents
of the linked list.. Then it reads car-numbers (until zero is
entered), delete the nodes with these car-numbers. At the end it
displays again the contents of the linked list.

Doubly Linked Lists

What is a Doubly Linked List?


Doubly Linked List (DLL) is a type of Linked List in which each
data item points to the next and also to the previous data item.
This "linking" is accomplished by keeping two address variables
(pointers) together with each data item. These pointers are used
to store the address of the previous and the address of the next
data items in the list.

The structure that is used to store one element of a linked list is


called a node like in Linked Lists.

A node has three parts: data, previous address and next


address.

The data part contains the necessary information about the


items of the list, the previous address part contains the address
of the previous node, the next address part contains the address
of the next node.

6
Linked List implementation of Stacks: PUSH & POP operations

Struct node{ }

Int data; else{

Node *next; top=temp;

}*top,*temp2,*temp; temp2=new node;

top=NULL; temp2->data=item;

void push(int item){ top->next=temp;

if(top==NULL) top=temp2;

{ temp2->next=temp;

temp=new node; temp->next=null;

temp->data=item’ }}

temp->next=NULL; what if overflow?

top=temp; int pop(){

7
If(top==NULL) Int item=temp->data;

{Cout<<”empty”; Top=top->next;

Return NULL;} Delete temp;

Node *temp; Return item;

Temp=top; }

Polish Notations (application of stack)

Infix expression: normal/ human way of expressing mathematical expressions

e.g. 4 + 5 * 5=A+B

Postfix expression:- a notation, in which the operator is written after the operands(reverse polish
notation)

e.g. 4 5 +5*=AB+

Prefix expression:- a notation, in which the operator is written before the operands(polish
notation)

e.g.+ 4 * 5 5=+AB

Result of 4+5*%=45(simple calculator) and 29(scientific cal-correct)

BODMAS, and associativity-human follow this precedence rule

Computers solve arithmetic expressions by restructuring them so the order of each calculation is
embedded in the expression

8
Because the postfix notation is most suitable for a computer to calculate any expression (due
to its reverse characteristic), and is the universally accepted notation for designing Arithmetic
and Logical Unit (ALU) of the CPU (processor).

e.g add(A, B)

But in a postfix expression operands appear before the operator, so there is no need for operator
precedence and other rules. As soon as an operator appears in the postfix expression during
scanning of postfix expression the topmost operands are popped off and are calculated by
applying the encountered operator.

Any expression entered into the computer is first converted into postfix notation, stored in
stack and then calculated.

Eg. Consider again the quadratic formula:


x = (-b+(b^2-4*a*c)^0.5)/(2*a)
In postfix form the formula becomes:
x b @ b 2 ^ 4 a * c * - 0.5 ^ + 2 a * / =
where @ represents the unary - operator.

Consider the postfix expression :


6523+8*+3+*

the first item is a value (6)


so it is pushed onto the stack the next item is a value (5)
so it is pushed onto the stack the next item is a value (2)
so it is pushed onto the stack the next item is a value (3)
so it is pushed onto the stack and the stack becomes
the remaining items are now: + 8 * + 3 + *

9
6*48=288

Exercise (convert to postfix)


a. A+(B-C)
b. A$B*C-D+E/F/(G+H)
c. (A+B)*(C-D)$E*F

Basic Queue Operations


Queue:-an ordered collection of items/ a data structure in which

 addition of a new element takes place at one end called REAR,


 delete takes place at the other end called FRONT.

It is called FIFO (First in First out)

The basic operations that can be performed on queue are

1. Insert (or add) an element to the queue (enqueue).

2. Delete (or remove) an element from a queue (dequeue)

10
Total number in the queue = front-rear+1

Algorithm:-

int FRONT =-1,REAR =-1; Implementation:-


int QUEUESIZE=0;
const int MAX_SIZE=100;
 To enqueue data to the queue int FRONT =-1, REAR =-1;
check if there is space in the queue int QUEUESIZE = 0;
REAR<MAX_SIZE-1 ?
Yes: - Increment REAR void enqueue(int x)
- Store the data in Num[REAR] {
- Increment QUEUESIZE if(QUEUESIZE<MAX_SIZE)
{
FRONT = = -1?
REAR++;
Yes: - Increment FRONT if(REAR = = MAX_SIZE)
No: - Queue Overflow REAR=0;
 To dequeue data from the queue Num[REAR]=x;
check if there is data in the queue QUEUESIZE++;
if(FRONT = = -1)
QUEUESIZE > 0 ? FRONT++;
Yes: - Copy the data in }
Num[FRONT] else
- Increment FRONT cout<<"Queue Overflow";
- Decrement QUEUESIZE }
No: - Queue Underflow
int dequeue()
11
{ FRONT = 0;
int x; QUEUESIZE--;
if(QUEUESIZE>0) }
{ else
x=Num[FRONT]; cout<<"Queue Underflow";
FRONT++; return(x);
if(FRONT = = MAX_SIZE) }

Array implementation of Queues:

Int n=10;

Struct queue{

int data[n];

int front,rear;

};Front=-1;rear=-1;

Void enq(int item) front=0;

{ }

if((rear==n-1 && front=0) | | Int deq()


(rear+1==front))
{int x;
{Cout<<”it is full”;}
If(front==-1)
If(rear==n-1)
{cout<<”queue empty”;
rear=0;
Return null;}
else
Else
rear=rear+1;
{
data[rear]=item;
x=data[front];
if(front==-1)
12
If(front==rear) Else

{front==-1; Front=front+1;

Rear==-1;} }

Else{ Return x;

if(front==n-1) }

Front=0; }

Linked List implementation of Queues:

Struct node{ p->data=x;

Int data; p->nxt=null;

Node *nxt; if(front==null)

}; {rear=front=p;}

*front,*rear; Else{rear->nxt=p;

Front=rear=NULL; Rear=rear->nxt;}

Void enq(int x) }

{ Int deq()

node *p; {

P=new node; If(front==null)


13
{cout<<”empty”;return null;}

Node *p;

Int x;

X=front->data;

P=front;

Front=front->nxt;

Delete p;

Return x;

14
4.2.3 Application of queue

i. Print server- maintains a queue of print jobs


Print()
{
EnqueuePrintQueue(Document)
}
EndOfPrint()
{
DequeuePrintQueue()
}
ii. Disk Driver- maintains a queue of disk input/output requests
iii. Task scheduler in multiprocessing system- maintains priority queues of processes
iv. Telephone calls in a busy environment –maintains a queue of telephone calls
v. Simulation of waiting line- maintains a queue of persons

Find the prefix and postfix notation for the following infix
expression:
(a + b – c) * (e / f) – ( g – h/i)
There is a quick way to convert from one notation to another. You start by inserting all
the implicit brackets/parentheses that determine the order of evaluation, regardless of
what notation the expression is already in. So, taking the expression above and adding
these implicit brackets gives:

This is before:
(a + b - c) * (e / f) - ( g - h/i)

This is after adding the implicit parentheses:


( ( ( (a + b) - c) * (e / f)) - ( g - (h/i)))

Postfix vs. Prefix Notation


If you want to convert to postfix notation, you would move the operator to the end of the
bracketed expression, right before the closing brace. To convert to prefix notation, you
would move the operator to the beginning of the bracketed expression, right after the
opening brace. So, (h/i) in postfix notation would look like (h i /), and in prefix notation would

15
look like (/ h i ). Do this for every operator in a bracket. So, converting the expression above
to prefix notation will give you:

Moving all the operators to the beginning of the


bracketed expression for prefix notation gives us:
( - ( * ( - ( + a b) c) ( / e f)) ( - g ( / h i ) ) )

And finally, removing all the parentheses gives us our final prefix notation:

- * - + a b c / e f - g / h i

Try figuring out how to get the postfix notation on your own using the rules given above. You
should get this as your answer:

a b + c - e f / * g h i / - -

 A binary tree is composed of zero or more nodes

 Each node contains:

 A value (some sort of data item)

 A reference or pointer to a left child (may be null), and

 A reference or pointer to a right child (may be null)

 A binary tree may be empty (contain no nodes)

 If not empty, a binary tree has a root node

 Every node in the binary tree is reachable from the root node by
a unique path

 A node with neither a left child nor a right child is called a leaf

 In some binary trees, only the leaves contain a value

16
Picture of a binary tree
a

b c

d e f

g h i j k

17
Size and depth
a
The size of a binary
tree is the number
b c
of nodes in it
d e f
This tree has size 12
g h i j k
The depth of a
l node is its distance
from the root
Balancea is at depth zero
e is at depth 2
a a
b The depth
c b of a
c e is the
d e f g binary tree
d f
hi j depth ofgits
A balanced h
i node
deepest j
binary tree An unbalanced
A binary tree is balanced Thisbinary
treeif has treedepth
every level4
above the lowest is “full” (contains 2n
nodes)
In most applications, a reasonably balanced
 A binary tree is defined recursively: it consists of a root, a left
binary tree
subtree, and is desirable
a right subtree

18
 To traverse (or walk) the binary tree is to visit each node in the binary
tree exactly once

 Tree traversals are naturally recursive

 Since a binary tree has three “parts,” there are six possible ways to
traverse the binary tree:

 root, left, right

 left, root, right

Tree traversals using


 left, right, root

“flags”
The order in which the nodes are
visited during a tree traversal can be
easily determined by imagining there
preo attachedinord
is a “flag” to each node,post
as
To traverse
rder the tree,er
follows:A collect
A
the flags:
orde
A
r
B C B C B C
D E F G D E F G D E F G
ABDEC DBEAF DEBFG
FG CG CA

 The depth of a node is the number of edges from the root to the node.
 The height of a node is the number of edges from the node to the deepest leaf.
 The height of a tree is a height of the root.
 A full binary tree.is a binary tree in which each node has exactly zero or two
children.
 A complete binary tree is a binary tree, which is completely filled, with the
possible exception of the bottom level, which is filled from left to right.
19
A complete binary tree is very special tree, it provides the best possible ratio between
the number of nodes and the height. The height h of a complete binary tree with N
nodes is at most O(log N). We can easily prove this by counting nodes on each level,
starting with the root, assuming that each level has the maximum number of nodes:
n = 1 + 2 + 4 + ... + 2h-1 + 2h = 2h+1 - 1

Solving this with respect to h, we obtain


h = O(log n)

where the big-O notation hides some superfluous details.

Advantages of trees

Trees are so useful and frequently used, because they have some very serious
advantages:

 Trees reflect structural relationships in the data


 Trees are used to represent hierarchies
 Trees provide an efficient insertion and searching
 Trees are very flexible data, allowing to move subtrees around with minumum
effort

Traversals
A traversal is a process that visits all the nodes in the tree. Since a tree is a nonlinear
data structure, there is no unique traversal. We will consider several traversal
algorithms with we group in the following two kinds

 depth-first traversal
 breadth-first traversal

20
There are three different types of depth-first traversals,:

 Pre Order traversal - visit the parent first and then left and right children;
 In Order traversal - visit the left child, then the parent and the right child;
 Post Order traversal - visit left child, then the right child and then the parent;

There is only one kind of breadth-first traversal--the level order traversal. This
traversal visits nodes by levels from top to bottom and from left to right.

As an example consider the following tree and


its four traversals:

Pre Order - 8, 5, 9, 7, 1, 12, 2, 4, 11, 3


In Order - 9, 5, 1, 7, 2, 12, 8, 4, 3, 11
Post Order - 9, 1, 2, 12, 7, 5, 3, 11, 4, 8
Level Order - 8, 5, 4, 9, 7, 11, 1, 12, 3, 2

In the next picture we demonstarte the order of node visitation. Number 1 denote the
first node in a particular traversal and 7 denote the last node.

These common traversals can be represented as a single algorithm by assuming that


we visit each node three times. An Euler tour is a walk around the binary tree where
each edge is treated as a wall, which you cannot cross. In this walk each node will be
visited either on the left, or under the below, or on the right. The Euler tour in which
we visit nodes on the left produces a preorder traversal. When we visit nodes from the
21
below, we get an inorder traversal. And when we visit nodes on the right, we get a
postorder traversal.

Binary Search Trees We consider a particular kind of a binary tree called a


Binary Search Tree (BST). The basic idea behind this data structure is to have such a
storing repository that provides the efficient way of data sorting, searching and
retriving.

A BST is a binary tree where nodes are ordered


in the following way:

 each node contains one key (also known


as data)
 the keys in the left subtree are less then
the key in its parent node, in short L < P;
 the keys in the right subtree are greater
the key in its parent node, in short P < R;
 duplicate keys are not allowed.

In the following tree all nodes in the left subtree


of 10 have keys < 10 while all nodes in the right
subtree > 10. Because both the left and right
subtrees of a BST are again search trees; the
above definition is recursively applied to all
internal nodes:

Insertion

22
The insertion procedure is quite similar to searching. We start at the root and
recursively go down the tree searching for a location in a BST to insert a new node. If
the element to be inserted is already in the tree, we are done (we do not insert
duplicates). The new node will always replace a NULL reference.

Exercise. Given a sequence of numbers:


11, 6, 8, 19, 4, 10, 5, 17, 43, 49, 31

Draw a binary search tree by inserting the above numbers from left to right.

Searching

Searching in a BST always starts at the root. We compare a data stored at the root
with the key we are searching for (let us call it as toSearch). If the node does not
contain the key we proceed either to the left or right child depending upon
comparison. If the result of comparison is negative we go to the left child, otherwise -
to the right child. The recursive structure of a BST yields a recursive algorithm.

Searching in a BST has O(h) worst-case runtime complexity, where h is the height of
the tree. Since s binary search tree with n nodes has a minimum of O(log n) levels, it
takes at least O(log n) comparisons to find a particular node. Unfortunately, a binary
serch tree can degenerate to a linked list, reducing the search time to O(n).

Deletion

23
Deletion is somewhat more tricky than insertion. There are several cases to consider.
A node to be deleted (let us call it as toDelete)

 is not in a tree;
 is a leaf;
 has only one child;
 has two children.

If toDelete is not in the tree, there is nothing to delete. If toDelete node has only
one child the procedure of deletion is identical to deleting a node from a linked list -
we just bypass that node being deleted

Deletion of an internal node with two children is less straightforward. If we delete


such a node, we split a tree into two subtrees and therefore, some children of the
internal node won't be accessible after deletion. In the picture below we delete 8:

Deletion starategy is the following: replace the node being deleted with the largest
node in the left subtree and then delete that largest node. By symmetry, the node being
deleted can be swapped with the smallest node is the right subtree.

Exercise. Given a sequence of numbers:


24
11, 6, 8, 19, 4, 10, 5, 17, 43, 49, 31

Draw a binary search tree by inserting the above numbers from left to right and then
show the two trees that can be the result after the removal of 11.

25

You might also like