Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
14 views11 pages

ADS Assignment3

The document outlines an assignment to implement a stack using arrays and linked lists in Java, including operations like push, pop, and infix-to-postfix conversion. It also discusses recursion, comparing recursive and iterative methods, particularly in the context of calculating factorials. The expected outcomes include understanding stack operations, expression conversion, and the efficiency of recursion versus iteration.

Uploaded by

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

ADS Assignment3

The document outlines an assignment to implement a stack using arrays and linked lists in Java, including operations like push, pop, and infix-to-postfix conversion. It also discusses recursion, comparing recursive and iterative methods, particularly in the context of calculating factorials. The expected outcomes include understanding stack operations, expression conversion, and the efficiency of recursion versus iteration.

Uploaded by

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

KOLA VINAY KUMAR

2403B05107
ADVANCE DATA STRUCTURES
ASSIGNMENT-03

AIM: Implement a stack using arrays and linked lists.

Description: Write code for stack operations and use the stack for infix-to-postfix conversion.

Expected Outcome: Understand stack operations and its applications in expression conversion.

Stack Operations in Java:

1. Push: Adds an element to the top of the stack. If the stack is implemented with an array, it
checks for overflow (full stack) before adding.

2. Pop: Removes and returns the top element of the stack. It checks for underflow (empty
stack) before removal.

3. Peek: Returns the top element of the stack without removing it.

4. IsEmpty: Checks if the stack is empty, returning a boolean value.

5. Implementation Options: Can be implemented using arrays or linked lists, each with its own
trade-offs in terms of memory and flexibility.

Infix and Postfix Conversion:

1. Infix Notation: Operators are placed between operands (e.g., A + B), which requires
parentheses and operator precedence rules for evaluation.

2. Postfix Notation (Reverse Polish Notation): Operators follow their operands (e.g., AB+),
eliminating the need for parentheses and making evaluation simpler.

3. Conversion Algorithm: Uses a stack to handle operators, ensuring correct precedence and
associativity.

4. Applications: Postfix expressions are used in compilers, calculators, and expression


evaluations for simpler parsing.

5. Advantage: Postfix eliminates ambiguity and allows evaluation in a single left-to-right pass
without backtracking.

Stack using arrays and linked lists:

To implement a stack using arrays and linked lists in Java, I’ll provide code for both
implementations. We’ll then use the stack to convert an infix expression to postfix
notation.

Code

Here is the Java code to implement stacks with arrays and linked lists, followed by the infix-
to-postfix conversion function.

import java.util.Stack;
// Stack implementation using an array

