0% found this document useful (0 votes)
40 views40 pages

DSAL - Assignment No 1 - 2-3writups

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)
40 views40 pages

DSAL - Assignment No 1 - 2-3writups

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/ 40

1.

Searching and Sorting


AIM: To implement various searching and sorting algorithms on database of students
implemented using array of structure.

OBJECTIVE:
1. To study the concepts of array of structure.
2. To understand the concepts, algorithms and applications of Sorting.
3. To understand the concepts, algorithms and applications of Searching.

THEORY:

1. Structure:
Structure is collection of heterogeneous types of data. In C++, a structure collects different
data items in such a way that they can be referenced as a single unit. Data items in a
structure are called fields or members of the structure.

Creating a Structures:
struct student
{
int roll_no;
char name[15];
float sgpa;

};
Here struct is keyword used to declare a structure. student is the name of the structure. In this
example, there are three types of variables int, char and float. The variables have their own
names, such as roll_no, name, sgpa.
Structure is represented as follows:

int char name[15] float sgpa


roll_no
2 bytes 15 bytes (1 byte for each char) 4 bytes

Declaring Structure Variables:


After declaring a structure, you can define the structure variables. For instance, the following
structure variables are defined with the structure data type of automobile from the previous
section:

struct student s1, s2, s3;

Here three structure variables, s1, s2, s3 are defined by the structure of student. All three
structure variables contain the three members of the structure student.

Referencing Structure Members with the Dot Operator:


1
Given the structure student and s1 is variable of type struct student we can access the fields
in following way:
s1.roll_no
s1.name
s1.sgpa
Here the structure name and its member's name are separated by the dot (.) operator.

Pointer to Structure:
We can declare a pointer variable which is capable of storing the address of a structure
variable as follows:
struct student *ptr;

Suppose if we have structure variable declared as:


struct student s1;

Then ptr can store the address of s1 by:


ptr = &s1;

Referencing a Structure Member with -> (arrow operator)


Using ptr we can access the fields of s1 as follows:
ptr->name or (*ptr).name
Because of its clearness, the -> operator is more frequently used in programs than the dot
operator.

2. Array of Structure:
To declare an array of a structures, we first define a structure and then declare an array
variable of that type. To declare an 20 element array of structures of type student define
earlier, we write,
struct student s[20];
This creates 20 sets of variables that are organized as defined in the structure student.
To access a specific structure, index the array name. For example, to print the name of 4 th
customer, we write
cout<< s[3].name;

3. Sorting:
It is the process of arranging or ordering information in the ascending or descending order of
the key values.
⮚ Bubble Sort
This is one of the simplest and most popular sorting methods. The basic idea is to pass
through the array sequentially several times. In each pass we compare successive pairs of
elements ( A[i] with A[i+1] ) and interchange the two if they are not in the required order. One
element is placed in its correct position in each pass. In the first pass, the largest element will
sink to the bottom, second largest in the second pass and so on. Thus, a total of n-1 passes
are required to sort ‘n’ keys.

Analysis:
In this sort, n-1 comparisons takes place in 1st pass , n-2 in 2nd pass , n-3 in 3rd pass , and so
2
on.
Therefore total number of comparisons will be
(n-1) + (n-2) + (n-3) + ……. + 3 + 2 + 1
This is an Arithmetic series in decreasing order
Sum = n/2 [2a + (n-1)d]
Where, n = no. of elements in series , a = first element in the series
d = difference between second element and first element.
Sum = (n-1) / 2 [ 2 * 1 + ((n-1) - 1) * 1 ]
= n(n-1) / 2
which is of order n2 i.e O(n2)
The main advantage is simplicity of algorithm and it behaves as O(n) for sorted array of
element. Additional space requirement is only one temporary variable.

Example:
Compare two consecutive elements, if first element is greater than second then interchange
the elements else no change.
Pass 1:

Pass 2:

Pass 3:

3
Pass 4:

⮚ Insertion Sort
Insertion sort works similarly as we sort cards in our hand in a card game.
We assume that the first card is already sorted then, we select an unsorted card. If the
unsorted card is greater than the card in hand, it is placed on the right otherwise, to the left. In
the same way, other unsorted cards are taken and put at their right place. A similar approach
is used by insertion sort.
Insertion sort is a sorting algorithm that places an unsorted element at its suitable place in
every iteration.

Analysis:
Worst Case Complexity: O(n2)
Suppose, an array is in ascending order, and you want to sort it in descending order. In this
case, worst case complexity occurs.
Each element has to be compared with each of the other elements so, for every nth element,
(n-1) number of comparisons are made.
Thus, the total number of comparisons = n*(n-1) ~ n2

Best Case Complexity: O(n)


When the array is already sorted, the outer loop runs for n number of times whereas the inner
loop does not run at all. So, there are only n number of comparisons. Thus, complexity is
linear.

Average Case Complexity: O(n2)


It occurs when the elements of an array are in jumbled order (neither ascending nor
descending).

4
Example:
Suppose we need to sort the following array.

1. The first element in the array is assumed to be sorted. Take the second element and store
it separately in key.
Compare key with the first element. If the first element is greater than key, then key is
placed in front of the first element.

2. Now, the first two elements are sorted.


Take the third element and compare it with the elements on the left of it. Placed it just
behind the element smaller than it. If there is no element smaller than it, then place it at
-------the beginning of the array.

3. Similarly, place every unsorted element at its correct position.


Place 4 behind 1

5
Place 3 behind 1 and the array is sorted:

⮚ Quick Sort
Quicksort is an algorithm based on divide and conquers approach in which the array is split
into subarrays and these sub-arrays are recursively called to sort the elements.

