Thoroughly understand the clue Binary Tree and the clue Binary Tree
I. Principles of clue Binary Tree
The number of empty chain fields is always greater than that of non-empty chain fields regardless of the form of the binary tree. To be precise, there are 2n chain domains in the binary Chain List of n nodes and n-1 non-empty chain domains, but n + 1 empty chain domains exist. As shown in.
Therefore, a method is proposed to store pointers using the original empty Chain Domain to point to other nodes in the tree. This pointer is called a clue.
Note that ptr points to a node in the binary linked list. The following are the rules for creating clues:
(1) If ptr-> lchild is empty, it will store the front node pointing to the node in the ordinal traversal sequence. This node is called the forward of ptr;
(2) If ptr-> rchild is empty, it stores the successor nodes pointing to the node in the ordinal traversal sequence. This node is called the Middle-order successor of ptr;
Obviously, it is necessary to identify whether lchild points to the left child or the front child, whether the rchild points to the right child or the next child. Therefore, we add two more ltag and rtag in each node. Note that ltag and rtag are only Boolean variables that distinguish numbers 0 or 1, the memory usage is smaller than the pointer variables like lchild and rchild. The node structure is as follows.
Where:
(1) When the ltag is 0, it points to the left child of the node, and when it is 1, it points to the precursor of the node;
(2) When rtag is 0, it points to the right child of the node, and when rtag is 1, it points to the successor of the node;
(3) Therefore, the binary linked list chart can be modified as a child.
II. Implementation of the clue Binary Tree Structure
The binary clue tree storage structure is defined as follows:
/* Binary Tree binary clue storage structure definition */typedef enum {Link, Thread} PointerTag; // Link = 0 indicates pointing to the left and right child pointers; thread = 1 indicates the lead or successor clue typedef struct BitNode {char data; // The node data struct BitNode * lchild, * rchild; // left and right child pointer PointerTag Ltag; // left and right signs PointerTag rtal;} BitNode, * BiTree;
The essence of the clue is to change the NULL pointer in the binary linked list to the leading or successor clue. Because the frontend and successor information can be obtained only when the binary tree is traversed, the clue process is the process of modifying the NULL pointer during the traversal process.
The code for the link-based Recursive Function of sequential traversal is as follows:
BiTree pre; // global variable, always pointing to the recently accessed node // The middle-order traversal to perform the Middle-order clue void InThreading (BiTree p) {if (p) {InThreading (p-> lchild); // recursion left subtree clue // === if (! P-> lchild) // No left child {p-> ltag = Thread; // front lead p-> lchild = pre; // left child pointer pointing to front} if (! Pre-> rchild) // No right child {pre-> rtag = Thread; // subsequent clues pre-> rchild = p; // forward the right child pointer to the next child (current node p)} pre = p; // === InThreading (p-> rchild ); // recursive right subtree clue }}
Except for the code between // =, the above Code has the same opportunity as the recursive code of sequential traversal in a binary tree. Instead, the print node function is changed to the clue function.
Some code in the middle has done the following:
At this time, the successor of the p node has not been accessed, so it can only judge the right pointer rchild of its precursor node pre, if (! Pre-> rchild) indicates that if it is null, p is the successor of pre, so pre-> rchild = p, and set pre-> rtag = Thread, complete the clue of the successor node.
If (! P-> lchild) indicates that if the left pointer field of a node is null, The pre can be assigned to p-> lchild because its precursor node has just been accessed and assigned a pre value, and modify p-> ltag = Thread (that is, defined as 1) to complete the clue of the precursor node.
Do not forget that the current node p is assigned to the pre for the next use after the previous and subsequent judgment.
With the clue binary tree, the traversal is actually equivalent to operating a two-way linked list structure.
Like a two-way linked list node, add a header node to the binary tree linked list, as shown in, and point the lchild domain pointer to the root node of the binary tree (the first step in the figure ), its rchild domain Pointer Points to the last node in the middle-order traversal access (the second step in the figure ). Otherwise, the lchild domain pointer and the rchild domain pointer of the last node point to the header node in the first node of the intermediate sequence of the binary tree (Steps 3 and 4 in the figure ). The advantage is that we can traverse from the first node to the next, or from the last node to the front.
The traversal code is as follows.
// T points to the header node. lchild points to the left link of the header node, and rchild points to the last node in the middle-order traversal. // Traverse the binary tree in the middle order to indicate the binary tree tint InOrderThraverse_Thr (BiTree t) {BiTree p; p = t-> lchild; // p points to the root node while (p! = T) // empty tree or p = t {while (p-> ltag = Link) at the end of Traversal) // when ltag is set to 0, the first node {p = p-> lchild;} printf ("% c", p-> data) that loops to the intermediate sequence is returned ); // display the node data, which can be changed to other operations on the node while (p-> rtag = Thread & p-> rchild! = T) {p = p-> rchild; printf ("% c", p-> data);} p = p-> rchild; // p enters its right subtree} return OK ;}
Note:
(1) In the code, p = t-> lchild indicates the first step in which p points to the root node to start traversing;
(2) while (p! = T) Actually, it means to loop until the fourth step in the figure appears. This means that p points to the header node, so it is equal to t (t is the pointer to the header node) and ends the loop, otherwise, the traversal operation will continue continuously;
(3) The loop while (p-ltag = Link) is formed by A-> B-> D-> H, at this time, the ltag of the H node is not a link (that is, it is not equal to 0), so this loop ends;
(4) print H;
(5) while (p-> rtag = Thread & p-> rchild! = T) because the rtag of node H is Thread (equal to 1), and does not point to the header node. Therefore, print the successor D of H, and then exit the loop because the rtag of D is Link;
(6) p = p-> rchild; that is, p points to the right child of node D;
(7) ...... The traversal will continue until HDIBJEAFCG is printed.
From this code, we can see that it is like scanning a linked list, so the time complexity is O (n ).
It makes full use of the space of the NULL pointer field (equivalent to saving space), and ensures that a traversal at the time of creation can be used for the rest of the life (meaning saving time ). Therefore, in actual problems, if the binary tree used needs to traverse or search for the knots and the frontend and successor in a traversal sequence, the storage structure of the clue binary linked list is a very good choice.
# Include <stdio. h> # include <stdlib. h> # define ERROR 0 # define OK 1 typedef enum {Link, Thread} PointerTag; // link = 0 indicates pointing to left and right children pointer // Thread = 1 indicates pointing to the leading or successor clues typedef struct BitNode {char data; // The node data struct BitNode * lchild; // left and right child pointer struct BitNode * rchild; PointerTag ltag; // left and right signs PointerTag rtag;} BitNode, * BiTree; BiTree pre; // global variable, always point to the accessed node // create a binary tree void CreateTree (BiTree * t) {char ch; scanf ("% c", & ch ); If (ch = '#') {* t = NULL;} else {(* t) = (BiTree) malloc (sizeof (BitNode )); if (* t) = NULL) {return;} (* t)-> data = ch; CreateTree (& (* t)-> lchild )); createTree (& (* t)-> rchild) ;}// t points to the header node, and the left link lchild of the header node points to the root node, the right-chain rchild of the header node points to the last node in the middle-order traversal. // Traverse the binary tree tint InOrderThraverse_Thr (BiTree t) {BiTree p; p = t-> lchild; // p points to the root node while (p! = T) {while (p-> ltag = Link) // when ltag = 0, the first node of the intermediate sequence is cyclically {p = p-> lchild ;} printf ("% c", p-> data); // displays node data, you can change it to another operation on the node while (p-> rtag = Thread & p-> rchild! = T) {p = p-> rchild; printf ("% c", p-> data);} p = p-> rchild; // p goes to its right subtree} return OK;} // performs a middle-order traversal to generate a middle-order clue void InThreading (BiTree p) {if (p) {InThreading (p-> lchild ); // recursion left subtree for clues if (! P-> lchild) // No left child {p-> ltag = Thread; // front lead p-> lchild = pre; // The left child Pointer Points to the front, here is Step 1} if (! Pre-> rchild) // No right child {pre-> rtag = Thread; // subsequent clues pre-> rchild = p; // forward the right child pointer to the next child (current node p)} pre = p; InThreading (p-> rchild ); // recursively turn the right subtree into clues} // create a header node and a middle-order clue Binary Tree int InOrderThread_Head (BiTree * h, BiTree t) {(* h) = (BiTree) malloc (sizeof (BitNode); if (* h) = NULL) {return ERROR;} (* h)-> rchild = * h; (* h) -> rtag = Link; if (! T) // if it is NULL {(* h)-> lchild = * h; (* h)-> ltag = Link;} else {pre = * h; (* h)-> lchild = t; // Step 1 (* h)-> ltag = Link; InThreading (t ); // locate the last node pre-> rchild = * h; // Step 4 pre-> rtag = Thread; (* h)-> rchild = pre; // Step 2} int main (int argc, char ** argv) {BiTree t; BiTree temp; printf ("Enter the content of the pre-ordered binary tree: \ n "); createTree (& t); // create a binary tree InOrderThread_Head (& temp, t); // Add the header node and generate a clue to printf ("output content of the ordinal Binary Tree: \ n "); InOrderThraverse_Thr (temp); printf (" \ n "); return 0 ;}
This article is based on http://blog.chinaunix.net/uid-26548237-id-4266920.html !!
In terms of data structure, can a full binary tree and a full binary tree be clue-driven?
Yes. Why not! First, we need to understand what is a clue binary tree and why there is a clue binary tree. The clue binary tree is mainly proposed for the existence of many idle pointers in the chain binary tree. If a binary tree has n nodes, there are a total of 2n pointers, but only n-1 pointers are used, and n + 1 pointers are idle pointers. When we make full use of these idle pointers to store the precursor or successor information, it becomes a clue binary tree. Pointers of leaf nodes full of Binary trees or full Binary Trees are free pointers and can be used to store clue information.
Issue about clues in the clue Binary Tree
I don't think you know what pre points.
My data structure book is of the Yan Weimin edition. The book says this: pre always points to the accessed node. If the pointer root points to the currently accessed node, then pre points to its prefix.
It is a bit abstract. In fact, it is mainly to know when to change the pre value. "pre always points to the accessed node" means that the pre value is changed after a node is accessed.
The specific idea is as follows: first, the code that creates clues in the book is a process of sequential traversal. The access order is divided into three steps: Left subtree-> itself node-> right subtree. The left subtree is used to call the function Inthread (root-> Lchild ). Any operation to access a node must be in the second step of the three steps, because the first step can be divided into three steps. It can be seen that the pre value should be modified after Step 2 and before step 3, that is, before Inthread (root-> Rchild. As in the code.
In addition, you must assign a value to pre before calling Inthread for the first time.
1. the root node in this Code may point to any node in the binary tree, because any node can be seen as the root node of A subtree, therefore, it can be understood that root points to the root node of the binary tree itself or its subtree.
Root-> Lchild = pre: This code points the left subtree of the current node to the pre of the current node, that is, to create a prefix index.
2. This code is mainly used to determine whether to establish a clue for pre. The prerequisite for establishing a clue is that the right node is null, which is the judgment in if.
Pre-> Rchild = root is to create a subsequent index for pre. Pre is the root prefix. In turn, root is the result of pre.
3. pre-continuation and subsequent node pointing are achieved through the pre-root relationship. Taking the first node as an example is quite special, because if the root node points to the first node, this is the first call. pre should be assigned a value before the call.