class ArrayStack {

private int top;

private int maxSize;

private char[] stackArray;

public ArrayStack(int size) {

maxSize = size;

stackArray = new char[maxSize];

top = -1;

public void push(char value) {

if (top == maxSize - 1) {

System.out.println("Stack is full");

} else {

stackArray[++top] = value;

public char pop() {

return (top == -1) ? '\0' : stackArray[top--];

public char peek() {

return (top == -1) ? '\0' : stackArray[top];

public boolean isEmpty() {

return top == -1;


}

// Stack implementation using a linked list

class LinkedListStack {

private class Node {

char data;

Node next;

Node(char data) {

this.data = data;

next = null;

private Node top;

public LinkedListStack() {

top = null;

public void push(char value) {

Node newNode = new Node(value);

newNode.next = top;

top = newNode;

public char pop() {

if (top == null) {

System.out.println("Stack is empty");

return '\0';

} else {
char value = top.data;
top = top.next;

return value;

public char peek() {

return (top == null) ? '\0' : top.data;

public boolean isEmpty() {

return top == null;

}
}

// Infix to Postfix Conversion using Stack

class InfixToPostfix {

private ArrayStack stack;

public InfixToPostfix(int size) {

stack = new ArrayStack(size);

public String convert(String infix) {

StringBuilder postfix = new StringBuilder();

for (int i = 0; i < infix.length(); i++) {

char ch = infix.charAt(i);

// If character is an operand, add it to output

if (Character.isLetterOrDigit(ch)) {

postfix.append(ch);
}

// If character is '(', push it to the stack

else if (ch == '(') {

stack.push(ch);

// If character is ')', pop and output from the stack until '(' is found

else if (ch == ')') {

while (!stack.isEmpty() && stack.peek() != '(') {

postfix.append(stack.pop());

stack.pop(); // remove '('

// If an operator is encountered

else {

while (!stack.isEmpty() && precedence(ch) <= precedence(stack.peek())) {

postfix.append(stack.pop());

stack.push(ch);

// pop all operators from the stack

while (!stack.isEmpty()) {

postfix.append(stack.pop());

return postfix.toString();

private int precedence(char ch) {

switch (ch) {
case '+':

case '-':

return 1;

case '*':

case '/':

return 2;

case '^':

return 3;

return -1;

// Testing the code

public class Main {

public static void main(String[] args) {

String infixExpression = "a+b*(c^d-e)^(f+g*h)-i";

InfixToPostfix converter = new InfixToPostfix(infixExpression.length());

System.out.println("Infix Expression: " + infixExpression);

String postfixExpression = converter.convert(infixExpression);

System.out.println("Postfix Expression: " + postfixExpression);

Explanation of the Code:

1. ArrayStack: Implements a stack using an array. Supports push, pop, peek, and isEmpty.

2. LinkedListStack: Implements a stack using a linked list with push, pop, peek, and isEmpty.

3. InfixToPostfix: Uses an ArrayStack to convert an infix expression to postfix notation. The


algorithm handles:

o Operands: Directly added to the output.

o Operators: Managed based on their precedence.


o Parentheses: Used to control the precedence explicitly.

Output

For an input of a+b*(c^d-e)^(f+g*h)-i, the output will be:


Infix Expression: a+b*(c^d-e)^(f+g*h)-i
Postfix Expression: abcd^e-fgh*+^*+i-

AIM: Demonstrate recursion and implement recursion with an explicit stack.

Description: Convert a recursive function (e.g., factorial) to use an iterative approach with a stack.

Expected Outcome: Compare recursive and iterative methods in terms of space and time
efficiency.

What is Recursion in Java?

 Recursion in Java is a process where a method calls itself to solve a problem.

 It is widely used in algorithms to solve problems that can be broken down into smaller,
similar sub-problems.

Structure of a Recursive Method

A recursive method in Java typically includes:

1. Base Case: Terminates the recursion.

2. Recursive Case: Calls the method itself with smaller input.

Example:

public int factorial(int n) {

if (n == 0) { // Base case

return 1;

return n * factorial(n - 1); // Recursive case

How Recursion Works in Java

 Each recursive call is pushed onto the call stack.

 The program waits until the base case is reached, then resolves each call in reverse order.

 Recursive calls consume memory, which may lead to a StackOverflowError if too many calls
are made.

Types of Recursion

1. Direct Recursion: A method calls itself direct


public void directRecursion() {
directRecursion();

2. Indirect Recursion: A method calls another method, which in turn calls the first method.

public void methodA() {

methodB();

public void methodB() {

methodA();

3. Tail Recursion: The recursive call is the last statement in the method.

public int tailRecursion(int n, int result) {

if (n == 0) return result;

return tailRecursion(n - 1, n * result);

Advantages of Recursion in Java

 Simplifies code for problems like traversing trees, graphs, or solving puzzles.

 Reduces complex iterative loops into elegant and readable methods.

 Useful for algorithms following a divide-and-conquer strategy (e.g., MergeSort, QuickSort).

6. Disadvantages of Recursion

 Memory Usage: Each recursive call uses stack space, leading to O(n)O(n)O(n) space
complexity.

 Performance Overhead: Function calls involve overhead for parameter passing and context
switching.

 Risk of StackOverflowError: Excessive recursion depth may exceed the call stack limit.

8. Applications of Recursion in Java

1. Mathematical Problems:

o Factorial, Fibonacci sequence, GCD, power calculation.

2. Data Structures:

o Tree Traversals (Inorder, Preorder, Postorder).

o Graph Traversals (DFS).

3. Sorting Algorithms:
o MergeSort, QuickSort.

4. Dynamic Programming:

o Problems solved using recursion with memoization.

5. Puzzles:

o Tower of Hanoi, N-Queens Problem.

Implementation of recursion with an explicit stack:

Here’s a Java program demonstrating both a recursive and an iterative (using an explicit stack)
implementation of the factorial function. The code will highlight the differences in implementation
and allow for a comparison of space and time efficiency.

import java.util.Stack;

public class RecursionVsIteration {

// Recursive implementation of factorial

public static int factorialRecursive(int n) {

if (n == 0 || n == 1) {

return 1;

return n * factorialRecursive(n - 1);

// Iterative implementation of factorial using an explicit stack

public static int factorialUsingStack(int n) {

Stack<Integer> stack = new Stack<>();

int result = 1;

// Push numbers onto the stack

while (n > 0) {

stack.push(n--);

// Pop numbers and multiply


while (!stack.isEmpty()) {
result *= stack.pop();

return result;

public static void main(String[] args) {

int number = 5; // Change this number to test with other values

// Recursive factorial

System.out.println("Factorial of " + number + " (Recursive): " + factorialRecursive(number));

// Iterative factorial using explicit stack

System.out.println("Factorial of " + number + " (Using Stack): " + factorialUsingStack(number));

// Space and time complexity comparison

System.out.println("\nSpace and Time Comparison:");

System.out.println("Recursive: Uses system stack for recursion, space complexity O(n).");

System.out.println("Iterative with Stack: Uses an explicit stack, space complexity O(n), but avoids
system overhead.");

Output

For an input of number = 5, the output will be:

Factorial of 5 (Recursive): 120

Factorial of 5 (Using Stack): 120

Space and Time Comparison:

Recursive: Uses system stack for recursion, space complexity O(n).

Iterative with Stack: Uses an explicit stack, space complexity O(n), but avoids system overhead.
Explanation

1. Recursive Method:

o Uses the system's call stack for each recursive call.

o Space complexity is O(n)O(n)O(n) due to the call stack.

o Elegant but limited by stack depth for large inputs.

2. Iterative Method with Stack:

o Uses an explicit stack to simulate the recursion.

o Space complexity remains O(n)O(n)O(n), but no risk of stack overflow.

o Slightly more verbose but suitable for large inputs where recursion may fail.

Comparison

 Space Efficiency: Both methods use O(n)O(n)O(n) space, but iterative avoids system stack
overhead.

 Time Efficiency: Similar for both, but recursion involves function call overhead.

 Use Cases: Recursive methods are simpler for small inputs, while iterative methods handle
larger inputs more safely.

You might also like