0% found this document useful (0 votes)
16 views18 pages

Assignment02 (SP24-BSE-047)

The document is an assignment on data structures, specifically focusing on stacks and their applications. It includes various questions about the suitability of stacks for different applications, algorithms for managing stacks, converting expressions, and evaluating mathematical operations. Additionally, it discusses the efficiency of iterative versus recursive algorithms for specific problems.

Uploaded by

Shaheer Qureshi
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)
16 views18 pages

Assignment02 (SP24-BSE-047)

The document is an assignment on data structures, specifically focusing on stacks and their applications. It includes various questions about the suitability of stacks for different applications, algorithms for managing stacks, converting expressions, and evaluating mathematical operations. Additionally, it discusses the efficiency of iterative versus recursive algorithms for specific problems.

Uploaded by

Shaheer Qureshi
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/ 18

Data Structures

ASSIGNMENT 02

Submitted to: - Sir Zahid Anwar

Submitted by: - Shaheer Qureshi

Reg-no: - SP24-BSE-047

Question # 1
Indicate whether a stack would be a suitable data structure for each of the following application. Justify your
answer.
Application Stack Suitable or not[Y/N] Reason
A bank simulation of its teller N Queue is more suitable for
operation to see how waiting times simulating waiting lines (FIFO).
would be affected by adding

1
another teller
An address book N Requires random access and
search, not LIFO behavior.
A program to receive data that are Y Stack provides LIFO behavior.
to be saved and processes in the
reverse order
A word processor to have a PF key Y Stack can store command history
that causes the preceding command (LIFO).
to be redisplayed. Every time the
user press the PF key, the program
shows the command that preceded
the one currently displayed.
A program to evaluate arithmetic Y Stack helps evaluate expressions
expressions according to the in correct order (e.g., postfix).
specific order of operators
A dictionary of words used by a N Requires search and retrieval, not
spelling checker to be built and LIFO structure.
maintained
A data structure used to keep track Y Stack tracks return points during
of return addresses for nested function calls (LIFO).
function while a program is
running
A program to keep track of patients N Queue is suitable for first-come,
as they check into a medical clinic, first-served systems.
assigning patient to doctor on a
first come, first served basis
Question # 2
Two stacks of positive integers are needed, one containing elements with values less than or equal to 1,000
and other containing elements with values larger than 1,000. The total number of elements in the small – value
stack and the large – value stack combined are not more than 200 at any time, but we cannot predict how
many are in each stack. (All of the elements could be in the small –value stack, they could be evenly divided,
both stacks could be empty, and so on). Can you think of a way to implement both stacks in one array?
a) Draw a diagram of how the stack might look.
b) Write the definitions for such a double – stack structure.
c) Write the algorithm for Push operation; it should store the new item into the correct stack according to
its value.

ANSWER IN THIS BOX


Part A.

S1 S1 S2 S2

topSmall topLarge

Part B.

2
define MAX_SIZE = 200
define THRESHOLD = 1000

structure DoubleStack:
array: Array[MAX_SIZE] of integers
topSmall: integer = -1 // index for small-value stack
topLarge: integer = MAX_SIZE // index for large-value stack
end structure
Part C.

procedure Push(DoubleStack S, integer value):


if S.topSmall + 1 >= S.topLarge then
throw "Stack Overflow"
end if

if value <= THRESHOLD then


S.topSmall := S.topSmall + 1
S.array[S.topSmall] := value
else
S.topLarge := S.topLarge - 1
S.array[S.topLarge] := value
end if
end procedure

Question # 3
In each plastic container of Pez candy, the colors are stored in random order (See figure below).

Your little brother likes only yellow ones, so he painstakingly takes out all the candies, one by one, eats the
yellow ones, and keeps the other in order, so that he can return them to container in exactly the same order as
before- minus the yellow candies, of course. Write the algorithm to simulate this process. You may use any of
the stack operations defined in the stack ADT, but may not assume any knowledge of stack’s implementation.
ANSWER IN THIS BOX

Algorithm: RemoveYellowCandies
Input: A stack S containing randomly ordered candies (including yellow ones)