Analysis:
Worst Case Complexity [Big-O]: O(n2)
It occurs when the pivot element picked is either the greatest or the smallest element. This
condition leads to the case in which the pivot element lies in an extreme end of the sorted
array. One sub-array is always empty and another sub-array contains n - 1 elements. Thus,
quicksort is called only on this sub-array. However, the quick sort algorithm has better
performance for scattered pivots.

Best Case Complexity [Big-omega]: O(n*log n)


6
It occurs when the pivot element is always the middle element or near to the middle element.

Average Case Complexity [Big-theta]: O(n*log n)


It occurs when the above conditions do not occur.

Example:

Step by Step Process for QS (A, 0, 6)

● Searching:
Searching is a process of retrieving or locating a record with a particular key value.

⮚ Linear Search

7
Linear search is the simplest searching algorithm that searches for an element in a list in
sequential order. We start at one end and check every element until the desired element is
not found.
Analysis:
Time Complexity: O(n)
Space Complexity: O(1)

Example:

⮚ Binary Search
This is a very efficient searching method used for linear / sequential data. In this search, Data
has to be in the sorted order either ascending or descending. Sorting has to be done based
on the key values.
In this method, the required key is compared with the key of the middle record. If a match is
found, the search terminates. If the key is less than the record key, the search proceeds in the
left half of the table. If the key is greater than record key, search proceeds in the same way in
the right half of the table. The process continues till no more partitions are possible. Thus
every time a match is not found, the remaining table size to be searched reduces to half.
If we compare the target with the element that is in the middle of a sorted list, we have three
possible results: the target matches, the target is less than the element, or the target is
greater than the element. In the first and best case, we are done. In the other two cases, we
learn that half of the list can be eliminated from consideration.
When the target is less than the middle element, we know that if the target is in this ordered
list, it must be in the list before the middle element. When the target is greater than the middle
element, we know that if the target is in this ordered list, it must be in the list after the middle
element. These facts allow this one comparison to eliminate one-half of the list from
consideration. As the process continues, we will eliminate from consideration, one-half of
what is left of the list with each comparison. This technique is called as binary search.

Analysis:
After 0 comaparisons 🡪 Remaining file size = n
After 1 comaparisons 🡪 Remaining file size = n / 2 = n / 21
After 2 comaparisons 🡪 Remaining file size = n / 4 = n / 22
After 3 comaparisons 🡪 Remaining file size = n / 8 = n / 23
8
……
After k comaparisons 🡪 Remaining file size = n / 2k

The process terminates when no more partitions are possible i.e. remaining file size = 1
n / 2k = 1
k = log2n
Thus, the time complexity is O(log2n). which is very efficient.

Example:

1. ALGORITHM / PSEUDOCODE :
⮚ Create a structure

Algorithm Create_database(struct student s[] )


Step 1 : Start
Step 2 : Accept how many records user need to add, say, no of records as n
Step 3 : For i = 0 to n – 1
Step 4 : Accept the record and store it in s[i]
Step 5 : End For
Step 6 : Return n

9
Algorithm Display_database(struct student s[] ,int n)
Step 1 : Start
Step 2 : For i = 0 to n – 1
Step 3 : Display the fields s.roll_no, s.name, s.sgpa
s = s + 1 // s will point to the next record
Step 4 : End For
Step 5: Stop

⮚ Algorithm for Bubble Sort student according to sort to roll numbers

Step 1 : Start
Step 2 : For Pass = 1 to n-1
Step 3 : For i = 0 to (n – pass – 1)
Step 4 : If s[i].roll_no < s[i+1].roll_no
Step 5 : Swap (s[i]. s[i+1])
Step 6 : End if
Step 7 : End for
Step 8 : End For
Step 9: Stop

⮚ Algorithm for Insertion Sort to sort student on the basis of names

Algorithm insertion_Sort (Struct student S[], int n)

Step 1 : Start
Step 2 : For i = 1 to n-1
Step 3 : Set key to s[i]
Step 4 : Set j to i-1
Step 5 : While j>=0 AND strcmp(s[i].name,key.name)>0
Step 6 : Assign s[j] to s[j+1]
Step 7 : Decrement j
Step 10 : End While
Step 11 : Assign key to s[j+1]
Step 12 : End for
Step 13 : Stop

⮚ Algorithm for Quick Sort to sort students on the basis of their sgpa.

Algorithm partition ( struct student s[], int l, int h) where s is the array of structure , l
is the index of starting element and h is the index of last element.

Step 1 : Start
Step 2 : Select s[l].sgpa as the pivot element
Step 3 : Set i = l
Step 4 : Set j = h-1
Step 5 : While i ≤ j
Step 6 : Increment i till s[i].sgpa ≤ pivot element
Step 7 : Decrement j till s[j].sgpa > pivot element
10
Step 8 : If i < j
Step 9 : Swap(s[i], s[j])
Step 10 : End if
Step 11: End while
Step 12 : Swap(s[j],s[l])
Step 13: return j
Step 14 : End

Algorithm quicksort( struct student s[], int l, int h) where s is the array of structure , l
is the index of starting element and h is the index of last element.
Step 1 : Start
Step 2 : If l<h
Step 3 : P=partition(s,l,h)
Step 4 : quicksort (s,l,p-1)
Step 5 : quicksort (s,p+1,h)
Step 6 : End

⮚ Algorithm for Linear Search to search students with sgpa given and display all of them

Algorithm linearS(struct student s[], float key, int n) Here s is array of structure
student, key is sgpa of student to be searched and displayed, n is total number of
students in record

