Top-20 Training Program (Data Structures) This work is licensed under a Attribution-NonCommercial-NoDerivs CC BY-NCND(http://creativecommons.org/licenses/by-nc-nd/3.0/) Stack(or Queue) Less Traversals Until now we have seen different ways of traversing a binary tree using stack(with or without recursion) and queue data structures in linear time. Can we do the same without using those explicit data structures in linear time? The following are the techniques we can use to perform traversal of binary tree without using stack and queue. 1) Threaded Binary Trees 2) Traveral by Link Inversion 3) Siklossy Traversal In this chapter we discuss Threaded Binary Tree idea. For remaining techniques, refer to[2]. Threaded Binary Trees ------------------------Fundamental idea: If we represent the binary tree in linked representation ,the number of NULL links in a binary tree of n nodes will be n+1. Hence, approximately half the space we allocate to hold the links in the left and right fields is wasted. In the following tree of 6 nodes, there are 7 NULL links. Fig. The Number of NULL links in a binarytree Why don’t we use this space for some useful purpose? In a threaded binary tree, this space which would otherwise be wasted is put to use by storing a pointer to some other node in the left or right fields of a node with no left or right son (or both). This pointer shall point to another node that bears a special relationship to Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) the node in question. This pointer is called the thread link, and it is distinguished from a true link (a pointer to a true right or left son) with the use of a tag bit. Binary Tree Vs Threaded Binary Tree ----------------------------------------We now have the following node structure and definitions for threaded binary tree: -----------------------------------------------------------------------------| ltag | Pointer to | data | Pointer to | rtag | | | Left child | | Right child | | -----------------------------------------------------------------------------Ordinary Binary Tree -------------------------left (P) = NULL left(P) = a right(P) = NULL right(P) = a Inorder Threaded Binary Tree -------------------------------------ltag(P) = 0, left(P) = inorder predecessor of P ltag(P) = 1, left(P) = a rtag(P) = 0, right(P) = inorder successor of P rtag(P) = 1, right(P) = a So that the left thread link of the leftmost node (which has no inorder predecessor) and the right link of the rightmost node (which has no inorder successor) won’t be left hanging, a special node called the head node or the list head is included in the representation of an inorder threaded binary tree. The following Fig. shows the representation of the binary tree in fig. as a threaded binary tree. Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) Fig. An inorder threaded binary tree We take note of the following observations: (1) the binary tree is the left subtree of the list head, and (2) the list head is its own right son. These conventions will be utilized later on in the traversal algorithms for threaded binary trees. Following these conventions, a null binary tree may be represented as shown below. Declarations of Threaded Binary Tree ------------------------------------------Following are the declarations needed for a node of a Threaded Binary Tree and itself. struct TBinaryNode { int ltag; struct TBinaryNode *left; ElementType data; Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) struct TBinaryNode *right; int rtag; }; typedef struct TBinaryNode* TBinaryTree; typedef struct TBinaryNode* Tposition; One way to grow up threaded binary tree is to start from creating a header node and insert root node to the left of header node. From this point, whenever we need to insert a new node q in the tree, insert it to left or right child of some random node p if no such child exists for p. Problem-I -----------Given two nodes p and q, write an efficient function to attach q to the right son of p in an inorder threaded binary tree. What are the time and space complexities of your solution? Function Prototype: void InsertRight(Tposition p, Tposition q) Solution: Following are the two cases that will arise when q is inserting as right child of p. Case-1: Node p doesn’t have right child Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) Case-2: Node p has a right child(or right subtree) Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) void InsertRight(Tposition p, Tposition q) { Tposition tmp; q->right = p->right; q->rtag = p->rtag; q->left = p; q->ltag = 0; p->right = q; p->rtag = 1; // take care of case-2 if(q->rtag ==1) { tmp = q->right; while(tmp->ltag) tmp = tmp->left; tmp->left = q; } } Time Complexity: O(n) Space Complexity: O(1) Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) Problem-II ------------Given an inorder threaded binary tree T and a node address p, write an efficient function to find the preorder successor of p in T. What are the time and space complexities of your solution? Function Prototype: Tposition PreSuccessorT(TBinaryTree t, Tposition p) Solution: If p has a left subtree, then return the left son of p. If p has no left subtree, then return the right son of the nearest root whose left subtree contains p. Tposition PreSuccessorT(Tposition p) { Tposition tmp; if(t->ltag == 1) return p->left; else { tmp=p; while(tmp->rtag==0) tmp=tmp->right; return tmp->right; } } Time Complexity: O(n) Space Complexity: O(1) Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) Problem-III -------------Given an inorder threaded binary tree T, write an efficient function to display elements of T in preorder. What are the time and space complexities of your solution? Function Prototype: void PreOrderT(TBinaryTree t) Solution: Start with list head, call PreSuccessorT to visit each node till we get list head again. void PreOrderT(TBinaryTree t) { Tposition p=t; while(1) { p=PreSuccessorT(p); if(p==t) return; printf(“%d\n”, p->data); } } Aha! Analysis --------------Initially, p points to the list head. SuccessorT(p) with the argument p pointing to the list head will return the root of binary tree. Subsequent calls to PreSuccessorT will yield the sequence in preorder. The last call to PreSuccessorT with the pointer to rightmost node as its argument will return the address of the list head, and the function terminates at that point. The important thing to note about the function PreOrderT is that it carries out preorder traversal without the use of a stack. How much time does preorder traversal take? Since we traverse all the tree links[=n-1] and all right thread links[=(n+1)/2]. Time Complexity: Θ(n) Space Complexity: O(1) Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537 Top-20 Training Program (Data Structures) Stack Less Traversal-I Solve the following problems. Problem-I(5 points) -----------Given two nodes p and q, the following function attaches q to the left son of p in an inorder threaded binary tree. Fill up the missing logic. void InsertRight(Tposition p, Tposition q) { q->left = p->left; q->ltag = p->ltag; q->right = p; q->rtag = 0; p->leftt = q; p->ltag = 1; if(q->ltag ==1) { } } Problem-II(10 points) ------------Given an inorder threaded binary tree T and a node address p, write an efficient function to find the inorder successor of p in T. Use this function to write a function for inorder traversal of given binary tree. What are the time and space complexities of your solution? Function Prototype: Tposition InSuccessorT(Tposition p) void InOrderT(TBinaryTree t) Copyright © 2008 By Algorithmica www.algorithmica.co.in Ph:040-64562535, 9246582537