[Elementary] Chained Binary Tree

        It is meaningless to add, delete, modify and check ordinary binary trees. If it is to store data, it is better to use sequential tables and linked lists. Learning the primary operations of binary trees is to lay the foundation for learning more complex binary trees later (searching binary trees, AVL trees, red-black trees, B-trees...).

        Most of the methods used here are recursive, divide and conquer, and non-recursive methods, but they are more difficult.


First, the traversal of the binary tree

PS: The '#' sign is used here to indicate empty.

Preorder traversal : root left subtree right subtree

void BinaryTreePrevOrder(BTNode* root)
{
    if (root == NULL) {
        printf("# ");
        return;
    }
       
    printf("%c ",root->_data);
    BinaryTreePrevOrder(root->_left);
    BinaryTreePrevOrder(root->_right);
    return;
}

 

 

Inorder traversal : left subtree root right subtree

void BinaryTreeInOrder(BTNode* root)
{
    if (root == NULL) {
        printf("# ");
        return;
    }
    BinaryTreeInOrder(root->_left);
    printf("%c ", root->_data);
    BinaryTreeInOrder(root->_right);

    return;
}

 

 

 

Post-order traversal : left subtree right subtree root


void BinaryTreePostOrder(BTNode* root)
{
    if (root == NULL) {
        printf("# ");
        return;
    }
    BinaryTreePostOrder(root->_left);
    BinaryTreePostOrder(root->_right);
    printf("%c ",root->_data);

    return;
}

 

 

Second, the creation of chained binary tree

typedef char BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

Q:  Here is known the preorder traversal result of the binary tree "ABD##E#H##CF##G##", please build a binary tree.
 

BTNode* BinaryTreeCreate(BTDataType* a,int* pi)
{
     //不能在 if 里面++,不然每判断一次都要加一次。
    if (a[*pi]=='#') {
        (*pi)++;
        return NULL;
    }

    BinaryTreeNode* root = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));

    root->_data = a[(*pi)++];

    root->_left = BinaryTreeCreate(a,pi);

    root->_right = BinaryTreeCreate(a,pi);

    return root;
}

test: 

        Check it out using preorder traversal.

PS: Here, the variable i needs to pass in the address to pass the parameter. If only the variable is passed in, it is just equivalent to a copy of the variable. When passed from the parent node to the left and right nodes, the value of i is equal. It will cause two data to be assigned under the same subscript, resulting in an error. So to pass in the address, let the value of i change once

 

3. Primary operation of binary tree

1. Find the number of binary tree nodes

int BinaryTreeSize(BTNode* root)
{
    return root == NULL ? 0 : BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;
}

 

2. Find the number of leaf nodes in the binary tree

int BinaryTreeLeafSize(BTNode* root)
{
    if (root==NULL) {
        return 0;
    }

    if (root->_left == NULL && root->_right == NULL) {
        return 1;
    }

    return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}

3. Find the depth of the binary tree

 

int Depth(struct TreeNode* root){
    if(root==NULL)
        return 0;

    int left = Depth(root->left);
    int right = Depth(root->right);

    return left > right ?left+1 :right+1;
}

 

4. Find the number of nodes in the kth layer of the binary tree

int BinaryTreeLevelKSize(BTNode* root, int k)
{
    assert(k >= 1);
    if (root == NULL)
        return 0;
    
    if (k == 1)
        return 1;

    return BinaryTreeLevelKSize(root->_left,k-1)+ BinaryTreeLevelKSize(root->_right,k-1);
}

        To find the number of nodes in the K layer, after entering the left and right subtrees, it is to find the number of nodes in the K-1 layer, and K==1 means that it has reached the specified number of layers.

 

5. Binary tree finds the node whose value is x

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if (root == NULL)
        return NULL;
    //使用前序最好,避免第一个节点就是要找的节点
    if (root->_data == x)
        return root;

    BTNode* ret1 = BinaryTreeFind(root->_left, x);
    if (ret1)
        return ret1;

    BTNode* ret2 = BinaryTreeFind(root->_right, x);
    if (ret2)
        return ret2;

    return NULL;
}

        When it is time to return to the node, use a variable to accept it, because there is another judgment here, if it is not empty, it must be returned to the previous node. If you use the following writing method, it will recurse again when returning, which is a waste of efficiency.

 //浪费效率
 if (BinaryTreeFind(root->_left, x))
     return BinaryTreeFind(root->_left, x);

6. Destruction of the binary tree

void BinaryTreeDestory(BTNode* root)
{
    if (root==NULL)
    {
        return;
    }

    BinaryTreeDestory(root->_left);
    BinaryTreeDestory(root->_right);
    free(root);
}

         To release nodes, use post-order traversal, because the nodes to be released are needed to find the following nodes, and the nodes to be released must be released from the last node.

7. Layer order traversal

        Layer-order traversal means that one layer is traversed, and after the first layer is traversed, the second layer is traversed.

        This is achieved by using the data structure of the previous queue.

        The idea is to put the root node of the binary tree into the queue, and then visit the head of the queue to bring its child nodes into the queue.

        At this time, A goes out of the queue, B becomes the head of the queue, and then B's child nodes are brought into the queue.        

        At this time, B goes out of the queue, C becomes the head of the queue, and then brings C's child nodes into the queue.

 

        At this time, C goes out of the queue, D becomes the head of the queue, and then the child nodes of D are brought into the queue. (Here, the child node of D is empty) Follow this method to the end in turn.

        It will be found that the order of the queue is the level order traversal of the binary tree.