3
Output: The same stack without yellow candies, maintaining original order of others
1. Create an empty temporary stack tempStack
2. While S is not empty:
a. currentCandy = Pop(S)
b. If currentCandy is not yellow:
Push(currentCandy, tempStack)
3. While tempStack is not empty:
a. Push(Pop(tempStack), S)
4. Return S

i. Draw a schematic diagram about how to plan six stacks in a single array.
ii. How would you implement a stack of stack?

Part 1:

STACK 1 STACK 2 STACK 3 STACK 4 STACK 5 STACK 6

ARRAY

Part 2:
PUSH Algorithm:
Algorithm PushStackOfStacks(mainStack, innerStack):
if mainStack is full:
throw "Stack Overflow"
mainStack.top += 1
mainStack.array[mainStack.top] = innerStack

POP Algorithm:
Algorithm PopStackOfStacks(mainStack):
if mainStack is empty:
throw "Stack Underflow"
innerStack = mainStack.array[mainStack.top]

4
mainStack.top -= 1
return innerStack

Push into specific inner stack Algorithm:


Algorithm PushToInnerStack(mainStack, stackIndex, value):
if stackIndex > mainStack.top:
throw "Invalid Stack"
innerStack = mainStack.array[stackIndex]
Push(innerStack, value) // Normal stack push

Question # 4 (Applications of Stack)


Write an equivalent postfix expression for the infix expression. Write each step of this conversion.
1. (A + B)*(C – D )

2. A ^ B * C – D + E/F
3. A/(B+C*D-E)
4. A-B*C+D/E
5. (A+B)^2 -(C-D)/2

ANSWER IN THIS BOX


1. A B + C D - *
2. A B ^ C * D - E F / +
3. A B C D * + E - /
4. A B C * - D E / +
5. A B + 2 ^ C D - 2 / -

Question # 5
What is the value of the postfix expression? Write each step of this conversion.
1. AB+CD–*
2. A B ^ C*D – E F/+
3. ABCD*+E-/
4. ABC*-DE/+
5. AB+2 ^CD-2/-
Where A = 12 , B = 3 ,C = 7 , D = 4 ,E = 2 and F = 5

ANSWER IN THIS BOX


1. (12+3)*(7-4) = 15*3 = 45
2. (12^3)*7 - 4 + (2/5) ≈ 2016 - 4 + 0 = 2012
3. ((12 + (3 * 7)) - 2)/5 = (12 + 21 - 2)/5 = 31/5 = 6
4. (12 - 3 * 7) + (4 / 2) = -9 + 2 = -7
5. ((12+3)^2 - (7-4))/2 = (15^2 - 3)/2 = (225 - 3)/2 = 111

Question # 6
i. Write an algorithm for converting an infix expression into prefix expression

5
ii. Write an algorithm for evaluation of prefix expression
ANSWER IN THIS BOX

Infix to Prefix:

1. Reverse the infix expression


2. Replace '(' with ')' and vice versa
3. Convert to postfix
4. Reverse the resulting postfix expression

Prefix Evaluation:

1. Read the expression from right to left


2. When an operand is encountered, push it onto stack
3. When an operator is encountered
A. Pop two operands from stack
B. Apply the operator
C. Push result back onto stack
4. Final result is the only remaining element in stack

Question # 7
i. Convert the following infix expression into equivalent prefix expression
A^B*C-D+E/F/(G+G)
ii. Evaluate the following prefix expression:
+ A*B+CD if A =2 , B =3, C = 4, D = 5

ANSWER IN THIS BOX


1. + - ^ A * B C D / / E F + G G
2. + 2 * 3 + 4 5 = 2 + 3*(4+5) = 2 + 27 = 29

Question # 8
The efficient method used in evaluating a polynomial of the form

is by nesting using Horner’s rule, as shown below:

Show how this can be carried out using a stack

ANSWER IN THIS BOX

Algorithm: EvaluatePolynomial

Input: Array of coefficients [aₙ, aₙ₋₁, ..., a₀], value x


Output: Value of polynomial at x

1. Create empty stack S

6
2. Push aₙ onto S
3. For each coefficient aᵢ from aₙ₋₁ to a₀:
a. top = Pop(S)
b. result = top * x + aᵢ
c. Push(result, S)
4. Final result is Pop(S)

