We know that the full binary tree is only a special binary tree. Most of the nodes of the binary tree do not exist completely, that is, many pointer fields are not fully utilized. On the other hand, when we traverse a binary tree in a certain order, we get a string of character sequences. After the traversal, we can know the precursor and Successor Relationship between nodes, that is, we can clearly know the precursor and successor of any node. However, this is based on the traversal. On the binary linked list, we can only know the address of each node pointing to its left and right child node, rather than who is the precursor of a node and who is the successor. You must traverse it once. Each time you need to know about it, you must traverse it once. Why don't you remember the pioneers and successors when creating them? How much time will be saved.
Based on the analysis from the two perspectives, we can consider using the empty addresses to store the addresses of the front-end and next nodes pointing to the nodes in a certain traversal order. We call this kind of pointer to the frontend and successor as a clue, and the binary chain table of the clue is called a chain table. The corresponding binary tree is called a threaded binary tree ).
6-10-2: After traversing the binary tree in the central order, we change the rchild in all NULL pointer fields to the next node of the binary tree.
6-10-3: After traversing the binary tree in the central order, we change the lchild in all the NULL pointer fields to the front node of the binary tree.
Figure 6-10-4 (the solid line of the hollow arrow is the precursor, and the black arrow of the dotted line is the successor) makes it easier to see that, as a result, a binary tree is transformed into a two-way linked list, which makes it easy to insert and delete nodes and find a node. Therefore, the process of traversing a binary tree in a certain order to turn it into a clue binary tree is called as a clue.
To distinguish whether the pointer field directs to the left and right children or to the frontend, two more ltags and rtags need to be added. When the ltag is 0, it indicates pointing to the left child, and when it is 1, it indicates pointing to the front child, if the rtag is 0, it indicates pointing to the right child. If the rtag is 1, it indicates pointing to the next child. Like the two-way linked list structure, you can add a header node to the binary tree linked list, as shown in Figure 6-10-6, the advantage of doing so is that we can traverse the first node starting with H (using 1, 4 lines ), you can also traverse the source node from the last node g (using two or three lines) and use the header node as the criterion for the end of the traversal.
The example program is as follows: (adapted from big talk data structure)
C ++ code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
|
# Include <iostream> Using namespace STD;# Define maxsize 50 Typedef char elemtype; Typedef Enum {link, thread} pointertag; Typedef char string [maxsize + 1]; // end with '\ 0' String STR;/* used to construct a binary tree */ /* Node Structure */ Typedef struct bthrnode { Elemtype data;/* node data */ Struct bthrnode * lchild;/* Left and Right child pointer */ Struct bthrnode * rchild; Pointertag ltag; Pointertag rtag; } Bthrnode, * bthrnodeptr; /* Construct a string */ Bool strassign (string DEST, char * PTR) { Cout <"Assign str..." <Endl; Int I; For (I = 0; PTR [I]! = '\ 0' & I <maxsize; I ++) Dest [I] = PTR [I]; Dest [I] = '\ 0 '; Return true; } Bool createbthrtree (bthrnodeptr * TPP) { Elemtype ch; Static int I = 0; If (STR [I]! = '\ 0 ') Ch = STR [I ++]; If (CH = '#') * TPP = NULL; Else { * TPP = (bthrnodeptr) malloc (sizeof (bthrnode )); If (! * TPP) Exit (1 ); (* TPP)-> DATA = CH;/* generate the root node */ Createbthrtree (& (* TPP)-> lchild);/* construct the left subtree */ If (* TPP)-> lchild) (* TPP)-> ltag = link; Createbthrtree (& (* TPP)-> rchild);/* construct the right subtree */ If (* TPP)-> rchild) (* TPP)-> rtag = link; } Return true; } Bthrnodeptr Prev;/* global variable, always pointing to the accessed node */ /* Perform a middle-order traversal to generate a middle-order clue */ Void inthreading (bthrnodeptr TP) { If (TP) { Inthreading (TP-> lchild);/* Line 3 bound during the first left recursion */ If (! TP-> lchild)/* No left child */ { TP-> ltag = thread;/* lead clue */ TP-> lchild = Prev;/* The left child Pointer Points to the front */ } If (! Prev-> rchild)/* No right child in front */ { Prev-> rtag = thread;/* Subsequent clues */ Prev-> rchild = TP;/* Forward the right child pointer to the next child (current node TP )*/ } Prev = TP; Inthreading (TP-> rchild);/* recursive right subtree clue */ } } /* Traverse the binary tree in the middle order and generate the clues. * HPP points to the header node */ Bool inorderthreading (bthrnodeptr * HPP, bthrnodeptr TP) { Cout <"inorderthreading..." <Endl; * HPP = (bthrnodeptr) malloc (sizeof (bthrnode )); If (! (* HPP )) Exit (1 ); (* HPP)-> ltag = link;/* Header node */ (* HPP)-> rtag = thread; (* HPP)-> rchild = (* HPP);/* Right pointer back */ If (! TP) (* HPP)-> lchild = * HPP;/* If the binary tree is empty, the left pointer returns */ Else { (* HPP)-> lchild = TP;/* bound line 1 */ Prev = (* HPP);/* the header node is the first point that has elapsed */ Inthreading (TP);/* perform a middle-order traversal to generate a middle-order clue */ Prev-> rchild = * HPP;/* the successor of the last node points to the header node, that is, line 4 */ Prev-> rtag = thread; (* HPP)-> rchild = Prev;/* the successor of the header node points to the last node, that is, line 2 */ } } /* Non-recursive algorithm for traversing the binary clue tree (head node) in the middle order */ Bool inordertraverse_thr (bthrnodeptr HP) { Cout <"inordertraverse..." <Endl; Bthrnodeptr bp; BP = hp-> lchild;/* BP points to the root node */ While (BP! = HP) { /* When the empty tree or traversal ends, BP = hp */ While (BP-> ltag = link) BP = BP-> lchild; /* Access the node with the left subtree empty */ Cout <bp-> data <''; While (BP-> rtag = thread & BP-> rchild! = HP) { BP = BP-> rchild; Cout <bp-> data <'';/* access the next node */ } BP = BP-> rchild; } Return true; } Int main (void) { Bthrnodeptr HP, TP; Strassign (STR, "abdh ### I ## EJ ### CF ## g ##"); Cout <"input pre-order traversal sequence:" <Endl; Cout <STR <Endl; Createbthrtree (& TP ); Inorderthreading (& HP, TP ); Inordertraverse_thr (HP ); Return 0; } |
Output:
Because the clue binary tree makes full use of the space of the NULL pointer field, it ensures that the pre-and post-propagation information can be continuously used once a traversal is created, therefore, if the binary tree used needs to traverse or search for the knots frequently and requires a kind of traversal sequence, the storage structure of the clue binary linked list is a good choice.