6.2 Two fork tree before further discussing the storage structure of the tree and its operation, a simple and extremely important tree structure-two fork tree is discussed. because any tree can be transformed into a two-fork tree for processing, and the binary tree is suitable for computer storage and processing, the binary tree is the focus of research in this chapter. 6.2. Definition of 12-fork Tree Each node has an ordered tree of no more than 2 degrees, called a binary tree . similar to the recursive definition of a tree, the recursive definition of a binary tree is as follows: two a tree or an empty tree, or a tree that is disjoint by a root node and two trees .a non-empty tree consisting of a subtree of the Saozi right subtree, respectively called the root. As can be seen from the above definition, the number of children in each node in a two-fork tree can only be 0, 1, or 2 , and each child has a left and right score. The child on the left is called the left child, and the child on the right is called the right child; a subtree with the left child as the root is called the left dial hand tree, and a subtree with the right child as its root is called the right child tree. similar to the basic operation of a tree, a binary tree has the following basic operations:
The nature of 6.2.2 two fork tree in the binary tree has the following important properties. This nature is easily proved by mathematical inductive method. Proof slightly. By the nature of 6.2 can be obtained the following further conclusions:
The following describes two special two-fork trees, and then discusses their related properties. you can number the nodes full of two forks, the contract number from the root node, the layer from top to bottom, the layer from left to right, layer by level from 1 to n label.
if the nodes in a complete binary tree with N nodes are numbered according to the above two-tree node numbering method, then the position of the 1~ n node in the complete binary tree is consistent with the position of the 1~ n node in the full two-fork tree. Figure 6-2 (b) shows a two-fork tree that is a fully binary tree. visible, full two fork tree must be a complete binary tree, while a complete binary tree is not necessarily full of two fork tree.
6.2. Storage structure of 32-fork TreeThere are two types of storage structures for two-tree: sequential storage structure and chained storage structure. @ Sequential Storage structurefor a full two-fork tree and a full binary tree, the data elements can be stored layer-by-row into a contiguous set of storage units, as shown in 6-3. When using a one-dimensional array to implement sequential storage structures, the nodes numbered I in the two-fork tree are stored in theThe first component in the array. So according to the nature of 6.7, you can get node I of the parent node, the left and right children nodes are stored in [2/i] , 2i and 2i+1 components respectively.
This storage method is very suitable and efficient for full two tree and full binary tree . Because the full two-tree and the complete binary tree use sequential storage structure to not waste space, but also based on the formula to quickly determine the relationship between nodes. However, for the general two-fork tree, it is necessary to use "virtual node" to fill a binary tree into a complete binary tree to store, otherwise can not determine the relationship between the predecessor of the node, but this will cause the waste of space. an extreme emotion. in order to store K nodes, it is necessary tostorage unit, Figure 6-4 illustrates this situation. This is a huge waste of storage space, which is a disadvantage of the sequential storage structure.
@ Chained storage structurethe design of different node structures can form different chain storage structures. Each node in the binary tree has two children, you can design each node to include at least 3 domains: The data field, the left child domain, and the right child domain. The data field holds the data element, the left child field holds a pointer to the left child's node, and the right child's field holds a pointer to the right child's node. As shown in 6-5 (a). The two-fork tree storage structure obtained by using this node structure is called a binary list. Easily proven in two with n nodesThere are n+1 empty links in the fork list.
to make it easier to find the parent node, you can add a pointer field to the node's parent node in the above node structure. As shown in 6-5 (b). The two-tree storage structure obtained by this node structure is called the three-fork linked list . There are also n+1 empty links in a triple-linked list with n nodes. different storage architectures have different methods for implementing two-tree operations. For example, to find a node of the parent node, in the three-linked list is easy to implement, in the binary list is required from the root node one by one to find. In the actual application, the storage structure should be selected according to the main operation of the binary tree. In order to find the parent node conveniently, we use the triple linked list as the storage structure of the binary tree, and in section 6.3, the implementation of the basic operation of the binary tree is also based on the three-fork linked list. Here we first give the definition of a node structure with four domains. code 6-1 two fork tree storage structure node definition
Public classBintreenodeImplementsNode {PrivateObject data;//data fieldsPrivateBintreenode parent;//parent NodePrivateBintreenode Lchild;//left childPrivateBintreenode Rchild;//Right ChildPrivate intHeight//The height of the subtree at which the node is rootedPrivate intSize//the number of descendants of the node (including the node itself) .102 PublicBintreenode () { This(NULL); } PublicBintreenode (Object e) {data= e; Height = 0; Size = 1;p arent= Lchild = Rchild =NULL;}/******node Interface Method * * * **/ PublicObject GetData () {returndata;} Public voidSetData (Object obj) {data =obj;}/*** * * * Auxiliary method, determine the current node location SITUATION * * * **///judge If there is a Father Public BooleanHasparent () {returnparent!=NULL;}//Judging if there are left children Public BooleanHaslchild () {returnlchild!=NULL;}//determine if there is a right child Public BooleanHasrchild () {returnrchild!=NULL;}//determine if it is a leaf node. Public BooleanIsLeaf () {return!haslchild () &&!hasrchild ();}//determine if the left child is a node Public BooleanIslchild () {return(Hasparent () && This==parent.lchild);}//determine if the right child is a node. Public BooleanIsrchild () {return(Hasparent () && This==parent.rchild);}/*** * * * methods related to Height * * * **///The height of the node to be taken, i.e. the height of the tree with the node as its root Public intGetHeight () {returnheight;}//Update the height of the current node and its ancestors Public voidupdateheight () {intNEWH = 0;//The new height is initialized to 0, the height is equal to the height of the left and right subtree and the larger of 1if(Haslchild ()) NEWH = Math.max (newh,1+getlchild (). GetHeight ());if(Hasrchild ()) NEWH = Math.max (newh,1+getrchild (). GetHeight ());if(Newh==height)return;//the height does not change and returns directlyHeight = NEWH;//Otherwise, update the heightif(Hasparent ()) getParent (). Updateheight ();//recursively update ancestors ' heights}/*** * * * methods related to Size * * * * **///The node number of the tree to which the node is rooted Public intGetSize () {returnsize;}//Update the current node and descendants of its ancestors Public voidupdatesize () {size= 1;//initialized to 1, the node itselfif(Haslchild ()) Size + = Getlchild (). GetSize ();//plus the left subtree size103if(Hasrchild ()) Size + = Getrchild (). GetSize ();//plus right subtree sizeif(Hasparent ()) getParent (). Updatesize ();//recursively update the size of ancestors}/*** * * * methods related to Parent * * * * **///take the parent node. PublicBintreenode getParent () {returnparent;}//disconnection from the relationship with the Father Public voidSever () {if(!hasparent ())return;if(Islchild ()) Parent.lchild =NULL;ElseParent.rchild =NULL;p arent.updateheight ();//Update parent node and its ancestor heightParent.updatesize ();//Update parent node and its ancestor sizeParent =NULL;}/*** * * * methods related to Lchild * * * * **///take the left child PublicBintreenode Getlchild () {returnlchild;}//set the current node to the left child and return to the original left child PublicBintreenode Setlchild (bintreenode LC) {Bintreenode OLDLC= This. lchild;if(Haslchild ()) {Lchild.sever ();}//Disconnect the current left child from the nodeif(lc!=NULL) {lc.sever ();//disconnecting the LC from its parent node This. lchild = LC;//Determine parent-child relationshipsLc.parent = This; This. Updateheight ();//Update the current node and its ancestor height This. Updatesize ();//Update the current node and its ancestor size}returnOLDLC;//back to the original left child}/*** * * * methods related to Rchild * * * * **///Take right child PublicBintreenode Getrchild () {returnrchild;}//set the right child of the current node and return to the original right child Publicbintreenode setrchild (Bintreenode rc) {bintreenode OLDRC= This. rchild;if(Hasrchild ()) {Rchild.sever ();}//Disconnect the current right child from the nodeif(rc!=NULL) {rc.sever ();//disconnecting the LC from its parent node This. rchild = RC;//Determine parent-child relationships104rc.parent= This; This. Updateheight ();//Update the current node and its ancestor height This. Updatesize ();//Update the current node and its ancestor size}returnOLDRC;//back to the original right child}}
Code 6-1 Description: In the code to determine the current node location of the auxiliary method and the simple get method can be completed in constant time, the implementation is very simple. The following focuses on the implementation and time complexity of updateheight (), Updatesize (), Sever (), Setlchild (LC), Getrchild (RC). ⑴updateheight (): If the child of the current node v changes, you need to use the Updateheight () method to update the height of the current node and its ancestor nodes. Note that because the height of a node changes, it affects the height of its ancestor nodes, where we allow this to be done directly on any node. because the height of any node in a binary tree is equal to the height of its left and right subtree, plus 1, and the height of the left-to-right subtree only needs to be obtained at the height of the child, and only θ (1) time is required. Continue and move from V to the parent reference retrograde upward, updating the height of each ancestor node in turn. If, in the above process, the height of a node is not changed, the algorithm can be terminated directly. In summary, when a node V is called Updateheight ()method, if the layer of V is level (v), it is necessary to update only the height of the level (v) +1 nodes, so the time complexity of the algorithm T (n) =0 (degree (v)). ⑵updatesize (): Also if the child of node v changes, the current node should be updated and the size of its ancestors. Because the scale of any node in the binary tree is equal to the size of its left and right sub-tree and the node itself, and the size of the subtree only need to get the node around the size of the child can be obtained, only the θ (1) time. Thus the algorithm's time complexity T (n) =0 (level (v)). ⑶sever (): Cut off the relationship between node V and parent node p. The algorithm needs to modify the pointer field of V and P, which requires constant time. In addition, due to the change in the children of P-node, it is necessary to call Updateheight () and Updatesize () to update the height and scale of parent node p and its ancestors. Its time complexity T (n) =0 (level (v)). ⑷setlchild (LC), Getrchild (RC): Two the function of the algorithm, one is to set the node V of the left child, one is set node V of the right child. The implementation of the two algorithms is similar, as illustrated by the example of Setlchild (). First, if V has a left child oldlc, you should call OLDLC. Sever () disconnects v from its left child. Second, the LC is called. Sever () disconnects its relationship to the parent node. Finally, establish a parent-child relationship between V and LC and Invoke V. updatesize () and V.updateheight () to update the size and height of V and its ancestors.
Data structures and algorithms (Zhou Peng-unpublished)-sixth chapter tree-6.2 Two fork Tree