[PHP data structure] complete binary tree, clue binary tree and sequential storage structure of tree

Time:2021-10-13

In the last article, we learned the basic chain structure of binary tree and the operations related to tree building and traversal. Today we are learning some concepts related to binary trees and a variant of binary trees.

Complete binary tree

What is a complete binary tree? Before we talk about the complete binary tree, let’s say another noun: “full binary tree”. Like the binary tree demonstrated in our previous article, it is a “full binary tree”. In this tree, all nodes have two child nodes. No node has only one child node, and all the bottom leaf nodes are on the same layer. This tree is called “full binary tree”, also known as “perfect binary tree”.

https://imgs.developpaper.com/imgs/1575433-20210727090046185-816323350.png

Is it a very beautiful tree? Yes, this binary tree is very perfect. It has neither redundant nodes nor missing nodes. It is very beautiful. However, in reality, perfect things are rare, and there will always be some regrets in life. We try not to let ourselves have too many defects, but we can’t live a life without any defects. Therefore, we allow leaf nodes to appear in the lowest and lower levels, and the leaf nodes at the lowest level are concentrated on the left of the tree, that is, leaf nodes can only have left subtrees. Then, such a tree with slight defects is called “complete binary tree”. Don’t worry about its imperfection, because such a slightly flawed life is complete, so “complete binary tree” is an ideal tree structure.

https://imgs.developpaper.com/imgs/1575433-20210727090047577-768489450.png

From the definition, we can see that a “full binary tree” must be a “complete binary tree”, and a “complete binary tree” in which a leaf node is on the first floor and all nodes have left and right child nodes is also a “full binary tree”.

Why do we talk about “full binary tree” and “complete binary tree”? Of course, it is to pave the way for our next content. Because “full binary tree” is a tree that most conforms to the nature of binary tree. Remember the five characteristics of binary tree introduced in the first article of tree series? We used the “full binary tree” at that time “As an example, and property 5 is the basis for us to learn to use sequential structure to store binary trees.

Sequential storage of binary tree

Through the concept of “full binary tree” and the properties of binary tree, 5 we can realize the implementation of using an array to store sequential structure.

$treeList = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'];

I believe you are no stranger. In the last article, we built the chain tree through this array, and this array is actually a binary tree with linear storage. Let’s see by comparing the properties 5 of binary trees.

  • The subscript of node a is 1, which is our tree root. Its child nodes are B and C, and the corresponding subscripts are 2 and 3 respectively, that is, 1 * 2 and 1 * 2 + 1.

  • Similarly, we select another node F. Its subscript is 6, so the subscript of its left child node is 6 * 2 = 12, corresponding to L; Its right child node is 6 * 2 + 1 = 13, corresponding to M.

  • Conversely, the parent node of a node is I / 2. Let’s see that the subscript of node K is 11, and its parent node is 11 / 2. Rounding off the decimal point is the position of subscript 5, that is, node E; The subscript of node j is 10, its parent node is 10 / 2, and it is also node e with subscript 5.

Now you can see how to represent a binary tree structure with an array. Moreover, the structure of array is more one-dimensional, which can better reflect that the operation of tree is a representation of two-dimensional one-dimensional, that is, nonlinear to linear, so that we can easily operate these data.

For the sequential storage structure, that is, the traversal of array elements, the forms of first order, middle order, second order and sequence can also be used. However, these traversal methods need to traverse according to the nature 5 of binary tree. But more importantly, as long as we give me a subscript, we can easily know the location of its subordinate nodes and superior nodes through the nature of binary tree, and can quickly obtain the information of these nodes. This feature is not found in binary trees with chain structure.

What if we do not store a “full binary tree”? Even if it is not a complete binary tree, we only need to set the corresponding node to null value. For example:

$treeList = ['', 'A', 'B', 'C', 'D', 'E', 'I', '', '', '', '', 'H', '', 'J', '', ''];

The binary tree graph corresponding to the structure of this tree is as follows:

https://imgs.developpaper.com/imgs/1575433-20210727090047577-768489450.png

