We have seen the in-order traversal of a binary tree. It is a recursive code. Recursion stack can be simulated using an explicit Stack data structure and keeping the function non-recursive. Let us see how:
When a function calls itself, its activation record (stack frame) is pushed in the function call stack of memory. The function call stack can be simulated using an extra stack. This logic can be used to convert any recursive implementation to non-recursive.
Take a Stack data structure and push contents of activation record (stack frame) of a function into that stack and simulate the recursion. Let us see the recursive function to print pre-order traversal of a binary tree again
void preOrder(Node*r) { if(r==NULL){ return; } // TERMINATING CONDITION cout<<r->data<<" "; preOrder(r->left); preOrder(r->right); }
Here we are printing the data at the root and doing the preorder traversal of left subtree, followed by pre-order traversal of right subtree. In a way, after printing the root, we follow the left subtree and when recursion returns to the root again, we call it for right sub-tree.
This can be done by proceeding with the left subtree while pushing the right subtree in stack. After we are done with the left subtree, pop the stack and traverse that subtree.
void preOrderStack(Node*r) { if (r == NULL) return; Stack s; while(r != NULL) { cout<< r->data<<" "; if(r->left == NULL) r = s.pop(); else { if(r->right != NULL) // PUSH RIGHT CHILD FOR LATER s.push(r->right); r = r->left; } } }
Asymptotic time taken by both the functions is O(n), but preOrderStack takes less time than the previous one. Below is the complete code in C++
#include <iostream> using namespace std; // TREE NODE struct Node{ int data; Node* left; Node* right; Node(int x):data(x), left(NULL), right(NULL){} }; //STACK IMPLEMENTATION class Stack { // NODE OF A LINKED LISTs struct SNode{ Node* data; SNode* next; // CONSTRUCTORS SNode():data(NULL), next(NULL){} SNode(Node* v):data(v), next(NULL){} }; SNode* top; public: Stack():top(NULL){} // DEFAULT CONSTRUCTOR. top = NULL void push(Node* x); Node* pop(); bool isEmpty(); }; void Stack::push(Node* x){ SNode* temp = new SNode(x); temp->next = top; top = temp; } Node* Stack::pop(){ if(isEmpty()) // STACK EMPTY { cout<<"STACK EMPTY"; return NULL; } else{ // REMOVE THE FIRST NODE Node* value = top->data; SNode* temp = top; top = top->next; delete temp; return value; } } bool Stack::isEmpty(){ return (top == NULL); } void preOrder(Node*r) { if(r==NULL){ return; } // TERMINATING CONDITION cout<<r->data<<" "; preOrder(r->left); preOrder(r->right); } void preOrderStack(Node*r) { if (r == NULL) return; Stack s; while(r != NULL) { cout<< r->data<<" "; if(r->left == NULL) r = s.pop(); else { if(r->right != NULL) // PUSH RIGHT CHILD FOR LATER s.push(r->right); r = r->left; } } } int main() { Node *r = new Node(5); r->left = new Node(3); r->right = new Node(20); r->left->left = new Node(1); r->left->right = new Node(4); r->right->left = new Node(15); r->right->right = new Node(25); r->right->right->left = new Node(13); r->right->right->right = new Node(17); preOrder(r); cout<<endl; preOrderStack(r); cout<<endl; return 0; }