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


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

Subject: Data Structure and Algorithm

Algorithm to Convert an Infix Expression to its Prefix Form

Converting an infix expression to its prefix form involves reversing the usual order of operations. In infix expressions, operators are written between the operands they operate on, e.g., A + B. In prefix expressions, also known as Polish notation, the operator precedes their operands, e.g., + A B.

Here is a step-by-step algorithm to convert an infix expression to its prefix form:

  1. Reverse the Infix Expression: Start by reversing the given infix expression. While reversing, you must also reverse the brackets, i.e., change '(' to ')' and vice versa.

  2. Convert to Postfix: Apply the postfix conversion algorithm on the reversed expression. The algorithm for converting an infix expression to postfix is as follows:

    • Initialize an empty stack and an empty postfix expression.
    • Scan the reversed infix expression from left to right.
    • If the scanned character is an operand, add it to the postfix expression.
    • If the scanned character is an opening bracket '(', push it onto the stack.
    • If the scanned character is a closing bracket ')', pop from the stack and add to the postfix expression until an opening bracket '(' is encountered on the stack.
    • If the scanned character is an operator, pop from the stack and add to the postfix expression all operators that have higher or equal precedence than the scanned operator. Then push the scanned operator onto the stack.
    • After the entire infix expression has been scanned, pop and add all remaining operators from the stack to the postfix expression.
  3. Reverse the Postfix Expression: Reverse the postfix expression obtained in step 2 to get the final prefix expression.

  4. Correct the Order of Operands: Since the operands are reversed in the first step, it's important to correct their order in the final prefix expression.

Let's illustrate this algorithm with an example:

Infix Expression: A + (B * C)

  1. Reverse the Infix Expression: )C * B( + A
  2. Convert to Postfix:
    • Reverse brackets: (C * B) + A
    • Apply postfix algorithm: CB* A+
  3. Reverse the Postfix Expression: +A *BC
  4. Correct the Order of Operands: +A *BC (No change needed as operands A, B, and C are single characters)

Final Prefix Expression: +A *BC

Advantages and Disadvantages of Doubly Linked List

Advantages Disadvantages
Bidirectional Traversal: Allows traversal of the list in both directions, making it easier to navigate. Memory Usage: Each node requires extra memory for one additional pointer (previous pointer), compared to singly linked lists.
Ease of Deletion: Deletion of a node is more efficient because we can easily access the predecessor node. Complexity: Implementation of operations like insertion and deletion is more complex due to the need to handle two pointers.
Insertions and Deletions: Can be done in constant time if the pointers to the node are given. Memory Overhead: More memory overhead per element, which can be significant in systems with a large number of nodes and limited memory.
No Need for a Tail Pointer: Unlike singly linked lists, a doubly linked list can be traversed backwards without the need for a tail pointer. Pointer Errors: More pointers mean a higher chance of pointer errors, such as accidentally creating a loop in the list.

Example of Insertion and Deletion Operations in a Doubly Linked List Stored in Array Form

Let's assume we have a doubly linked list with nodes that have the following structure:

struct Node {
    int data;
    int prev; // Index of the previous node in the array
    int next; // Index of the next node in the array
};

Insertion Operation

To insert a new node after a given node:

  1. Allocate memory for the new node and put in the data.
  2. Change the next of the new node to the next of the given node.
  3. Change the next of the given node to the new node.
  4. Change the prev of the new node to the given node.
  5. Change the prev of the new node's next node to the new node.

Deletion Operation

To delete a node from the doubly linked list:

  1. If the node to be deleted is the head node, change the head.
  2. Change the next of the node's previous node, if it is not NULL.
  3. Change the prev of the node's next node, if it is not NULL.
  4. Free the memory for the node to be deleted.

Here's a simple example of how these operations might look in code:

// Assume array 'list' holds the nodes and 'head' points to the first node.

// Insertion after node at index 'x'
void insertAfter(int x, int data) {
    int newIndex = findFreeIndex(); // Function to find a free index in the array
    list[newIndex].data = data;
    list[newIndex].prev = x;
    list[newIndex].next = list[x].next;
    if (list[x].next != -1) {
        list[list[x].next].prev = newIndex;
    }
    list[x].next = newIndex;
}

// Deletion of node at index 'y'
void deleteNode(int y) {
    if (list[y].prev != -1) {
        list[list[y].prev].next = list[y].next;
    } else {
        head = list[y].next; // If head node is deleted, update the head
    }
    if (list[y].next != -1) {
        list[list[y].next].prev = list[y].prev;
    }
    // Assume -1 is used to indicate a free or null index
    list[y].prev = -1;
    list[y].next = -1;
}

In this example, findFreeIndex is a hypothetical function that would find an unused index in the array to store a new node. The -1 value is used to indicate a NULL pointer equivalent for the prev and next indices.