code:

PS: Because it needs to bring in the child nodes of the node, it needs to store the nodes of the binary tree in the queue.

//存二叉树的节点数据
typedef struct BinaryTreeNode* Qdatatype;

struct QueNode
{
	Qdatatype data;
	struct QueNode* next;
};
void BinaryTreeLevelOrder(BTNode* root)
{

    Queue q;
    QueueInit(&q);
    if (QueueIsEmpty(&q)) {
        QueuePush(&q,root);
    }

    while (!QueueIsEmpty(&q)) {
        BTNode* front = QueueTop(&q);
        QueuePop(&q);

        printf("%c ", front->_data);

        if (front->_left) {
            QueuePush(&q, front->_left);
        }

        if(front->_right){
            QueuePush(&q, front->_right);
        }
        
    }
    QueueDestroy(&q);
}

test:

 

8. Determine whether a binary tree is a complete binary tree

        Here we need to use the previous idea of ​​layer order traversal to judge, here we need to enqueue the empty nodes together, and then judge whether the empty nodes are continuous, if all are empty nodes, then it is a complete binary tree, if there are nodes in the middle, then it is not complete binary tree.

        

bool BinaryTreeComplete(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if (QueueIsEmpty(&q)) {
        QueuePush(&q, root);
    }

    while (!QueueIsEmpty(&q)) {
        BTNode* front = QueueTop(&q);
        QueuePop(&q);
        //这里遇到空指针,那么说明到最后一层了,节点都被带到队列中去了
        if (front) {
            QueuePush(&q, front->_left);
            QueuePush(&q, front->_right);
        }
        else {
            break;
        }
    }

    while (!QueueIsEmpty(&q))
    {
        BTNode* front = QueueTop(&q);
        QueuePop(&q);

        if (front) {
            QueueDestroy(&q); //注意这里退出的时候要释放内存。
            return false;
        }
        
    }

    QueueDestroy(&q);
    return true;
}

test:

 

4. Elementary OJ questions

1. Determine whether it is a single-valued binary tree

A binary tree is a single- valued binary tree         if every node of the tree has the same value . Returns only if the given tree is a single-valued binary tree  true; otherwise  false.

 

        Take a benchmark value to judge whether they are equal. If each node is equal, then it is a single-valued binary tree. Otherwise not.

code: 

bool flag=true;

bool isSameNode(struct TreeNode* root,int val){
    if(root==NULL)
        return true;

    if(root->val!=val)
        flag=false;

    isSameNode(root->left,val);
    isSameNode(root->right,val);
    return true;
}

bool isUnivalTree(struct TreeNode* root){
    if(root==NULL)
        return true;

    flag=true;
    isSameNode(root,root->val);
    return flag;
}

 

2. Check if the two trees are the same

Given the sum of the roots of two binary trees  p ,  q write a function to check whether the two trees are the same.

Two trees are considered identical if they are structurally identical and the nodes have the same value.

        First of all, it is necessary to determine whether the number of nodes is the same. If they are the same, the values ​​of the cut nodes are all equal, then the two trees are the same.

 code: 

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    
    if(p==NULL && q==NULL)
        return true;

    if(p==NULL || q==NULL)
        return false;
    
    if(p->val!=q->val)
        return false;

    return isSameTree(p->left,q->left) && 
           isSameTree(p->right,q->right);
}

 

3. Judging that another tree is its own subtree

        You are given two binary trees root and subRoot. Tests that root contains a subtree with the same structure and node values ​​as subRoot. Returns true if present; otherwise, returns false.

        Decompose the problem into whether the left and right subtrees are the same as another tree. If there is a subtree that is equal, it means that it is its own subtree. Then each node has to be judged, and two recursions are used, one is to judge the same judgment, and the other is to traverse the nodes.

 code:

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    
    if(p==NULL && q==NULL)
        return true;

    if(p==NULL || q==NULL)
        return false;
    
    if(p->val!=q->val)
        return false;

    return isSameTree(p->left,q->left) && 
           isSameTree(p->right,q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(root==NULL)
        return false;

    if(isSameTree(root,subRoot))
        return true;

    return isSubtree(root->left,subRoot)||
           isSubtree(root->right,subRoot);
}

 

4. Determine whether it is a symmetric binary tree

Given the root of a binary tree  root , check if it is axisymmetric. 

        It is enough to decompose and judge whether the subtrees are equal, but it should be noted that the direction of judgment is not a single direction for judgment.

 

code:

bool isSameTree(struct TreeNode* q,struct TreeNode* p)
{
     if(p==NULL && q==NULL)
        return true;

    if(p==NULL || q==NULL)
        return false;
    
    if(p->val!=q->val)
        return false;

    return isSameSubTree(q->left,p->right)&&
           isSameSubTree(q->right,p->left);

}

bool isSymmetric(struct TreeNode* root){
    if(root==NULL)
        return true;

    return isSameSubTree(root->left,root->right);
}


Summarize:

        You will find that using the recursive method, the code is actually relatively simple, but the idea must be clear, and the main idea is to divide and conquer.

Guess you like

Origin blog.csdn.net/weixin_45423515/article/details/125029875