Question # 9 (Recursion)
Consider the following recursion for integer multiplication of two positive number a and b:
a* 1 = a
a*b = a(b -1) + a
This can be implemented using following recursive algorithm as follows:
Algorithm recursive_multiplication(a, b)
if b = 1 then
return a
else
return a + recursive_multiplication ( a, b-1)
a) Convert above recursive algorithm in to an iterative algorithm? Present your iterative version into
Pseudo code.
b) Mathematically the following definition for integer multiplication is valid:
a multiply by b : a*b = a(b+1) – a
Can we have recursive algorithm for calculating integer multiplication based on above definition?
Explain carefully.

ANSWER IN THIS BOX


Part A.
Algorithm iterative_multiplication(a, b):
result = 0
for i from 1 to b:
result = result + a
return result
Part B.
Algorithm recursive_multiplication_v2(a, b):
if b = 0 then
return 0
else
return recursive_multiplication_v2(a, b+1) - a
However, this version is problematic because:

1. It doesn't have a proper base case (keeps increasing b)


2. It would lead to infinite recursion
3. The original recursive definition is more natural for this operation

Question # 10
Determine whether a recursive or iterative solution is most appropriate for GCD problem
Iterative version Recursive version
ALGORITHM M_Euclid_iterative(m, n) ALGORITHM M_Euclid_recursive(m, n)
// Input: m ≥ 0 n ≥ 0 // Input: Two non-negative integers m and n, not both

7
// Output: Greatest Common Divisor of m and n zero.
while n ≠ 0 do // Output: Greatest Common Divisor of m and n
if m < n then if m = 0 then
swap(m, n) ans ← n
m ← m- n else if m > n then
return m ans ← M_Euclid(n, m)
else
nLess ← n- m
ans ← M_Euclid(m, nLess)
return ans

ANSWER IN THIS BOX


The recursive solution is more appropriate for the GCD problem because:
1. The Euclidean algorithm is naturally recursive in its definition
2. The recursive version is more concise and easier to understand
3. The problem size reduces quickly with each recursive call
4. Modern compilers can optimize tail recursion to be as efficient as iteration

Question # 11
i. Consider the following two algorithms Algorithm A and Algorithm B that solve
same problem P. Explain what these algorithms compute?

ANSWER IN THIS BOX


Algorithm A computes the sum of the first n natural numbers (1 + 2 + ... + n).

Algorithm B computes the nth Fibonacci number.

Both algorithms use recursion but solve different problems. Algorithm A has O(n) time complexity while
Algorithm B has exponential time complexity O(2^n) in its naive recursive form.

Question # 12
Consider the problem of compute the factorial function F(n) = n! for an arbitrary
nonnegative integer n. Which of the algorithm iterative or recursive is most efficient.
Justify your answer.

8
ANSWER IN THIS BOX
The iterative version is more efficient for computing factorial because:

1. It avoids the overhead of recursive function calls


2. It uses constant space (O(1)) compared to O(n) stack space for recursion
3. Modern processors can optimize simple loops better than recursion
4. For large n, the recursive version may cause stack overflow

Question # 13
Consider the following two algorithms for computing n th term of Fibonacci sequence, F(n). One is iterative
and other is recursive.
ITERATIVE ALGORITHM:

RECURSIVE ALGORITHM:

Which of the algorithm iterative or recursive is most efficient. Justify your answer.

ANSWER IN THIS BOX


The iterative algorithm is much more efficient for computing Fibonacci numbers
9
because:

1. The recursive version has exponential time complexity O(2^n)


2. The iterative version has linear time complexity O(n)
3. The recursive version does redundant calculations (recomputes same values)
4. The iterative version uses constant space while recursive uses O(n) stack space

Question # 14
Consider the following problem:
Problem: Compute an where a ≠ 0 and n is a nonnegative
Inorder to solve a given problem using recursion, we split it into smaller subproblem. Here is various strategy
for splitting into smaller subproblem. Youhave to design recursive algorithm for each of the strategy