Step 1 : Start
Step 2 : Set i to 0 and flag to 0
Step 3 : While i<n
Step 4 : If s[i].sgpa==key
Step 5 : Print s[i].roll_no, s[i].name
Step 6 : Set flag to 1
Step 7 : i++
Step 8 : End while
Step 9 : If flag==0
Step 10 : Print No student found with sgpa=value of key
Step 11: End if
Step 12 : End

⮚ Algorithm for Binary Search to search students having given string in their names

Algorithm Binary_Search (s, n , Key ) Where s is an array of structure , n is the no of


records, and key is element to be searched
Step 1 : Start
Step 2 : Set l = 0 & h = n-1
Step 3 : While l ≤ h
Step 4 : mid = (l + h ) / 2
Step 5 : If strcmp (s[mid].name, key)==0)
Step 6 : Return 1 // Found
11
Step 7 : Else
Step 8 : If strcmp (key, s[mid].name)<0
Step 9 : h = mid – 1
Step 10 : Else
Step 11 : l = mid + 1
Step 12 : End if
Step 13 : End if
Step 14 : End while
Step 15 : Return 0 // Not found

Test cases/validation:
● Roll numbers should not repeat
● Name should only contain alphabets
● Before going for e (binary search) records should be sorted according o names.
● Records can be enter in 3 ways and can check number of passes in each sorting algorithm: sorted, unsorted
and partially sorted
● For d and e give input which is not present in record

Application:
Useful in managing large amount of data.

FAQ:

12
 What is the need of sorting
 What is searching?
 How to get output after each pass?
 What do you mean by PASS?
 What is recursion?
 Where the values are stored in recursion?
 Explain the notation Ω, θ, О for time analysis.
 Explain the time complexity of bubble sort and linear search, binary search.

 What is need of structure?


 What are the differences between a union and a structure?
 Which operators are used to refer structure member with and without pointer?
 List the advantages and disadvantages of Sequential / Linear Search?
 List the advantages and disadvantages of binary Search?
 What you mean by internal & External Sorting?
 Analyze Quick sort with respect to Time complexity
 In selecting the pivot for QuickSort, which is the best choice for optimal partitioning:
a) The first element of the array
b) The last element of the array
c) The middle element of the array
d) The largest element of the array
e) The median of the array
f) Any of the above?
 Explain the importance of sorting and searching in computer applications?
 Analyze bubble sort with respect to time complexity.
 What is Divide and conquer methodology?
 How the pivot is selected and partition is done in quick sort?

 What is the complexity of quick sort?

13
2. Implementation of Stack

AIM: Write a program to implement stack as an abstract data type using linked list and
use this ADT for conversion of infix expression to postfix, prefix and evaluation of
postfix/prefix expression.

OBJECTIVE:

1) To understand the concept of abstract data type.


2) How different data structures such as arrays and a stacks are represented as an
ADT.

THEORY:

What is an abstract data type?

An Abstract Data type is defined as a mathematical model of the data objects that
make up a data type as well as the functions that operate on these objects. There are no
standard conventions for defining them. A broad division may be drawn between
"imperative" and "functional" definition styles. In general terms, an abstract data type is a
specification of the values and the operations that has two properties:

 It specifies everything you need to know in order to use the data type
 It makes absolutely no reference to the manner in which the data type will be
implemented.

When we use abstract data types, our programs divide into two pieces:
 The Application: The part that uses the abstract data type.
 The Implementation: The part that implements the abstract data type.

1. Concept of Linear data structure using linked organization


Linked lists provides a way to represent an ordered or linear list, in which each item in the list
is a part of structure that also contains a “link” to the structure containing the next item. Each
item has only one predecessor and only one successor.
Each structure of the list is called as a ‘node’ & it consists of two fields,
i) One containing the ‘item’ &
ii) Second containing the ‘address’ of the next ‘node’.

▪ A linked list therefore can be defined as a collection of structures ordered not by their
physical placement in memory (like an array} but by logical links that are stored as part of
data in the structure or a node itself. The link is in the form of pointer to another structure or
node of the same type.
▪ Such a structure is represented as follows:
14
struct node
{
<data type> item;
struct node *next;
};
For example, consider the following ordered list stored as a linked list
L = {BAT, CAT, FAT, MAT, WAT}
head

a1 a2 a3 a4 a5
BAT CA FAT MAT WAT 0
T
Node 1 Node 2 Node 3 Node 4
Node 5

Dynamic Memory Management:

1) Allocating a block of memory using new operator:


new operator allocates memory of specified size & returns a pointer of specified type .
The format is,
node *newp;
newp = new node;
where ‘newp’ is a pointer of type node, pointing to a block of memory of size node and
it is NULL if not enough space is available.
2) Releasing the used memory space using delete operator:
The format is,
delete newp;
will release a memory block allocated by new operator pointed by pointer ‘newp’.

Types of Linked Lists:

1. Singly Linked List (SLL)


head
A B C 0

2. Circular Singly Linked List (CSLL)


head

A B C

15
3. Doubly Linked List (DLL)
head
A B C

4. Circular Doubly Linked List (CDLL)


head
A B C

2. Example of Linear data structure


Data structure whose elements (objects) are sequential and ordered in a way so that:
● there is only one first element and has only one next element,
● there is only one last element and has only one previous element, while all other elements
have a next and a previous element
Arrays, Strings, Stack, Queue, Lists

3. Stack :