Then, in the method of building chain tree, we only need to add another judgment. We can quickly generate a chain stored binary tree through such a sequential stored binary tree, which is convenient for our subsequent operation.

//Establish binary tree
function CreateBiTree($arr, $i)
{
    If (! Isset ($arr [$I]) |! $arr [$I]) {// a judgment is added here if the array element is empty
        return null;
    }
    $t = new TBTNode();
    $t->data = $arr[$i];
    $t->lChild = CreateBiTree($arr, $i * 2);
    $t->rChild = CreateBiTree($arr, $i * 2 + 1);
    return $t;
}

Clue binary tree

Next, let’s talk about “clue binary tree”. What’s this?

From the above learning, we know “full binary tree” and “complete binary tree”. However, this structure is a very ideal tree structure, but most of the real situation may be “ideal is full, reality is bony”. Many trees can not form such a complete binary tree, let alone “full binary tree” “Yes. The traversal of trees often uses stacks or queues. These two traversal methods are basically linear, which is the time complexity of O (n) at best. So, is there a faster way to improve the efficiency of traversal?

Let’s try this:

  • If the left child node of the leaf node of the tree is empty, let it point to the predecessor (superior) node

  • If the right child node of the leaf node of the tree is empty, let it point to the successor node

What are the benefits? We can avoid large-scale recursive operations, so as to speed up the traversal of the tree. In the whole algorithm, it has no advantage, because we need to cue a tree, that is, to change the direction of the left and right children of its leaf nodes, which is also a traversal. However, if your operation needs to be traversed frequently and repeatedly back and forth, its overall performance is better than that of ordinary binary tree traversal. Because after a cue, its traversal is to perform ordinary linear traversal operation on the basis of quickly finding leaf nodes, rather than recursive operation.

For clue binary tree, we need to change the node storage data structure of the tree.

//Clue binary tree node
class TBTNode
{
    public $data;
    public $lTag = 0;
    public $rTag = 0;
    public $lChild;
    public $rChild;
}

We add two flag bits. When $LTAG or $rtag is 1, $lchild or $rchild point to the predecessor or successor node respectively. In this way, during the final traversal, we can quickly distinguish the pointing state of the node through the tag flag bit.

Then we simply build a tree. Use the example in the previous section.

//Establish binary tree
function CreateBiTree($arr, $i)
{
    If (! Isset ($arr [$I]) |! $arr [$I]) {// a judgment is added here if the array element is empty
        return null;
    }
    $t = new TBTNode();
    $t->data = $arr[$i];
    $t->lChild = CreateBiTree($arr, $i * 2);
    $t->rChild = CreateBiTree($arr, $i * 2 + 1);
    return $t;
}

$treeList = ['', 'A', 'B', 'C', 'D', 'E', 'I', '', '', '', '', 'H', '', 'J', '', ''];

$tree = CreateBiTree($treeList, 1);

The next step is the most important cueing process. We can establish pre order, middle order and post order cue binary trees. Correspondingly, the results obtained during the last traversal of the clue binary tree will also be the results corresponding to the three traversal methods. Here, we learn the most common and classic “middle order clue binary tree”. Therefore, we clue the tree in the form of middle order traversal.

//Cueing
function InThread(?TBTNode $p, ?TBTNode &$pre)
{
    if ($p) {
        //Recursion, left subtree, cueing
        InThread($p->lChild, $pre);

        if (!$p->lChild) {
            //Establish the precursor clue of the current node
            $p->lChild = $pre;
            $p->lTag = 1;
        }
        if ($pre && !$pre->rChild) {
            //Create a follow-up clue for the current node
            $pre->rChild = $p;
            $pre->rTag = 1;
        }
        $pre = $p; // $ Pre points to the current $p as a pointer to the next node that $p will point to
        $p = $p->rChild; // $ P points to a new node. At this time, the nodes pointed to by $pre and $p respectively form a precursor successor pair to prepare for the next cue
        
        //Recursion, right subtree, cueing
        InThread($p, $pre);
    }
}