Model Algorithm
an = an-1 × a 1. Algorithm PowerLinear(a, n):
2. if n == 0 then
3. return 1
4. else
5. return a * PowerLinear(a, n-1)
(an/2 ) 2 if n is even and positive 1. Algorithm PowerDivideConquer(a, n):
an = (a(n-1)/2 ) 2 * a if n is odd and > 1 2. if n == 0 then
3. return 1
a if n = 1 4. else if n == 1 then
5. return a
6. else if n % 2 == 0 then
7. half = PowerDivideConquer(a, n/2)
8. return half * half
9. else
10. half = PowerDivideConquer(a, (n-1)/2)
11. return half * half * a
a ë n/2 û * a é n/2 ù if n > 1 1. Algorithm PowerFloorCeiling(a, n):
n
a= a if n = 1 2. if n == 0 then
3. return 1
4. else if n == 1 then
5. return a
6. else
7. left = PowerFloorCeiling(a, floor(n/2))
8. right = PowerFloorCeiling(a, ceil(n/2))
9. return left * right

Which algorithm is efficient? Justify your answer.

10
Most Efficient Algorithm: Model 2
Because it:

 Reduces the problem size by half in each step,


 Makes only one recursive call per level,
 Has logarithmic complexity: O(log n).

Question # 15
Indicate whether each of the following application would be a suitable for a queue. Justify your answer.

ANSWER IN THIS BOX

a. N – LIFO behavior needed, which suits a stack, not a queue.


b. Y – Patients are handled in the order they arrive (FIFO).
c. N – Backtracking uses LIFO logic, suitable for a stack.
d. N – Needs sorting/searching, not sequential access.
e. Y – Requests are processed in the order they arrive (FIFO).
f. Y – Simulates checkout lines, which follow FIFO logic.
g. N – Requires fast lookup, not sequential processing.
h. Y – Customers are served in the order of ticket numbers (FIFO).
i. N – Lottery is based on random selection, not order.

Question # 16
Write an algorithm that will reverse all the elements in a queue
ANSWER IN THIS BOX
Algorithm ReverseQueue(Q):

11
Create an empty stack S
While Q is not empty:
Push(Dequeue(Q), S)
While S is not empty:
Enqueue(Pop(S), Q)
Return Q

Question # 17
i. How would you implement a queue of stacks?
ii. How would you implement a stack of queues?
iii. How would you implement a queue of queues?
a. Draw a diagram of how each of these data structures might look.
b. Write algorithms/ routines to implement the appropriate operations of each of these data
structures
ANSWER IN THIS BOX
Part 1.
i. Queue of stacks:

1. Each element in the queue is a stack


2. Enqueue: Add a new stack at the rear
3. Dequeue: Remove a stack from the front

Part 2.
ii. Stack of queues:
1. Each element in the stack is a queue
2. Push: Add a new queue on top
3. Pop: Remove the top queue

Part 3.

iii. Queue of queues:

1. Each element in the outer queue is another queue


2. Enqueue: Add a new queue at the rear
3. Dequeue: Remove a queue from the front

Question # 18
Write algorithms (for insertion and deletion) that implement two queues in one array where first queue will
start from 0th position and second queue will start from last position of the array.

ANSWER IN THIS BOX


Algorithm Enqueue1(Q, x):
if Q.rear1 + 1 == Q.front2 then
throw "Queue Overflow"
Q.array[Q.rear1] = x

12
Q.rear1 = Q.rear1 + 1

Algorithm Dequeue1(Q):
if Q.front1 == Q.rear1 then
throw "Queue Underflow"
x = Q.array[Q.front1]
Q.front1 = Q.front1 + 1
return x

Algorithm Enqueue2(Q, x):


if Q.rear2 - 1 == Q.front1 then
throw "Queue Overflow"
Q.array[Q.rear2] = x
Q.rear2 = Q.rear2 - 1

Algorithm Dequeue2(Q):
if Q.front2 == Q.rear2 then
throw "Queue Underflow"
x = Q.array[Q.front2]
Q.front2 = Q.front2 - 1
return x
Question # 19
Write an algorithm that uses stack in order to reverse the elements of a circular queue, which is stored in an
array. For example, if the initial queue is that given in Fig-1 as under, then the resulting Queue is that given in
Fig-2.

ANSWER IN THIS BOX