i. Concept
Stacks are more common data objects found in computer algorithms. It is a special case of
more general data object, an ordered or linear list. It can be defined as an ordered list, in
which all insertions & deletions are made at one end, called as ‘top’ i.e. Last element inserted
is outputted first (Last In First Out or LIFO).
Stack can be represented mathematically as:
S = {a1, a2, …,an} where a1 is the bottommost element & a n is topmost element. & a i+1 is on
the top of the element ai , 1 < i <= n.
ii. Definition of stack
In computer science, a stack is a last in, first out (LIFO) abstract data type and data
structure. A stack can have any abstract data type as an element, but is characterized by only
two fundamental operations: push and pop. The push operation adds an item to the top of the
stack, hiding any items already on the stack, or initializing the stack if it is empty. A pop either
reveals previously concealed items, or results in an empty stack. A stack is a restricted data
structure, because only a small number of operations are performed on it. The nature of the
pop and push operations also mean that stack elements have a natural order. Elements are
removed from the stack in the reverse order to the order of their addition: therefore, the lower
elements are those that have been on the stack the longest. A collection of items in which
only the most recently added item may be removed. The latest added item is at the top. Basic
16
operations are push and pop. Often top and isEmpty are available, too. Also known as "last-
in, first-out" or LIFO.
iii. Terminology with stack
An abstract data type (ADT) consists of a data structure and a set of primitives
a. Initialise creates/initialises the stack
b. Push adds a new element
c. Pop removes a element
d. IsEmpty reports whether the stack is empty
e. IsFull reports whether the stack is full
f. Destroy deletes the contents of the stack (may be implemented by re-initialising the
stack)
iv. Diagram (vertical view)
Given below is a pictorial representation of Stack.

As shown above, there is a pile of plates stacked on top of each other. If we want to add
another item to it, then we add it at the top of the stack as shown in the above figure (left-
hand side). This operation of adding an item to stack is called “Push”.
On the right side, we have shown an opposite operation i.e. we remove an item from the
stack. This is also done from the same end i.e. the top of the stack. This operation is called
“Pop”.
As shown in the above figure, we see that push and pop are carried out from the same
end. This makes the stack to follow LIFO order. The position or end from which the items are
pushed in or popped out to/from the stack is called the “Top of the stack”.
Initially, when there are no items in the stack, the top of the stack is set to -1. When we
add an item to the stack, the top of the stack is incremented by 1 indicating that the item is
added. As opposed to this, the top of the stack is decremented by 1 when an item is popped
out of the stack

17
4. ADT of Stack
Define Structure for stack(Data, Next Pointer)
● Stack Empty:
Return True if Stack Empty else False.
Top is a pointer of type structure stack.
Empty(Top)
Step 1: if Top == NULL
Step 2: return 1;
Step 3: else return 0;
● Push Operation:
Top & Node pointer of structure Stack.
Push(element)
Step 1: Node->data = element;
Step 2: Node->Next = Top;
Step 3: Top = Node
Step 4: Stop.
● Pop Operation:
Top & Temp pointer of structure Stack.
Pop()
Step 1:if Top != NULL
Then
i) Temp = Top;
ii) element=Temp->data;
iiI) Top = (Top)->Next;
iv) delete temp;
Step 2: Else Stack is Empty.
Step 3: return element;

5. Realization of Stack ADT