//Create a clue binary tree
function createInThread(TBTNode $root)
{
    $pre = null; //  Precursor node pointer
    if($root){
        InThread($root, $pre);
        $pre->rChild = null; //  Nonempty binary tree, cueing
        $pre->rTag = 1; //  Last node in post-processing sequence
    }
}

createInThread($tree);

var_dump($tree);
// object(TBTNode)#1 (5) {
//     ["data"]=>
//     string(1) "A"
//     ["lTag"]=>
//     int(0)
//     ["rTag"]=>
//     int(0)
//     ["lChild"]=>
//     object(TBTNode)#2 (5) {
//       ["data"]=>
//       string(1) "B"
//       ["lTag"]=>
//       int(0)
//       ["rTag"]=>
//       int(0)
//       ["lChild"]=>
//       object(TBTNode)#3 (5) {
//         ["data"]=>
//         string(1) "D"
//         ["lTag"]=>
//         int(1)
//         ["rTag"]=>
//         int(1)
//         ["lChild"]=>
//         NULL
//         ["rChild"]=>
//         *RECURSION*
//       }
//       ……

The specific steps of the algorithm have been written in detail in the notes. In a word, the summary is to determine the form of its left and right children according to the information of the node during the middle order traversal. If there are left and right children, continue. If there is no child, point the left and right nodes to the precursor or successor. The established clue binary tree is as shown in the figure:

https://imgs.developpaper.com/imgs/1575433-20210727090048410-1717600884.png

The last is traversal. What we need is to quickly obtain the information of the leftmost leaf node, and then the information of the next hop. At this time, the power of the clue is brought into play.

//In the middle order clue binary tree with $p as the root, the first node under the middle order sequence, that is, the leftmost node
function First(?TBTNode $p){
    while($p->lTag == 0){
        $p = $p->lChild; //  Bottom left node (not necessarily leaf node)
    }
    return $p;
}

//In a middle order binary tree, node $p is the successor node under the middle order
function NextNode(?TBTNode $p){
    if($p->rTag == 0){
        return First($p->rChild);
    }else{
        return $p->rChild; //  If rtag = = 1, the follow-up clue is returned directly
    }
}

//Middle order traversal on middle order clue binary tree
function Inorder(TBTNode $root){
    //The first node is not empty and the next node is not empty
    for($p = First($root);$p;$p=NextNode($p)){
        echo $p->data, ',';
    }
}

Inorder($tree); // D,B,E,H,A,I,J,C,

When a node with $LTAG not 0 is encountered, this node is the leftmost node. If this node is not empty, [output] it. Then we get the node of the next hop, that is, the $rtag flag of the right child of the node. If it is 0, that is, it has a right child. After [output], we look down until we find a node with $rtag also 1, and directly return the successor of this node, that is, the middle node of the middle order traversal, [output] it.

Is the order of the final output the same as the result of our sequence traversal? Pay attention to the code. When traversing the middle order clue binary tree, we don’t use a recursion. We use while() and for() to complete the traversal of the clue binary tree.

summary

It’s not easy to insist until now. Can’t underestimate the data structure? It’s just a tree now. Our pictures haven’t started yet! Of course, don’t be afraid. Learn step by step and master it slowly. Don’t fantasize about eating a fat man at one breath. After writing this article, I can’t write a middle order clue binary tree right away. We still focus on understanding the principle. If we can really write by hand, it is also memorized for the interview or prepared for the postgraduate entrance examination. In the interview, I have to ask more other questions. After all, the temporary preparation is far less impressive than the insight brought by in-depth understanding!

Test code:

https://github.com/zhangyue0503/Data-structure-and-algorithm/blob/master/4. Tree / source / 4.3 complete binary tree, clue binary tree and sequential storage structure of tree.php

reference material:

Data structure, Second Edition, Yan Weimin

Data structure, Second Edition, Chen Yue

High score notes on data structure, 2020 edition, tianqin postgraduate entrance examination

Official account: hard core project manager

Add wechat / QQ friends: [xiaoyuezigonggong / 149844827] get free PHP and project management learning materials

Tiktok, official account, voice, headline search, hard core project manager.

Station B ID: 482780532