(a) Write algorithm to convert an infix expression to its prefix form. (b) Discuss the advantages and disadvantages of doubly linked list. Give an example to demonstrate insertion and deletion operations in DLL in array form.


Q.) (a) Write algorithm to convert an infix expression to its prefix form. (b) Discuss the advantages and disadvantages of doubly linked list. Give an example to demonstrate insertion and deletion operations in DLL in array form.

Subject: Data Structure and Algorithm

(a) Algorithm to Convert an Infix Expression to its Prefix Form

Converting an infix expression to its prefix form involves reversing the infix expression, converting it to postfix, and then reversing it again to get the prefix expression. The algorithm uses a stack to handle the operators and parentheses. Here's a step-by-step algorithm:

  1. Initialize an empty stack for operators and an empty list for the output.
  2. Reverse the infix expression.
  3. Iterate over the reversed expression:
    • If the token is an operand, add it to the output list.
    • If the token is a right parenthesis ), push it onto the stack.
    • If the token is a left parenthesis (, pop the stack and add to the output list until a right parenthesis ) is encountered on the stack. Pop and discard the right parenthesis.
    • If the token is an operator:
      • While there is an operator at the top of the stack with greater precedence, or the operator at the top of the stack has equal precedence and the token is left associative, pop operators from the stack onto the output list.
      • Push the current operator onto the stack.
  4. After the expression is fully scanned, pop any remaining operators from the stack to the output list.
  5. Reverse the output list to get the prefix expression.

Example:

Let's convert the infix expression A + B * C to its prefix form.

  1. Reverse the expression: C * B + A
  2. Initialize stack and output list: stack = [], output = []
  3. Scan the reversed expression:
    • C is an operand, add to output: output = [C]
    • * is an operator, push to stack: stack = [*], output = [C]
    • B is an operand, add to output: output = [C, B]
    • + is an operator, push to stack: stack = [+,*], output = [C, B]
    • A is an operand, add to output: output = [C, B, A]
  4. Pop remaining operators from the stack to the output: output = [C, B, *, A, +]
  5. Reverse the output list to get the prefix expression: + A * B C

(b) Advantages and Disadvantages of Doubly Linked List

A doubly linked list (DLL) is a complex data structure that consists of nodes where each node contains a data part and two pointers. One pointer points to the next node and the other points to the previous node.

Advantages:

Advantage Description
Bidirectional Traversal DLLs can be traversed in both forward and backward directions, providing greater flexibility.
Efficient Insertions/Deletions Insertions and deletions can be done efficiently at any point in the list without the need to traverse from the head node (as in singly linked lists).
Dynamic Size The size of the list can be increased or decreased as needed.
No Need for Backtracking In some algorithms, such as the ones that require scanning and backtracking, DLLs are more efficient as they can easily go to the previous node.

Disadvantages:

Disadvantage Description
Memory Usage Each node requires extra memory for an additional pointer (previous pointer), leading to higher memory usage.
Complexity Implementation of DLLs is more complex than singly linked lists due to the handling of two pointers.
Greater Risk of Errors Insertion and deletion operations are more error-prone as they involve updating multiple pointers.

Example of Insertion and Deletion Operations in DLL:

Let's consider a DLL represented in array form, where each element is a node with the format [previous, data, next].

Initial DLL: null <- [null, 1, 2] <-> [1, 2, 3] <-> [2, 3, null] -> null

Insertion:

Insert a new node with data 4 before the node with data 3.

  1. Create a new node: [2, 4, 3]
  2. Update the next pointer of the node with data 2 to point to the new node: [1, 2, 4]
  3. Update the previous pointer of the node with data 3 to point to the new node: [4, 3, null]
  4. The updated DLL: null <- [null, 1, 2] <-> [1, 2, 4] <-> [2, 4, 3] <-> [4, 3, null] -> null
Deletion:

Delete the node with data 2.

  1. Update the next pointer of the node with data 1 to point to the node with data 4: [null, 1, 4]
  2. Update the previous pointer of the node with data 4 to point to the node with data 1: [1, 4, 3]
  3. The updated DLL after deletion: null <- [null, 1, 4] <-> [1, 4, 3] <-> [4, 3, null] -> null

In array form, the operations would look like this:

Before Insertion:

Previous Data Next
null 1 2
1 2 3
2 3 null

After Insertion of 4:

Previous Data Next
null 1 2
1 2 4
2 4 3
4 3 null

After Deletion of 2:

Previous Data Next
null 1 4
1 4 3
4 3 null

This demonstrates how insertion and deletion operations are performed in a doubly linked list.