i. Using Sequential organization (Array)
The three basic stack operations are push, pop, and stack top. Push is used to insert data into
the stack. Pop removes data from a stack and returns the data to the calling module. Stack top
returns the data at the top of t`he stack without deleting the data from the stack.

Push
18
Push adds an item at the top of the stack. After the push, the new item becomes the top. The
only potential problem with this simple operation is that we must ensure that there is room for the
new item. If there is not enough room, the stack is in an overflow state and the item cannot be
added.
Following figure shows the push stack operation.

Fig.: Push Stack operation


Pop
When we pop a stack, we remove the item at the top of the stack and return it to the user.
Because we have removed the top item, the next older item in the stack becomes the top. When
the last item in the stack is deleted, the stack must be set to its empty state. If pop is called when
the stack is empty, it is in an underflow state. The pop stack operation is shown in following figure

Fig.: Pop Stack operation

Stack top
The third stack operation is stack top. Stack top copies the item at the top of the stack; that is, it
returns the data in the top element to the user but does not delete it. You might think of this
operation as reading the stack top. Stack top can also result in underflow if the stack is empty.
The stack top operation is shown in following figure

Fig.: Stack top operation

Following figure traces these three operations in an example. We start with an empty stack and
push green and blue into the stack. At this point the stack contains two entries. We then pop blue
from the top of the stack, leaving green as the only entry. After pushing red, the stack again
contains two entries. At this point we retrieve the top entry, red, using stack top. Note that stack
top does not remove red from the stack; it is still the top element. We then pop red, leaving green
19
as the only entry. When green is popped, the stack is again empty. Note also how this example
demonstrates the last in–first out operation of a stack.
Although green was pushed first, it is the last to be popped.

Fig.: Stack Example


ii. Using Linked organization (Linked list)
To implement the linked list stack, we need two different structures, a head and a data node. The
head structure contains metadata—that is, data about data—and a pointer to the top of the stack.
The data structure contains data and a link pointer to the next node in the stack. The conceptual
and physical implementations of the stack are shown in following figure.

Fig.: Conceptual and Physical Stack Implementations


20
Stack Head
Generally, the head for a stack requires only two attributes: a top pointer and a count of the
number of elements in the stack. These two elements are placed in a structure. Other stack
attributes can be placed here also. For example, it is possible to record the time the stack was
created and the total number of items that have ever been placed in the stack. These two
metadata items allow the user to determine the average number of items processed through the
stack in a given period. Of course, we would do this only if such a statistic were required for some
reason. A basic head structure is shown in Figure.

Stack Data Node


The rest of the data structure is a typical linked list data node. Although the application
determines the data that are stored in the stack, the stack data node looks like any linked list
node. In addition to the data, it contains a link pointer to other data nodes, making it a self-
referential data structure. In a self-referential structure, each instance of the structure contains a
pointer to another instance of the same structure. The stack data node is also shown in following
figure

Fig.: Stack head, Stack Data node structure

We use the design shown in following figure, which demonstrates the four most common stack
operations: create stack, push stack, pop stack, and destroy stack. Operations such as stacktop
are not shown in the figure because they do not change the stack structure.

21
Fig.: Stack Operations

Push Stack
Push stack inserts an element into the stack. The first thing we need to do when we push data
into a stack is find memory for the node. We must therefore allocate a node from dynamic
memory. Once the memory is allocated, we simply assign the data to the stack node and then set
the link pointer to point to the node currently indicated as the stack top. We also need to update
the stack top pointer and add 1 to the stack count field. Figure traces a push stack operation in
which a new pointer (pNew) is used to identify the data to be inserted into the stack.
To develop the insertion algorithm using a linked list, we need to analyze three different stack
conditions: (1) insertion into an empty stack, (2) insertion into a stack with data, and (3) insertion
into a stack when the available memory is exhausted. The first two of these situations are shown
in Figure 3-8. The third is an error condition.

Fig.: Push Stack Example

When we insert into a stack that contains data, the new node’s link pointer is set to point to the
node currently at the top, and the stack’s top pointer is set to point to the new node. When we
22
insert into an empty stack, the new node’s link pointer is set to null and the stack’s top pointer is
set to point to the new node. However, because the stack’s top pointer is null, we can use it to set
the new node’s link pointer to null. Thus the logic for inserting into a stack with data and the logic
for inserting into an empty stack are identical.
Pop Stack
Pop stack sends the data in the node at the top of the stack back to the calling algorithm. It then
adjusts the pointers to logically delete the node. After the node has been logically deleted, it is
physically deleted by recycling the memory that is, returning it to dynamic memory. After the
count is adjusted by subtracting 1, the algorithm returns the status to the caller: if the pop was
successful, it returns true; if the stack is empty when pop is called, it returns false. The operations
for pop stack are traced in Figure.

Fig.: Pop Stack Example

6. Application of Stack
Stack applications can be classified into four broad categories:
i. reversing data (Conversion of decimal number into binary number)
ii. parsing data (Parenthesis matching)
iii. postponing data usage (Expression conversion and evaluation)
iv. backtracking steps (Goal seeking and the eight queens problem)

1. Expression conversion and stack

i. Need for expression conversion


One of the disadvantages of the infix notation is that we need to use parentheses to control the
evaluation of the operators. We thus have an evaluation method that includes parentheses and
two operator priority classes. In the postfix and prefix notations, we do not need parentheses;
each provides only one evaluation rule.
Although some high-level languages use infix notation, such expressions cannot be directly
evaluated. Rather, they must be analyzed to determine the order in which the expressions are to
be evaluated.
ii. What is Polish Notation?
Conventionally, we use the operator symbol between its two operands in an arithmetic
expression.

23
A+B C–D*E A*(B+C)
We can use parentheses to change the precedence of the operators. Operator precedence is
pre-defined. This notation is called INFIX notation. Parentheses can change the precedence of
evaluation. Multiple passes required for evaluation. Named after Polish mathematician Jan
Named after Polish mathematician Jan Lukasiewicz
Reverse Polish (POSTFIX) notation refers to the notation in which the operator symbol is placed
after its two operands.
AB+ CD* AB*CD+/
Polish PREFIX notation refers to the notation in which the operator symbol is placed before its
two operands.
+AB *CD /*AB-CD
iii. Advantages Polish notations over infix
expression
a. No concept of operator priority.
b. Simplifies the expression evaluation rules.
c. No need of any parenthesis, Hence no ambiguity in the order of evaluation.
d. Evaluation can be carried out using a single scan over the expression string.
iv. Conversion of infix to postfix.
We can also use a stack to convert an expression in standard form (otherwise known as
infix) into postfix. We will concentrate on a small version of the general problem by allowing
only the operators +, *, (, ), and insisting on the usual precedence rules. We will further
assume that the expression is legal. Suppose we want to convert the infix expression
a+b*c+(d*e+f)*g
into postfix. A correct answer is a b c * + d e * f + g * +.
When an operand is read, it is immediately placed onto the output. Operators are not
immediately output, so they must be saved somewhere. The correct thing to do is to place
operators that have been seen, but not placed on the output, onto the stack. We will also
stack left parentheses when they are encountered. We start with an initially empty stack.
If we see a right parenthesis, then we pop the stack, writing symbols until we encounter a
(corresponding) left parenthesis, which is popped but not output.
If we see any other symbol (+, *, (), then we pop entries from the stack until we find an
entry of lower priority. One exception is that we never remove a (from the stack except when
processing a ). For the purposes of this operation, + has lowest priority and (highest.
When the popping is done, we push the operator onto the stack.
Finally, if we read the end of input, we pop the stack until it is empty, writing symbols onto
the output.
The idea of this algorithm is that when an operator is seen, it is placed on the stack. The
stack represents pending operators. However, some of the operators on the stack that have
high precedence are now known to be completed and should be popped, as they will no

24
longer be pending. Thus prior to placing the operator on the stack, operators that are on the
stack, and which are to be completed prior to the current operator, are popped.
This is illustrated in the following table:

Expressio Stack When Third Operator Is Action


n Processed

a*b-c+d - - is completed; + is pushed

a/b+c*d + Nothing is completed; * is


pushed

a-b*c/d -* *is completed; / is pushed

a-b*c+d -* *and - are completed; + is


pushed

Parentheses simply add an additional complication. We can view a left parenthesis as a high-
precedence operator when it is an input symbol (so that pending operators remain pending) and
a low-precedence operator when it is on the stack (so that it is not accidentally removed by an
operator). Right parentheses are treated as the special case.
To see how this algorithm performs, we will convert the long infix expression above into its
postfix form. First, the symbol a is read, so it is passed through to the output.
Then + is read and pushed onto the stack. Next b is read and passed through to the output.
The state of affairs at this juncture is as follows:

Next, a * is read. The top entry on the operator stack has lower precedence than *, so nothing is
output and * is put on the stack. Next, c is read and output. Thus far, we have

The next symbol is a +. Checking the stack, we find that we will pop a * and place it on the
output; pop the other +, which is not of lower but equal priority, on the stack; and then push the +.

The next symbol read is a (. Being of highest precedence, this is placed on the stack. Then d is
read and output.

25
We continue by reading a *. Since open parentheses do not get removed except when a closed
parenthesis is being processed, there is no output. Next, e is read and output.

The next symbol read is a +. We pop and output * and then push +. Then we read and output f.

Now we read a ), so the stack is emptied back to the (. We output a +.

We read a * next; it is pushed onto the stack. Then g is read and output.

The input is now empty, so we pop and output symbols from the stack until it is empty.

As before, this conversion requires only O(N) time and works in one pass through the input. We
can add subtraction and division to this repertoire by assigning subtraction and addition equal
priority and multiplication and division equal priority. A subtle point is that the expression a - b - c
will be converted to a b - c - and not a b c - -. Our algorithm does the right thing, because these
operators associate from left to right. This is not necessarily the case in general, since
exponentiation associates right to left: = 28 = 256, not 43 = 64. We leave as an exercise the
problem of adding exponentiation to the repertoire of operators.

Let’s work on one more example before we formally develop the algorithm.
A + B * C – D / E converts to A B C * + D E / -
The transformation of this expression is shown in following figure. Because it uses all of the basic
arithmetic operators, it is a complete test.

26
Fig.: Infix Transformation
We begin by copying the first operand, A, to the postfix expression. See Figure (b). The add
operator is then pushed into the stack and the second operand is copied to the postfix
expression. See Figure (d). At this point we are ready to insert the multiply operator into the
stack. As we see in Figure (e), its priority is higher than that of the add operator at the top of the
stack, so we simply push it into the stack. After copying the next operand, C, to the postfix
expression, we need to push the minus operator into the stack. Because its priority is lower than
that of the multiply operator, however, we must first pop the multiply and copy it to the postfix
expression. The plus sign is now popped and appended to the postfix expression because the
minus and plus have the same priority. The minus is then pushed into the stack. The result is
shown in Figure (g). After copying the operand D to the postfix expression, we push the divide
operator into the stack because it is of higher priority than the minus at the top of the stack in
Figure (i).
After copying E to the postfix expression, we are left with an empty infix expression and two
operators in the stack. See Figure (j). All that is left at this point is to pop the stack and copy each
operator to the postfix expression. The final expression is shown in Figure (k).
We are now ready to develop the algorithm. We assume only the operators shown below. They
have been adapted from the standard algebraic notation.
Priority 2: * /
Priority 1: + -
Priority 0: (
Convert Infix expression to Postfix expression
Algorithm inToPostFix (formula)
Convert infix formula to postfix.
Pre formula is infix notation that has been edited

27
to ensure that there are no syntactical errors
Post postfix formula has been formatted as a string
Return postfix formula
1 createStack (stack)
2 loop (for each character in formula)
1 if (character is open parenthesis)
1 pushStack (stack, character)
2 elseif (character is close parenthesis)
1 popStack (stack, character)
2 loop (character not open parenthesis)
1 concatenate character to postFixExpr
2 popStack (stack, character)
3 end loop
3 elseif (character is operator) //Test priority of token to token at top of stack
1 stackTop (stack, topToken)
2 loop (not emptyStack (stack) AND priority(character) <= priority(topToken))
1 popStack (stack, tokenOut)
2 concatenate tokenOut to postFixExpr
3 stackTop (stack, topToken)
3 end loop
4 pushStack (stack, token)
4 else // Character is operand
1 Concatenate token to postFixExpr
5 end if
3 end loop //Input formula empty.
//Pop stack to postFix
4 loop (not emptyStack (stack))
1 popStack (stack, character)
2 concatenate token to postFixExpr
5 end loop
6 return postFix
end inToPostFix

V. Evaluation postfix and infix with example

28
Now let’s see how we can use stack postponement to evaluate the postfix expressions we
developed earlier.
For example, given the expression shown below,
ABC+*
and assuming that A is 2, B is 4, and C is 6, what is the expression value?
The first thing you should notice is that the operands come before the operators. This means that
we will have to postpone the use of the operands this time, not the operators. We therefore put
them into the stack. When we find an operator, we pop the two operands at the top of the stack
and perform the operation. We then push the value back into the stack to be used later.
Following figure traces the operation of our expression. (Note that we push the operand values
into the stack, not the operand names. We therefore use the values in the figure.)

Fig.: Evaluation of Postfix expression


When the expression has been completely evaluated, its value is in the stack.
The algorithm is shown below
Evaluation of Postfix Expressions
Algorithm postFixEvaluate (expr)
This algorithm evaluates a postfix expression and returns its value.
Pre a valid expression
Post postfix value computed
Return value of expression
1 createStack (stack)
2 loop (for each character)
1 if (character is operand)
1 pushStack (stack, character)
2 else
1 popStack (stack, oper2)

29
2 popStack (stack, oper1)
3 operator = character
4 set value to calculate (oper1, operator, oper2)
5 pushStack (stack, value)
3 end if
3 end loop
4 popStack (stack, result)
5 return (result)
end postFixEvaluate

2. Test cases/validation

Validation
i. If Stack Empty Display message “Stack Empty”
ii. If memory not available Display message “memory
not available”
iii. Parenthesis matching display appropriate message
open/close parenthesis missing
Infix to postfix /prefix Test Cases

INPUT: POSTFIX OUTPUT:

(A+B) * (C-D) AB+CD-*

A$B*C-D+E/F/(G+H) AB$C*D-EF/GH+/+

((A+B)*C-(D-E))$(F+G) AB+C*DE—FG+$

A-B/(C*D$E) ABCDE$*/-

A^B^C ABC^^

INPUT: PREFIX OUTPUT:

(A+B) * (C-D) *+AB-CD

A$B*C-D+E/F/(G+H) +-*$ABCD//EF+GH

((A+B)*C-(D-E))$(F+G) $-*+ABC-DE+FG

A-B/(C*D$E) -A/B*C$DE

A^B^C ^A^BC

30
FAQ:
1. What is data structure?
2. Types of data structure?
3. Examples of linear data structure & Non-linear data structure?
4. What are the operations can implement on stack?
5. Explain recursion using stack.
6. Explain how a string can be reversed using stack.
7. How does a stack similar to list? How it is different?
8. List advantages and disadvantages of postfix and prefix expression over infix
expression.

31
3. Implementation of Priority Queue

AIM: Implement priority queue as ADT using single linked list for servicing patients in an
hospital with priorities as i) Serious (top priority) ii) medium illness (medium priority)
iii) General (Least priority)

OBJECTIVE:

1) To understand the concept of priority Queue.


2) How data structures Queue is represented as an ADT.

THEORY:

Queue:
i. Concept
Queues are more common data objects found in computer algorithms. It is a special case of
more general data object, an ordered or linear list. It can be defined as an ordered list, in which
all insertions are allowed at one end, called as ‘rear’ & all deletions are made at other end, called
as ‘front’ i.e. First element inserted is outputted first (First In First Out or FIFO).
Queue can be represented mathematically as :
S = {a1, a2, …,an} where a1 is the first element & an is last element.& ai is ahead of ai+1 , 1=< i
< n.
ii. Definition of Queue:
Queue is a linear list in which data can be inserted at one end, called the rear, and deleted from
the other end, called the front. It is a first in–first out (FIFO) restricted data structure
Figure 1 shows two representations of a queue: one a queue of people and the other a computer
queue. Both people and data enter the queue at the rear and progress through the queue until
they arrive at the front. Once they are at the front of the queue, they leave the queue and are
served.

Fig.1: Queue Concept

iii. Terminology with


Queue
An abstract data type
(ADT) consists of a data structure and
a set of primitives
a. Initialise creates/initialises the queue
b. Enqueue adds a new element
c. Dequeue removes a element
d. IsEmpty reports whether the queue is empty

32
e. IsFull reports whether the queue is full
f. Destroy delete the contents of the queue
iv. Diagram (horizontal view)
Given below is a pictorial representation of queue.

Fig.2: Queue stored in an array


An enqueue to an empty queue is placed in the first element of the array, which becomes both
the front and the rear. Subsequent enqueues are placed at the array location following rear; that
is, each enqueue stores the queue data in the next element after the current queue rear. Thus, if
the last element in the queue is stored at array location 11, the data for the next enqueue is
placed in element 12.
Dequeues take place at the front of the queue. As an element is deleted from the queue, the
queue front is advanced to the next location; that is, queue front becomes queue front plus one.
Figure 2(a) shows a conceptual queue; Figure 2(b) shows a physical queue after it has been in
operation for a period of time. At the point shown, the data have migrated from the front of the
array to its centre.
When we implement a queue in an array, we use indexes rather than pointers. Thus, the front of
the queue in figure 3 is 5 and the rear is 16.
The definition of a full queue changes when we implement a queue in an array. A full queue is
defined as every location filled. Because arrays have a finite number of elements, we can
determine that the queue is full by testing the queue count against the maximum number of
elements.
When data arrive faster than the queue service time, the queue tends to advance to the end of
the array. This leads to the situation where the last element in the array is occupied but the
queue is not full because there are empty elements at the beginning of the array. This situation is
shown in Figure F-3.

33
Fig.3: Array Queue filled with Last element filled
When the data are grouped at the end of the array, we need to find a place for the new element
when we enqueue data. One solution is to shift all of the elements from the end to the beginning
of the array. For example, in Figure 3 element 5 can be shifted to element 0, element 6 to 1, 7 to
2, and so
forth until element 16 is shifted to 11.
v. Circular Queue
A more efficient alternative is to use a circular array. In a circular array, the last element is
logically followed by the first element. This is done by testing for the last element and, rather than
adding one, setting the index to zero. Given our array queue above, the next element after 16 is
0. A circular queue is shown in Figure 4.
With this understanding of a circular queue, we are ready to rewrite the abstract data type. The
only difference in the calling sequence between the two implementations is the addition of a
maximum queue size in the create queue function.

Fig.4: Circular Queue

Figure 5 illustrates the operation of this code on an example. The first figure 5 shows an empty
queue with first = rear = 0. The second figure shows the queue after the integer 10 is inserted.
The Third figure shows the queue when 20, 30, 40, 50, and 60 have been inserted. The fourth
figure shows the queue after 70 is inserted. Notice that, although one slot remains empty, the
queue is now full because Queue::Insert will not permit another element to be inserted. If it did
permit an insertion at this stage, rear and front would be the same. This is the condition that
Queue: Delete checks to determine whether the queue is empty! This would make it impossible
to distinguish between the queue being full and being empty. The fifth figure shows the queue
after two integers (10 and 20) are deleted. The last figure shows a full queue after the insertion of

34
integers 80 and 90.

Fig. 5 Demonstration of queue in a circular array

vi. Applications of Queues:


1. Multiuser, multiprogramming environment job scheduling
2. Reversing stack using queue
3. queue Simulation, all types of customer service(like railway reservation) centers are designed
using the concept of queues
4. Categorizing data

ALGORITHM:

Define structure for Queue(Priority, Patient Info, Next Pointer).

Empty Queue:
Return True if Queue is Empty else False.
isEmpty(Front)
Front is pointer of structure,which is first element of Queue.
Step 1: If Front = = NULL
Step 2: Return 1

35
Step 3: Return 0

Insert Function:
Insert Patient in Queue with respect to the Priority.
Front is pointer variable of type Queue,which is 1st node of Queue.
Patient is a pointer variable of type Queue, which hold the information about new
patient.
Insert(Front, Queue )
Step 1: If Front = = NULL //Queue Empty
Then Front = Patient;
Step 2: Else if Patient->Priority > Front->Priority
Then i) Patient->Next = Front;
ii) Front=Patient;
Step 3: Else A) Temp = Front;
B) Do Steps a while Temp != NULL And
Patient->Priority <= Temp->Next->Priority
a) Temp=Temp->Next;
c) Patient->Next = Temp->Next;
Temp->Next = Patient;
Step 4: Stop.

Delete Patient details from Queue after patient get treatment:


Front is pointer variable of type Queue,which is 1st node of Queue.
Delete Node from Front.
Delete( Front )
Step 1: Temp = Front;
Step 2: Front = Front->Next;
Step 3: return Temp

Display Queue Front:


Front is pointer variable of type Queue,which is 1st node of Queue.
Display( Front )
Step 1: Temp = Front;
Step 2: Do Steps while Temp != NULL
a) Display Temp Data
b) If Priority 1 Then ―General Checkup‖;
Else If Priority 2 Then Display ― Non-
serious"; Else If Priority 3 Then Display
"Serious"
Else Display "Unknown";
c) Temp = Temp->Next;
Step 3: Stop.
Display Queue rear:
Front is pointer variable of type Queue,which is 1st node of Queue.
Display( Rear )
Step 1: Temp = Rear;
Step 2: Do Steps while Temp != NULL
a) Display Temp Data
b) If Priority 1 Then ―General Checkup‖;
36
Else If Priority 2 Then Display ― Non-serious";
Else If Priority 3 Then Display "Serious"
Else Display "Unknown";
c) Temp = Temp->Next;
Step 3: Stop.

INPUT:
Test Case O/P
Queue Empty Display message ―Queue Empty‖
Queue Full Display message ―Queue Full‖
Name of patients & category of patient like
a) Serious (top priority), b) non-serious (medium priority), c) General Checkup (Least
priority).
E.g. Enter patient arrival in the hospital with following priorities 1, 3, 2, 2, 1, 3

OUTPUT:
Priority queue cater services to the patients based on priorities.
Patient should be given service in the following order 3, 3, 2, 2, 1, 1

Note: 3 means top priority.

Test cases/Validation :

Addition of elements in :
Tokan Insert More?
A Y
B Y
C Y
D Y
E N
******************************** OUTPUT ***************************
Display of elements in Queue :

After creation front rear elements


At front : 0 0 queue is empty
At rear : 0 0 queue is empty
All from front : 0 0 queue is empty
All from rear : 0 0 queue is empty

After Additions front rear elements


At front : 0 5 A
At rear : 0 5 E
All from front : 0 5 ABCDE
All from rear : 0 5 EDCBA

**********************************************************************
37
Test Cases:
1. Create an empty circular queue

2. Display front element

3. Display rear element

4. Display all elements of queue starting from front

5. Display all elements of queue starting from rear

6. Add element A in queue

7. Display front element

8. Display rear element

9. Display all elements of queue starting from front

10. Display all elements of queue starting from rear

11. Add elements B, C, D, and E in queue

12. Display front element

13. Display rear element

14. Display all elements of queue starting from front

15. Display all elements of queue starting from rear

16. Delete an element from queue

17. Display front element

18. Display rear element

19. Display all elements of queue starting from front

20. Display all elements of queue starting from rear

21. Delete an element from queue

22. Delete an element from queue

23. Delete an element from queue

24. Delete an element from queue

25. Display front element

38
26. Display rear element

27. Display all elements of queue starting from front

28. Display all elements of queue starting from rear

29. Delete an element from queue

30. Add elements 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 in queue

31. Display front element

32. Display rear element

33. Display all elements of queue starting from front

34. Display all elements of queue starting from rear

35. Add element 11 in queue

FAQ:

1. What are the types of data structure?


2. What are the operations can implement on queue?
3. What is circular queue?
4. What is Multiqueue?
5. Explain importance of stack in recursion
6. Explain Implicit & Explicit Stack.
7. Applications of stack and Queue as a data structure

39
40

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy