【データ構造】二分木の古典的な演習

965.単一値の二分木

アイデア:

1.ツリーが空の場合、ルールに違反していないため、trueを返します。

2.ルートノードと左側のサブツリーの右側のサブツリーの値を比較し、等しくない場合はfalseを返します。

3.プレオーダートラバーサルは再帰的に実装できます。つまり、左側のサブツリーが右側のサブツリーと比較され、それらは等しくなければなりません。

 

bool isUnivalTree(struct TreeNode* root){
    //先序遍历
    if(root == NULL)
        return true;
        //判断==并没有多大的用处,判断相反可快速结束递归。
    if(root->left && root->val != root->left->val)//1.判断节点是否存在,2.判断值是否不相等。
        return false;
    if(root->right && root->val != root->right->val)
        return false;
    return isUnivalTree(root->left) && isUnivalTree(root->right);//左树 右树都得同时满足才可返回真

}

100.同じ木

2つのツリー間の比較は、対応するノードが存在し、等しいかどうかを確認することです。

アイデア:1。両方のツリーが空の場合、trueを返します。

2. 2つのツリーの対応するノードが欠落している場合は、falseを返します

3.再帰、事前注文トラバーサルを実行できます。

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);

}

対称二分木

2つのツリーが等しいかどうかの比較に基づいて、マイナーな変更が行われました。

ここでは、ルートノードの下のルート左サブツリーとルート右サブツリーを比較するだけで済みます。

比較には注意が必要です。これは鏡面対称であるため、左ツリーの左サブツリーと右ツリーの右サブツリーが比較されます。

左側のツリーの右側のサブツリーは、右側のサブツリーの左側のサブツリーと比較されます。

同じツリーのコードを呼び出すだけです。

 

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->right) && _isSameTree(p->right,q->left);

}

bool isSymmetric(struct TreeNode* root){
    //为空树
    if(root == NULL)
        return true;
    //调用相同树的代码
    return _isSameTree(root->left,root->right);

}

二分木のプレオーダートラバーサル

レビュー:プレオーダートラバーサル:ルート-左サブツリー-右サブツリー

要するに、それはまだ再帰的な分割統治の考えですが、この質問は少し異なります。

この質問では、データを格納するために配列スペースを申請する必要があります。静的配列の使用は、関数スタックフレームのために関数がスコープ外になると破棄され、戻り値がまったく存在しない可能性があります。また、staticによって変更された静的ローカル変数は複数回呼び出され、データカバレッジの問題が発生します。最適な解決策は、ヒープ上のスペースを開く、どのくらいのスペースを開くかです。

最初に二分木をトラバースして、二分木のノード数を取得できます。対応するコードとアイデアは、以前のブログで言及されています。

アイデア:1。プレオーダートラバーサルのアイデア

2.ノードの数を再帰的に見つけます。

2.アレイを動的に開きます。

 

 int BTreeSize(struct TreeNode* root)
{
    return root == NULL? 0:BTreeSize(root->left)+BTreeSize(root->right)+1;
}
void _preorder(struct TreeNode* root,int* a,int* pi)
{
    if(root == NULL)
        return ;
    a[(*pi)++] = root->val;

    _preorder(root->left,a,pi);
    _preorder(root->right,a,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
    //确定树的大小
    *returnSize = BTreeSize(root);
    int* a = (int*)malloc(sizeof(int)*(*returnSize));

    int i =0;
    _preorder(root,a,&i);
    return a;
}

二分木のポストオーダートラバーサル

ポストオーダートラバーサル:左サブツリー-右サブツリー-ルート

このアイデアは、上記のプレオーダートラバーサルと一致しています

 

int BTreeSize(struct TreeNode* root)
{
    return root == NULL? 0:BTreeSize(root->left)+BTreeSize(root->right)+1;
}
void _preorder(struct TreeNode* root,int* a,int* pi)
{
    if(root == NULL)
        return ;

    _preorder(root->left,a,pi);
    _preorder(root->right,a,pi);
    a[(*pi)++] = root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize){
    *returnSize = BTreeSize(root);
    int* a = (int*)malloc(sizeof(int)*(*returnSize));

    int i =0;
    _preorder(root,a,&i);
    return a;

}

二分木の順序のない横断

int BTreeSize(struct TreeNode* root)
{
    return root == NULL? 0:BTreeSize(root->left)+BTreeSize(root->right)+1;
}
void _preorder(struct TreeNode* root,int* a,int* pi)
{
    if(root == NULL)
        return ;

    _preorder(root->left,a,pi);
    a[(*pi)++] = root->val;
    _preorder(root->right,a,pi);
    
}
int* inorderTraversal(struct TreeNode* root, int* returnSize){
    *returnSize = BTreeSize(root);
    int* a = (int*)malloc(sizeof(int)*(*returnSize));

    int i =0;
    _preorder(root,a,&i);
    return a;
}

別の木のサブツリー

本質的に、それはサブツリーを見つける問題です。大きなツリーの小さなツリーと与えられた小さなツリーの構造と値が完全に等しい場合trueを返します。

関数コードを呼び出して2つの数値が同じかどうかを判断し、分割統治のアイデアを採用し、最初に左側のサブツリーを実行して検索し、次に右側のサブツリーを実行して検索することを検討してください。期間中に見つかった場合は、直接trueを返します

主に分岐のアイデア。

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 && subRoot == NULL)
        return true;
    if(root == NULL || subRoot == NULL)
        return false;
    //判断其是否为相同的树,找完左树找右树
    return _isSameTree(root,subRoot) || isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

二分木探索

アイデア:1)木を作り、再帰的に分割統治します。

2)パラメータを渡す場合は、ポインタの受け渡し、値による呼び出し、仮パラメータの受け渡しが必要ですが、仮パラメータの変更は実際のパラメータに影響を与えないため、再帰時にエラーが発生します。

3)順序付きトラバーサル、左サブツリー-ルート-右サブツリー

#include<stdio.h>
#include<stdlib.h>
typedef struct BTreeNode
{
    char data;
    struct BTreeNode* left;
    struct BTreeNode* right;
}BTNode;
BTNode* CreatTree(char *a, int *pi)//这里必须传递指针 pi
{
    //递归方式创建树,那么就必须传址调用,而不是传值调用。
    //如果是‘#’就返回NULL,同时找数组下一位
    if(a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    //创建树
    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    root->data = a[(*pi)++];
    root->left = CreatTree(a, pi);
    root->right = CreatTree(a, pi);
    return root;
}
void InOrder(BTNode* root)
{
    if(root == NULL)
        return;
    InOrder(root->left);
    printf("%c ",root->data);
    InOrder(root->right);
}
int main()
{
    char a[100];
    scanf("%s",a);
    //创建树
    int i = 0;
    BTNode* Tree = CreatTree(a,&i);
    InOrder(Tree);
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_61932507/article/details/124229341