12. Establish a binary tree and a binary tree
1. Traverse Binary Trees1. DefinitionBinary tree traversal refers to accessing all the nodes in the binary tree in sequence from the root node, so that each node is accessed once and only once.2. Forward Traversal(1) Rules: If the binary tree is null, the return value is null. Otherwise, first access the root node, then traverse the left subtree In the first order, and then traverse the right subtree In the first order.(2) Instances
The result of the pre-order traversal is a bdgh ceif analysis: when the root node is accessed first, the left subtree is traversed in the pre-order. When you access the left subtree of the root, we assume that B is the root of the Left subtree to traverse it.(3) algorithmsWe can see from the binary tree definition that it uses recursion. Therefore, the traversal algorithm can also adopt recursion.
<Span style = "font-size: 18px;">/* recursive algorithm for pre-order traversal of Binary Trees */void PreOrderTraverse (BiTree T) {if (T = NULL) // if the tree is empty, return blank return; printf ("% c", T-> data); // display node data, you can change it to another node operation PreOrderTraverse (T-> lchild); // You can traverse the left subtree PreOrderTraverse (T-> rchild) first ); // finally traverse the right subtree} </span>
Instance analysis:As shown in, when PreOrderTraverse (T) function is called, the program runs as follows: a) PreOrderTraverse (T) is called, and T root node is not null. Therefore, printf is executed to print the letter; b) then, call PreOrderTraverse (T-> lchild) to access the left child of node A. If node B is not null, execute printf to print B. c) in this case, call PreOrderTraverse (T-> lchild) recursively, access the left child of Node B, and execute printf to print the letter D; d) execute PreOrderTraverse (T-> lchild) Again ), the left child accessing the D node, execute printf to print the letter G; e) execute PreOrderTraverse (T-> lchild) Again, and access the left child of the G node, because the G node does not have the left child, the returned result is null, so T = null returns this function. At this time, PreOrderTraverse (T-> rchild) is called to access the right child of node D and run Printf prints the letter H; f. 3. Sequential Traversal
(1) Rules: If the tree is empty, the return value is null. Otherwise, start from the root node (note that the root node is not accessed first), traverse the left subtree of the root node in the middle order, then access the root node, and traverse the right subtree in the middle order.
(2) Instances
The result of the Middle-order traversal is: gdhb a eicf.
(3) algorithms
<Span style = "font-size: 18px;">/* Central order traversal recursive algorithm */void InOrderTraverse (BiTree T) {if (T = NULL) return; inOrderTraverse (T-> lchild); // traverse the left subtree printf ("% c", T-> data) in the middle order; // display node data, you can change it to another node operation InOrderTraverse (T-> rchild); // Finally, traverse the right subtree in the middle order} </span>
4. Post-order traversal
(1) Rules: If the tree is empty, the return value is null. Otherwise, you can traverse the left and right subtree from left to right, and then access the root node.
(2) Instances
The result of the post-order traversal is: GHDB IEFC
(3) algorithms
<Span style = "font-size: 18px;">/* recursive algorithm for post-order traversal of Binary Trees */void PostOrderTraverse (BiTree T) {if (T = NULL) return; postOrderTraverse (T-> lchild); // traverse the left subtree PostOrderTraverse (T-> rchild) sequentially; // then traverse the right subtree printf ("% c ", t-> data); // displays node data, which can be changed to other node operations. </span>
5. Sequence Traversal
(1) Rules: If the tree is empty, the return value is null. Otherwise, access from the first layer of the tree, that is, the root node, is traversed layer by layer from top to bottom. In the same layer, access the nodes one by one in the order from left to right.
(2) Instances
Sequence traversal result: A BC DEF GHI
Ii. Derivation of traversal resultsBinary tree traversal properties: (1) a binary tree can be uniquely identified by pre-sequential and mid-order traversal sequences; (2) a post-sequential traversal sequence and a middle-order traversal sequence, A binary tree can be uniquely identified; 1. assume that the pre-order traversal sequence of a binary tree is ABCDEF and the middle-order traversal sequence is CBAEDF. What is the result of the post-order traversal of this binary tree? Analysis: 2. Assume that the Chinese and Western sequence of a binary tree is ABCDEFG, And the post sequence is BDCAFGE? Analysis:
Iii. Establishment of Binary TreesFor a common Binary Tree, We need to extract the NULL pointer of each borrow point in the binary tree to a virtual node. Its value is a specific value, such "#". We call this processed binary tree an Extended Binary Tree of the original binary tree. The extended binary tree can be used to determine a binary tree through a "forward", "Central", or "backward" traversal sequence. (1) The sequential sequence of the Extended Binary Tree is AB # D # C # (2) implementation algorithm.
<Span style = "font-size: 18px;">/* enter the borrow value (one character) in the binary tree in the forward Order * Where # indicates the empty tree, construct a binary linked list to represent the binary tree T */void CreateBitree (Bitree * T) {TElemType ch; scanf ("% c", & ch ); // enter the node data character if (ch = '#') * T = NULL; else {* T = (BiTree) malloc (sizeof (BiTNode )); // if (! * T) // if the allocation is unsuccessful, the end of the exception (memory OVERFLOW) exit (OVERFLOW); (* T)-> data = ch; // generate the root node CreateBiTree (& (* T)-> lchild); // construct the left subtree CreateBiiTree (& (* T)-> rchild ); // construct the right subtree }}</span>
Conclusion: In fact, building a binary tree also uses recursion to stay away, but it is only necessary to generate a node and assign values to the node where it was originally printed. In addition, we can also establish a binary tree by means of central or post-order traversal, except that the node generated in the code and the code order for constructing the left and right word subtree can be exchanged.
4. Clue Binary TreeFor a binary linked list with n nodes, each node has two pointer fields pointing to the left and right children, so there are a total of 2n pointer fields. The n-node binary tree has a total of n-1 branch lines (the root node has no precursor). That is to say, there are actually 2n-(n-1) = n + 1 null pointer fields. Because these spaces do not store anything, this will lead to a waste of memory resources. In addition, 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. If you want to know, you must traverse the linked list once. You must traverse the linked list once each time you need to know it. In order to provide memory space utilization and save operation time, we can consider clarifying the frontend and successor of the node at creation.
1. Clue Binary TreeIf we call the pointer pointing to the front and back-drive as a clue, the Binary linked list with the clue is called a clue linked list; the Binary Tree with the clue is called a Threaded Binary Tree ), the process of traversing a binary tree in a certain order to turn it into a clue binary tree is called a clue. Using the clue binary tree, we can traverse it to operate a two-way linked list structure, which greatly improves the access speed. For example, after A binary tree is traversed in A central order: hdibje a fcg, A null pointer refers to the successor or precursor to A forward direction (node rchild pointer or lchild pointer.
2. Structure and implementation of a clue Binary Tree node
(1) node StructureIt is unknown whether the lchild of a node points to its left child or the front child, whether the rchild points to the right child or to the next child. Therefore, we add two more ltag and rtag in each node. Note that ltag and rtag only store the Boolean variables of numbers 0 or 1, the occupied memory space is smaller than the pointer variables like lchild and rchild. The node structure is as follows:
(2) Implementation of the clue Binary Tree Structure
<Span style = "font-size: 18px; ">/* Binary Tree binary clue storage structure definition * Link = 0 indicates the left and right child pointers * Thread = 1 indicates the Clues pointing to the front or rear drive */typedef eum {Link, thread} PointerTag; typedef struct BiThrNode/* binary clue storage node Structure */{TElemType data; // data field: node data struct BiThrNode * lchild, * rchild; // pointer field: left/right child pointer PointerTag LTag; PointerTag RTag; // left/right flag} BiThrNode, * BiThrTree; </span>
3. recursive functions with clues in the middle order traversal (difficult)The essence of the clue is to change the NULL pointer in the binary linked list to the leading or successor clue. Because the information of the frontend and successor 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 of the recursive function for Traversing clues in the middle order is as follows: BiThrTree pre; // global variable, always point to the accessed node/* In-order traversal to perform in-order clue */void InThreading (BitThrTree p) {if (p) {InThreading (p-> lchild ); // recursion left subtree for clues if (! P-> lchild) // No left child at the node {p-> LTag = Thread; // lead: Set the left pointer of the node to 1, note that the Left Pointer Points to the frontend p-> lchild = pre; // The left Pointer Points to the frontend} if (! Pre-> rchild) // No right child before {pre-> RTag = Thread; // pre-rchild = p; // forward the right child pointer to the next child (current node p)} pre = p; // keep the forward InThreading (p-> rchild) of the pre pointing to p ); // recursive right subtree clue} source code analysis: (1) node precursor clue 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. (2) The node is driven after the drive because the node has not been accessed, so it can only make a judgment on its front node pre's right pointer rchild, 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. (3) The pre = p statement is used to assign the current node p to the pre after completing the judgment of the precursor and its successor, so that it can be used for the next time.
4. Non-recursive algorithm for traversing the clue binary tree T in the middle orderBinary Tree binary clue storage representation (taking the central order as an example): Add a header node to the online cable chain table and point the lchild domain pointer to the root node of the binary tree, its rchild domain Pointer Points to the last point of sequential access. The lchild domain pointer of the first node in the sequence serial in the binary tree and the rchild domain pointer of the last node all point to the header node. In this way, a two-way clue linked list is created. The advantage of this definition is that the traversal can be performed from the first node to the next, or from the last node to the front.
/* T points to the header node. The left-click lchild of the header node points to the root node. The right-link rchild of the header node points to the last node of the central traversal. * it traverses the binary tree T represented by the chain table of the two forks in the central order, the time complexity is O (n) */Status InOrderTraverse_Thr (BiThTree T) {BiThrTree p; p = T-> lchild; // p points to the root node while (p! = T) // when the empty tree or traversal ends, 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 ); // display the node data. You can change it to another while (p-> RTag = Thread & p-> rchild! = T) {p = p-> rchild; printf ("% c", p-> data);} p = p-> rchild; // p to its right child root} source code analysis: (1) p = T-> lchild; point p to the root node to start traversing, as shown in number ①; (2) while (p! = T): that is, loop until ④ 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 will continue. (3) The while (p-> LTag = Link) loop 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 end this loop and print H; (4) 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. (5) p = p-> rchild, that is, p points to the right child of node D. ...... Loop until the print HDIBJEAFCG ends the traversal operation.
Conclusion: The clue of a binary tree is conducive to saving space and time. In actual problems, if the binary tree used needs to traverse or search for the knots frequently, the first and subsequent components in the traversal sequence are required, therefore, using the storage structure of the clue binary linked list is a very good choice.