当前位置:首页 » 《我的小黑屋》 » 正文

完全二叉树、搜索二叉树、平衡二叉树和满二叉树(C++)

26 人参与  2024年11月07日 18:03  分类 : 《我的小黑屋》  评论

点击全文阅读


一、完全二叉树

1、什么是完全二叉树

完全二叉树是这样定义的:若二叉树的深度为 h,除第 h 层外,其它各层的结点数都达到最大个数,第 h 层所有的叶子结点都连续集中在最左边,这就是完全二叉树。(第 h 层可能包含 [1~2h] 个节点)

上面的定义看起来比较复杂。事实上,完全二叉树的节点满足如下规律:

所有节点只存在3种情况:1、有左右2个孩子;2、只有左孩子;3、没有孩子(叶节点),即不存在只有右孩子的情况;我们采用层序遍历的方式遍历节点,当遍历到某一个节点,它只有左孩子,或者没有孩子,则后序所有节点一定都是叶节点。

如下所示是完全二叉树

2、怎么判断是否是完全二叉树

        根据上述规律,我们可以设计算法:采用层序(广度优先)方法遍历节点,每一个节点都要满足上诉条件1。当遍历到某个节点不是有左右孩子时,开始检测后面节点是否全部是叶节点,如果满足,则是完全二叉树。

至于怎么写层序遍历,可以参考下面文章二叉树的宽度(广度)优先遍历C++_二叉树广度优先遍历c语言-CSDN博客

代码如下

bool IsCST(TreeNode* root){    bool flag = false; //一个flag,记录已经遍历到不是左右孩子双全的节点    if (root == nullptr)    {        return true;    }    std::queue<TreeNode*> node_que;    node_que.push(root);    while(!node_que.empty())    {        // 弹出队首节点        TreeNode* node = node_que.front();        node_que.pop();        // flag为true        if(flag)        {            // 条件二:flag是true,存在任何孩子都不是完全二叉树            if(node->left || node->right) return false;        }        else        {            if (node->left)            {                // 左孩子入队                node_que.push(node->left);                //条件二:有左孩子没有右孩子,则flag置true                if (!node->right)                {                    flag = true;                }                else                {                    // 右孩子入队                    node_que.push(node->right);                }            }            else            {                // 条件一:无左孩子但有右孩子,不是完全二叉树                if(node->right) return false;                // 条件二:无左孩子无右孩子,则flag同样置true                flag = true;            }        }    }    return true;}

二、搜索二叉树

1、什么是搜索二叉树

一个二叉搜索树要满足如下条件:

节点的左子树只包含 小于 当前节点的数节点的右子树只包含 大于 当前节点的数所有左子树和右子树自身必须也是二叉搜索树。

空树也是二叉搜索树。

例如下面是一个二叉搜索树:

2、怎么判断是否是搜索二叉树

        二叉搜索树要求任意节点的左子树都要比该节点小,而右子树比该节点大。那么,我们如果采用中序遍历的方式遍历一个二叉搜索树,理应得到一个严格递增的数列。所以我们可以考虑结合中序遍历的算法实现对搜索二叉树的判断。

        我们改变一下中序遍历的代码,就可以得到如下算法。

int s_val = 0; // 记录上一个节点的值bool b_first = true; //记录是不是中序第一个节点bool IsBST(TreeNode *root) {// 根节点为空,直接返回if (nullptr == root) {return true;}// 1)判断左子树是不是搜索二叉树if (!IsBST(root->left)) {return false;}// 比较当前值与左子树最后一个值if (!b_first && root->val < s_val) {return false;}else {s_val = root->val;b_first = false;}// 3)判断右子树是不是搜索二叉树return IsBST(root->right);}

三、平衡二叉树

1、什么是平衡二叉树

一棵平衡二叉树必须要满足如下条件:

每个节点左右两个子树的高度差不超过1每个左子树和右子树自身必须也是平衡二叉树

空树也是平衡二叉树。

例如下图就是一棵平衡二叉树

2、怎么判断是否是平衡二叉树

根据平衡二叉树的性质,我们只要判断左右子树分别是平衡二叉树,并且左右子树的高度差在1以内即可。

我们很自然的想到用递归法求解。在递归中我们需要提取2个信息:一是子树是否是平衡的;二是子树的高度,方便返回判断是否和兄弟子树的高度相差在1以内。

代码如下

struct Result{    int height; //树的高度    bool is_balance; //是否平衡    Result(int l=0, bool is_b=true):height(l), is_balance(is_b){}};Result IsBalanceTree(TreeNode* root){    if (root == nullptr)    {        return Result();    }    Result ret_left = IsBalanceTree(root->left);    Result ret_right = IsBalanceTree(root->right);    int lev = std::max(ret_left.height, ret_right.height) + 1;    int lv_diff = std::abs(ret_left.height - ret_right.height);    if (!ret_left.is_balance || !ret_right.is_balance || lv_diff > 1)    {        return Result(lev, false);    }    return Result(lev, true);}

四、满二叉树

1、什么是满二叉树

如果一棵树除最后一层无任何子节点外,每一层上的所有节点都有两个子节点,则这棵树是满二叉树。

2、怎么判断是否是满二叉树

        假设根节点所在是1层,则一棵满二叉树的每k层共有2^(k-1)个节点,一棵满二叉树的总结点个数为(2^k) -1。根据这个数学特征,我们采用层序遍历的方法可以很方便地判断是否是满二叉树。

代码如下

bool IsFullTree(TreeNode* root){    if (root == nullptr) return true;    std::queue<TreeNode*> node_que;    std::unordered_map<TreeNode*, int> node_lv; //记录每个节点所在层数    int cur_lv = 1; //记录当前遍历到的层数    int node_count = 0; // 当前层节点计数    node_que.push(root);    node_lv[root] = 1;    while(!node_que.empty())    {        // 弹出队首节点        TreeNode* node = node_que.front();        node_que.pop();        //换层        if (node_lv[node] != cur_lv)        {            // 计算上一层是否满足条件,不满足数学条件,则返回false            if(node_count != pow(2, cur_lv-1)) return false;            // 重置此层节点计数            node_count = 0;            cur_lv = node_lv[node];        }        node_count++;        // 左孩子进队列        if (node->left)        {            node_que.push(node->left);            node_lv[node->left] = cur_lv + 1;        }        // 右孩子进队列        if (node->right)        {            node_que.push(node->right);            node_lv[node->right] = cur_lv + 1;        }    }    //检测最后一层是否满足节点个数条件    if(node_count != pow(2, cur_lv-1)) return false;    return true;}


点击全文阅读


本文链接:http://zhangshiyu.com/post/183816.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1