Algorithm ReverseCircularQueue(Q):
Create an empty stack S
// Transfer all elements to stack
while not Q.isEmpty():
Push(S, Q.dequeue())
// Transfer back to queue
while not S.isEmpty():
Q.enqueue(Pop(S))
return Q
13
Question # 20
It is required to split a circular queue into two circular queues (say CQueue1 and CQueue 2) so that all the
elements in odd positions are in one queue and those in even positions are in another queue as shown in the
following figure. Write a C++ program to accomplish this. Assume that queue is maintained in an array.

CQueue2:
CQueue1:

Before

ANSWER IN THIS BOX


#include <iostream>
using namespace std;

void splitQueue(int original[], int size, int queue1[], int queue2[]) {


int front1 = 0, rear1 = -1;
int front2 = 0, rear2 = -1;

for (int i = 0; i < size; i++) {


if (i % 2 == 0) { // even position (0-based)
queue1[++rear1] = original[i];
} else { // odd position
queue2[++rear2] = original[i];
}
}
}

int main() {
const int SIZE = 6;
int original[SIZE] = {10, 20, 30, 40, 50, 60};
int queue1[SIZE/2 + 1], queue2[SIZE/2];

splitQueue(original, SIZE, queue1, queue2);

cout << "Queue1 (even positions): ";


for (int i = 0; i <= SIZE/2; i++) {
cout << queue1[i] << " ";
}

cout << "\nQueue2 (odd positions): ";


for (int i = 0; i < SIZE/2; i++) {

14
cout << queue2[i] << " ";
}

return 0;
}

Question # 21
Can a queue be represented by a circular linked list with only one pointer pointing to the tail of the queue.
Write C++ functions for add and delete operations on such a queue.

ANSWER IN THIS BOX


#include <iostream>
using namespace std;

struct Node {
int data;
Node* next;
Node(int d) : data(d), next(nullptr) {}
};

class CircularQueue {
private:
Node* tail;
public:
CircularQueue() : tail(nullptr) {}

void enqueue(int x) {
Node* newNode = new Node(x);
if (tail == nullptr) {
tail = newNode;
tail->next = tail;
} else {
newNode->next = tail->next;
tail->next = newNode;
tail = newNode;
}
}

int dequeue() {
if (tail == nullptr) {
throw "Queue Underflow";
}
int x;
if (tail->next == tail) {
x = tail->data;
delete tail;
tail = nullptr;
} else {

15
Node* temp = tail->next;
x = temp->data;
tail->next = temp->next;
delete temp;
}
return x;
}
};

Question # 22
A DEQUE is a data structure consisting of a list of items, on which the following operations are possible:
PUSH ( X,D) : Insert item X on the front end of DEQUE D.
POP(D) : Remove the front item from DEQUE D and return it.
Inject(X, D) : Insert item X on the rear end of DEQUE D.
Eject(D) : Remove the rear item from DEQUE D and return it.
Write C++ program (complete program) that support the above DEQUE operations.

ANSWER IN THIS BOX


#include <iostream>
using namespace std;

const int MAX_SIZE = 100;

class Deque {
private:
int arr[MAX_SIZE];
int front, rear, size;

public:
Deque() : front(-1), rear(0), size(0) {}

bool isFull() { return size == MAX_SIZE; }


bool isEmpty() { return size == 0; }

void push(int x) {
if (isFull()) {
cout << "Deque Overflow\n";
return;
}
if (front == -1) {
front = rear = 0;
} else if (front == 0) {
front = MAX_SIZE - 1;
} else {
front--;
}
arr[front] = x;

16
size++;
}

void inject(int x) {
if (isFull()) {
cout << "Deque Overflow\n";
return;
}
if (front == -1) {
front = rear = 0;
} else if (rear == MAX_SIZE - 1) {
rear = 0;
} else {
rear++;
}
arr[rear] = x;
size++;
}

int pop() {
if (isEmpty()) {
throw "Deque Underflow";
}
int x = arr[front];
if (front == rear) {
front = -1;
rear = 0;
} else if (front == MAX_SIZE - 1) {
front = 0;
} else {
front++;
}
size--;
return x;
}

int eject() {
if (isEmpty()) {
throw "Deque Underflow";
}
int x = arr[rear];
if (front == rear) {
front = -1;
rear = 0;
} else if (rear == 0) {
rear = MAX_SIZE - 1;
} else {
rear--;

17
}
size--;
return x;
}
};

18

You might also like