Binary tree is a very common and useful data structure, which combines the advantages of an ordered array with a linked list. Finding data in a binary tree is as fast as finding data in an array, and adding and removing data in a binary tree is as efficient as it is in a linked list, so the relevant technology of binary tree has always been a must in the programmer's interview test.
- Basic knowledge
- Basic concepts
- Properties
- Examples of binary trees
- Recursive implementation of two-fork tree traversal
- How sequence traversal and sequential traversal are known
- Extended known sequence traversal and post-order traversal for First order traversal
- The sequential traversal of two-fork tree by non-recursive implementation
- How to use non-recursive method to realize the first order traversal and the middle sequence traversal of two-fork tree
- Using non-recursive algorithm to find the depth of binary tree
- Hoffman codec
Basic knowledge
Binary trees (binary tree) are also known as binary trees, two-ary trees, pairs of trees, etc., which are a set of N (n>=0) finite elements. The set is either empty or consists of an element called root (root) and two not-to-be-crossed, two-tree trees that are called the Saozi right subtree, respectively. When the collection is empty, the two fork tree is called an empty binary tree.
In a binary tree, an element is also called a node. Recursive definition of binary tree: two fork tree or an empty tree, or a tree by a root node and two disjoint respectively called the root node of the Saozi right sub-tree composed of non-empty tree, Saozi right subtree is also a binary tree.
Basic concepts
Here are some basic concepts of some common two-fork trees:
(1) The degree of the nodal point. The number of subtrees owned by a node is called the degree of the node.
(2) leaf node. Nodes with a degree of 0 are called leaf nodes, or terminal nodes.
(3) Branching nodes. A node with a degree of not 0 is called a branch, or is called a non-terminal junction. The nodes of a tree are branch nodes except for the leaf nodes.
(4) left child, right child, parents. The root node of a subtree of a node in a tree is called the child of this node. This node is called the parent of the child's node. Children with the same parent are called Brothers.
(5) path, path length. If a cluster of nodes of a tree n1,n2,..., NK has the following relationship: Ni+1 's parent node () at Node ni 1<=i<k
, N1,n2,..., nk is called a path by N1~nk. The length of this path is k-1
(6) Ancestors and descendants. In a tree, if there is a path from the node m~ node n, then M is called the ancestor of N, and N is called the descendant of M
(7) The number of layers of the node. The number of layers for the root node of the specified tree is 1, and the remaining nodes are equal to the number of layers of their parent nodes plus 1.
(8) The depth of the tree. The maximum number of layers for all nodes in a tree is called the depth of the tree.
(9) The degree of the tree. The maximum number of nodes in a tree is called the degree of the tree, and the degree of leaf node is 0.
(10) Full two fork tree. In a binary tree, if all branch nodes have Saozi right subtree, and all leaf nodes are on the same layer, such a binary tree is called full two fork tree
(11) Complete binary tree. A two-prong tree with n nodes at a depth of k, the nodes in the tree are numbered from top to bottom, left to right, and if the nodes numbered I () are in the same position in the binary tree as the nodes 1<=i<=n
numbered I in the full two-tree, the binary tree is called a complete binary tree. The complete binary tree is characterized by: leaf nodes can only be present at the bottom and sub-lower, and the lowest leaf nodes are concentrated in the left part of the tree. It is important to note that a full two fork tree is definitely a binary tree, while a complete binary tree is not necessarily a full two-fork tree.
Properties
The basic properties of the binary tree are as follows
Property 1: There is a maximum of 2^ (i-1) nodes (i>=1) on the layer I of a non-empty binary tree.
Property 2: A two-fork tree with a depth of k, with a maximum of 2^k-1 nodes and a minimum of K nodes.
Property 3: For a non-empty two-fork tree, the degree of 0 of the node (that is, the leaf node) is always more than 2 nodes, that is, if the leaf node is n0, the degree of 2 is N2, then there is N0 = n2 + 1.
Proof: The total number of nodes represented by N0 is 0 (leaf node), the total number of nodes with N1 expressed as 1, N2 the total number of nodes with 2 representation, and N represents the total number of nodes of the whole binary tree, then n=n0+n1+n2. According to the nature of the binary tree and the tree, we can know n=n1+2*n2+1 (The sum of all nodes is +1 = total number of nodes), according to two equations N0 + n1 +n2 = N1+2*n2 +1, so n2 = n0-1, i.e. N0 = n2 + 1. So n = n0 + n1 + n2.
Property 4: Full binary tree with n nodes has a depth of log2 n + 1 (log with 2, logarithm of n, rounded down)
Proof: According to the nature of 2, the depth of the two-fork tree with a maximum of only 2^k-1 nodes, and the definition of a complete binary tree is the same depth as the full two-tree front number is the same, that is, its sum of points n is located in the K-layer and the K-1 layer full two fork tree capacity, that is 2^(k-1)-1 < n <= 2^(k-1) - 1
2^(k-1) <= n < 2^k
, or, three k-1 <= log2n < k
since K is an integer, the depth is described in Properties 4.
Property 5: For a complete binary tree with n nodes, if all nodes in the two-ary tree are numbered sequentially from top to bottom and from left to right, then for any node with the sequence number I, there are:
(1) If i>1, the sequence number of the nodes of the node is I/2; if i=1, then the node with the ordinal i is the root node, with no parental nodes.
(2) If 2i<=n, the sequence number of the node of I is the number of the left child node is 2i; if 2i>n, then the node with the ordinal I is no left child.
(3) If 2i+1 <= N, then the right child node of the node with the ordinal number is 2i+1; if 2i+1>n, then the node with the ordinal I is no right child.
In addition, if the root node of the two-fork tree is numbered starting from 0, the parent node of the corresponding I-node is numbered (i-1)/2, the left child is numbered 2i+1, and the right child is numbered 2i+2.
Questions about binary tree examples
Example 1: There are 1001 nodes in a complete binary tree, and what is the number of leaf nodes?
Example 2: If the root hierarchy is 1, what is the height of the full binary tree with 61 nodes?
Example 3: In a tree with 100 nodes, what is the number of edges?
Analytical
Example 1: Two fork tree formula: n = n0 + n1 + N2 = n0+n1+ (n0-1) = 2*n0 + n1-1. In a fully binary tree, N1 can only take 0 or 1. If N1 = 1, then 2*n0 = 1001, can be introduced n0 as a decimal, does not conform to test instructions; if N1 = 0, then 2*n0-1 = 1001, then N0 = 501. So the answer is 501.
Example 2: If the root hierarchy is 1, what is the height of the full binary tree with 61 nodes?
Depending on the nature of the binary tree, the full binary tree with n nodes has a depth of log2n + 1 (log with 2 logarithm of the base n), so the height of the full binary tree with 61 nodes is log2n + 1 (log is the logarithm of the base N of 2), which should be 6 layers. So the answer is 6.
Example 3: In a tree with 100 nodes, what is the number of edges?
In a tree, each node has one edge in addition to the root nodes, so the total number of edges should be 100-1, or 99. So the answer is 99.
Recursive implementation of two-fork tree traversal
The idea of the binary tree's first order traversal is to start from the root node, go straight along the Zuozi until there is no left child's node, and then visit the node that passes through, and then the address of the node goes into the stack, and when the node of the left child is found, the right child from the top of the stack exits the node. At this point, the left subtree of this node has been accessed, and the above method is used to traverse the right subtree of the node, so as to repeat until the stack is empty.
The idea of sequential traversal in binary tree is to start from the root node, go straight along the Zuozi until there is no left child's node, and put the address of the crossing node into the stack, and when found no left child's node, exit the node from the top of the stack and access it. At this point, the left subtree of this node has been accessed, and the above method is used to traverse the right subtree of the node, so as to repeat until the stack is empty.
The idea of a binary tree's post-order traversal begins with the root node, along the Zuozi until there is no left child's node, and the address of the junction of the first time into the stack, when found no left child's node, the node's left subtree has been visited, from the top of the stack to exit the node, to determine whether the node is the first time the stack. If it is, then the address of the node is then the second time into the stack, and along the right subtree of the node until there is no right child's node, if not, then access the node. At this point, the left and right subtrees of the node are fully traversed and the pointer p=null, so repeat until the stack is empty.
How to find the sequential traversal and the sequence traversal
The general data structure has the traversal operation, according to the demand, the binary tree generally has the following kinds of traversal methods: First order traversal, middle sequence traversal, sequential traversal and sequence traversal
(1) First Order traversal: If the binary tree is empty, the traversal ends. Otherwise, the first step is to access the root node; the second step is to traverse the left sub-tree of the root node, and the third step is to traverse the right subtree of the root node in the first order.
(2) Middle sequence traversal: If the binary tree is empty, the traversal ends. Otherwise, in the first step, the middle sequence traverses the left subtree of the root node; the second step is to access the root node; the third step, the middle sequence traverses the right subtree of the root node.
(3) Post-order traversal: If the binary tree is empty, the traversal ends. Otherwise, the first step is to traverse the left subtree of the root node, and the second step is to follow through the right subtree of the root node; Third step, access the root node.
(4) Hierarchical traversal: Starting from the first layer of the two-fork tree (root node), traversing from top to bottom, and in the same layer, the nodes are accessed from left to right sequentially.
The various traversal results in Figure 13-15 are as follows:
First Order traversal abdhiejcfg
Middle Sequence Traversal HDIBJEAFCG
Post-Traversal HIDJEBFGCA
Hierarchical Traversal ABCDEFGHIJ
For example, the preface is listed as ABDECF, and the sequence is listed as DBEAFC. Order sequence.
First, the rule of the first sequence traversal tree is around the root, you can see the first sequence traversal sequence of elements must be the root node of the tree, then a is the root node. Then the order traversal is Zogen right, then according to the root node A, the left subtree contains the element is DBE, the right subtree contains the element as FC. Then the recursive solution is Zuozi (the first order of the left subtree is BDE, the middle order is DBE), and the right subtree is solved recursively (i.e. the first order of the right subtree is CF and the middle order is FC). So recursion until there are no left and right subtrees. So, the tree structure is shown in 13-16.
In the above example, we can summarize the process of solving the binary tree with the first order traversal and the middle order traversal, the steps are as follows:
(1) Determine the root node of the tree. The root is the first element in the sequence traversal of all elements in the current tree, that is, the first node of the first order traversal is the root of a binary tree.
(2) The subtree of the solution tree. Find the root in the middle sequence traversal position, the location to the left is two tree left child, position right is two fork tree right child, joghen node left or right is empty, then the direction subtree is empty, if the root node left and right are empty, then the root node is a leaf node.
(3) The left and right children of the two-fork tree are respectively step (1) (2) until the two-tree structure is calculated.
Extended, known sequence traversal and post-order traversal, first order traversal
The first step is to determine the heel of the tree, which is the last element in the current tree that all elements appear in the post-routing traversal.
The second step is to solve the subtree of the tree, find the root node in the middle sequence traversal of the position, all the elements on the left side of the root is the left dial hand tree, the root right of all elements is the right subtree, if the root node left or right is empty, then the direction subtree is empty, if the root node left and right are empty, the root
The third step is the recursive solution tree, and the Saozi right subtree is considered as a binary tree respectively. Repeat the above steps until all nodes are positioned. The process is similar to the process of solving a tree based on the first order sequence and the middle sequence sequence, slightly different.
It is important to note that the binary tree cannot be built if it knows the sequence of first order and sequential traversal. For example, the first sequence is listed as ABDECF, the order sequence is DEBFCA, at this time only the root node can be determined, but the composition of the left and right subtree is uncertain.
The sequential traversal of two-fork tree by non-recursive implementation
The sequential traversal can be implemented recursively, and the recursive call in the program is the information of the stored function in the stack. In general, can solve problems with recursion can be solved by the stack, knowledge recursion more in line with people's way of thinking, the code is relatively simpler, but it can not be explained that recursion is faster and more space than the stack, because in the recursive process is the operating system to facilitate the implementation of storage information stack. The following is a stack to achieve a two-fork tree post-order traversal.
The idea of the stack is "advanced and out", that is, the root node into the stack (then there is an element in the stack), the root node out of the stack when the right left child into the stack (then there are two elements in the stack, note is "Advanced right backward Left", not "advanced left backward Right"), and then the stack top out of the stack (that is, left child) Then the right left child of the top element of the stack into the stack, the process has been executed until the stack is empty, the stack of elements in order is the binary tree of the first order traversal.
Using the stack to solve the two-fork tree's post-order traversal is the final output Father node, the first sequence traversal is in the node when the stack into the right left child. Obviously, for the post-order traversal, should not be in the Father node out of the stack, the right left child into the stack, should be in the stack when the right left child one into the stack. When the Father node is out of the stack, it should be judged whether the right-left child has traversed (whether or not to execute the stack), then it should be a token to determine whether or not traversed.
The structure of a binary tree is borrowed to define a new structure for this algorithm.
typedefstruct stackTreeNode{ BTree treeNode; int flag;} *pSTree;
Structure, flag is the flag, 0 means that the child does not traverse 2 to indicate that the child is traversed, the specific implementation code is as follows:
intLastorder (BTree root) { Stack< pstree >Stacktree; Pstree Stree = (pstree)malloc(sizeof(structStacktreenode)); Stree->treenode = root; Stree->flag =0; Stacktree.push (Stree); while(!stacktree.empty ()) {Pstree Tmptree = Stacktree.top ();if(Tmptree->flag = =2) {cout<< Tmptree->treenode->data <<" "; Stacktree.pop (); }Else{if(Tmptree->treenode->rchild) {Pstree Stree = (pstree)malloc(sizeof(structStacktreenode)); Stree->treenode = tmptree->treenode->rchild; Stree->flag =0; Stacktree.push (Stree); } tmptree->flag++;if(Tmptree->treenode->lchild) {Pstree Stree = (pstree)malloc(sizeof(structStacktreenode)); Stree->treenode = tmptree->treenode->lchild; Stree->flag =0; Stacktree.push (Stree); } tmptree->flag++; } }return 1;}
How to use non-recursive method to realize the first order traversal and the middle sequence traversal of two-fork tree
The method of converting the first-order traversal recursive algorithm of two-fork tree into a non-recursive algorithm is as follows:
(1) The root node of the two-fork tree is the current one.
(2) If the current node is not empty, then first access the node, and the node into the stack, and then the left child node as the current node, repeat steps (2), until the current node is empty.
(3) If the stack is not empty, then the stack top node out of the stack, and the current node of the right child node as the current node
(4) Repeat step (2) (3) until the stack is empty and the current node is empty.
The method of converting the middle order traversal recursive algorithm into a non-recursive algorithm is as follows:
(1) The root node of the two-fork tree as the current node.
(2) If the current node is not empty, then the node enters the stack and takes its left child node as the current node, repeating steps (2) until the current node is empty.
(3) If the stack is not empty, the top node of the stack is out of the stack and as the current node, then access the current node, and then the right child node of the current node as the current node.
(4) Repeat Steps (2) (3) until the stack is empty and is currently empty.
Using non-recursive algorithm to find the depth of binary tree
Calculate the depth of the binary tree, is generally used after the post-traversal, using recursive algorithm, first calculate the depth of the Zuozi, and then calculate the depth of the right subtree, and finally take the larger one plus 1 is the depth of the two-fork tree
typedef struct node{char data; struct Node *lchild; struct Node *rchild; struct Node *parent;} Bnode,*btree; //the depth recursive algorithm of the second-order traverse to find the binary tree int Posttreedepth (BTree root) {int left,right, max ; if (Root!=null) {left = posttreedepth (Root->lchild); right = Posttreedepth (Root->rchild); max = left > right? Left:right; return (max +1 ); } else return 0;}
It is very cumbersome and complex to change the algorithm directly into non-recursive form. Considering the relationship between the depth of the two fork tree and the depth, the following two kinds of non-recursive algorithms can be used to solve the binary tree depth.
Method One: First the algorithm is changed to the first order traversal and then rewrite the non-recursive form. First Order traversal algorithm: Before traversing a node, calculate the current node in which layer, the maximum number of layers is equal to the depth of two fork tree.
intGetmax (intAintb) {returnA>B?A:B;}intGettreetreeheightpreorder (ConstBTree root) {structInfo {ConstBTree TreeNode;intLevel } deque<Info>dq//Double-ended queue, you can insert and delete elements at both ends intLevel =-1;intTreeheight =-1; while(1) { while(Root) {++level;if(Root->rchild) {Info info = {root->rchild, level}; Dq.push_back (info);//Tail insert a data}//End Ifroot = root->lchild; }//while (Root)Treeheight = Getmax (treeheight, level);if(Dq.empty ()) Break;ConstInfo&info = Dq.back ();//Returns the last dataroot = info. TreeNode; level = Info.level; Dq.pop_back ();//Delete last data}returnTreeheight;}
Method Two: Modify the iterative algorithm mentioned above. In the example above, the maximum size used for the secondary stack (or the double-ended queue) minus 1 is equal to the depth of the two-fork tree. Thus, it is only necessary to record the maximum stack size of the secondary stack after placing the element into the secondary stack (or when accessing the node data)
intGettreeheightpostorder (ConstBTree root) { deque<const btree>dq//double-ended queue intTreeheight =-1; while(1) {//Pre-order the left subtree into the stack for(; root!=null; root=root->lchild) dq.push_back (root);//dq.size () the size of the secondary stackTreeheight = Getmax (Treeheight, (int) Dq.size ()-1); while(1) {if(Dq.empty ())returnTreeheight;ConstBTree parrent = Dq.back ();ConstBTree rchild = parrent->rchild;if(rchild&& root!=rchild) {root = Rchild; Break; } root = Parrent; Dq.pop_back (); } }returnTreeheight;}
Hoffman codec
Huffman coding uses a technique called prefix coding, which means that the encoding of any data is not a prefix for another data encoding. The optimal binary tree, i.e. Hoffman (two-tree with the smallest length of the weighted path), is a way to realize Huffman coding. The Huffman coding process is the process of constructing the Huffman tree, and the corresponding algorithm for constructing the Huffman tree is as follows:
(1) There is a set of letters that need to be encoded with weights, such as a (4) B (8) C (1) d (2) e (11). The weights corresponding to each letter in parentheses are respectively.
(2) Select two C (1) d (2) with a lower weight in the letter to form a new binary tree, the weight of the parent node is the sum of the two letter weights, recorded as F (3), and then added to the original letter sequence (does not contain the selected weight of the smallest two letters), the remaining letter is a (4) B (8) E ( One) F (3)
(3) Repeat steps (2) until all letters are added to the two fork tree. (encoding is usually left 0, right 1)
The decoding process of Huffman Tree is opposite to the coding process, triggering from the root node, reading the encoded content one by one, and if encountering 0, the root node of the left subtree, or the root node of the right subtree, once the leaf node is reached, the code will be translated into many corresponding characters. It then resumes decoding from the root node until the binary code ends.
Data structure and algorithm: two fork Tree