通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

完全二叉树为什么非常适合顺序存储结构

完全二叉树非常适合顺序存储结构的原因:完全二叉树是一种特殊二叉树,它保证所有叶子节点都在最下层,而且除了最下一层之外,其他层的节点都被填满,如果最下层不满,也必须沿着左侧连续添加节点。

一、完全二叉树非常适合顺序存储结构的原因

完全二叉树非常适合顺序存储结构的原因:完全二叉树是一种特殊二叉树,它保证所有叶子节点都在最下层,而且除了最下一层之外,其他层的节点都被填满,如果最下层不满,也必须沿着左侧连续添加节点。

一般情况下,如果将树的结点从上到下,每一层从左到右从1开始挨个编号,那么结点 i 的左孩子就是2i,右孩子就是2i+1,将这个规律反映到顺序存储中。我们可以根据数组的下标i也能找到左孩子(2i)和右孩子(2I+1),前提是数组下标 i=0位丢弃不用,从i=1开始存储树的编号为1的根结点,以此类推。所以,这样即使是将一棵树顺序存储到了一个一维数组中,结点 i 的左孩子就是2i,右孩子就是2i+1这套公式照样能够使用。

顺序存储结构可以用一个一维数组来实现,而完全二叉树的结构固定,数组的大小也是固定的。这种数组的实现方式不需要使用指针等引用类型,因此占用空间更小,访问速度更快。顺序存储的特点是连续的内存块,可以充分利用 CPU 缓存行的特性,减少一次访问需要多次跳跃的情况,因此顺序存储的数组访问速度更快。

运用完全二叉树的结构特点,可以通过下标计算父子节点的位置,大大简化了对树结构的操作。下标的计算公式是:对于节点i,它的左子节点下标为2i,右子节点下标为2i+1,父节点下标为i/2(向下取整),这些计算都可以通过位运算来实现,比加减乘除等运算更快。

由于完全二叉树除了最后一层可能不满,其他所有层都是满的,因此可以确保一个长度为 N 的完全二叉树只需要 2logN 表示。这也意味着在存储一个有 n 个节点的树时,使用数组只需要分配 2n 的空间,但是使用链表需要分配 n 个节点的空间,空间浪费很多。

二、完全二叉树简介

一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。如果对满二叉树的结点进行编号,约定编号从根结点起, 自上而下,自左而右。则深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。从满二叉树和完全二叉树的定义可以看出,满二叉树是完全二叉树的特殊形态,即如果一棵二叉树是满二叉树,则它必定是完全二叉树。

完全二叉树代码实现:

#include <iostream>
#include <queue>
 
using namespace std;
 
template <class T>
struct TreeNode
{
    T data;
    TreeNode<T> *left;
    TreeNode<T> *right;
    TreeNode(const T &x) : data(x),
                           left(NULL),
                           right(NULL) {}
};
template <class T>
bool IsComplete(TreeNode<T> *root)
{
    //1.树为空,返回错误
    if (root == NULL)
    {
        return false;
    }
    //2.树不为空
    queue<TreeNode<T> *> q;
    q.push(root);
    while (!q.empty())
    {
        TreeNode<T> *较好 = q.front();
        //2.1如果该节点两个孩子都有,则直接pop
        if (较好->left && 较好->right)
        {
            q.pop();
            q.push(较好->left);
            q.push(较好->right);
        }
        //2.2如果该节点左孩子为空,右孩子不为空,则一定不是完全二叉树
        if (较好->left == NULL && 较好->right)
        {
            return false;
        }
        //2.3如果该节点左孩子不为空,右孩子为空或者该节点为叶子节点,则该节点之后的所有结点都是叶子节点
        if ((较好->left && 较好->right == NULL) || (较好->left == NULL && 较好->right == NULL))
        {
                        if (NULL != 较好->left && NULL == 较好->right) 
                        {
                            q.push(较好->left);    
                        }
            q.pop(); //则该节点之后的所有结点都是叶子节点
            while (!q.empty())
            {
                较好 = q.front();
                if (较好->left == NULL && 较好->right == NULL)
                {
                    q.pop();
                }
                else
                {
                    return false;
                }
            }
            return true;
        }
    }
    return true;
}
 
//满二叉树
void test1()
{
    //       1
    //   2       3
    // 4    5  6   7
    TreeNode<int> *node1 = new TreeNode<int>(1);
    TreeNode<int> *node2 = new TreeNode<int>(2);
    TreeNode<int> *node3 = new TreeNode<int>(3);
    TreeNode<int> *node4 = new TreeNode<int>(4);
    TreeNode<int> *node5 = new TreeNode<int>(5);
    TreeNode<int> *node6 = new TreeNode<int>(6);
    TreeNode<int> *node7 = new TreeNode<int>(7);
    node1->left = node2;
    node1->right = node3;
    node2->left = node4;
    node2->right = node5;
    node3->left = node6;
    node3->right = node7;
    cout << IsComplete<int>(node1) << endl;
}
 
//二叉树为空
void test2()
{
    cout << IsComplete<int>(NULL) << endl;
}
 
//3.二叉树不为空,也不是满二叉树,遇到一个结点左孩子为空,右孩子不为空
void test3()
{
    //       1
    //   2       3
    // 4    5      7
    TreeNode<int> *node1 = new TreeNode<int>(1);
    TreeNode<int> *node2 = new TreeNode<int>(2);
    TreeNode<int> *node3 = new TreeNode<int>(3);
    TreeNode<int> *node4 = new TreeNode<int>(4);
    TreeNode<int> *node5 = new TreeNode<int>(5);
    TreeNode<int> *node7 = new TreeNode<int>(7);
    node1->left = node2;
    node1->right = node3;
    node2->left = node4;
    node2->right = node5;
    node3->right = node7;
    cout << IsComplete<int>(node1) << endl;
}
 
//4.二叉树不为空,也不是满二叉树,遇到叶子节点,则该叶子节点之后的所有结点都为叶子节点
void test4()
{
    //        1
    //    2       3
    // 4    5
    TreeNode<int> *node1 = new TreeNode<int>(1);
    TreeNode<int> *node2 = new TreeNode<int>(2);
    TreeNode<int> *node3 = new TreeNode<int>(3);
    TreeNode<int> *node4 = new TreeNode<int>(4);
    TreeNode<int> *node5 = new TreeNode<int>(5);
    node1->left = node2;
    node1->right = node3;
    node2->left = node4;
    node2->right = node5;
    cout << IsComplete<int>(node1) << endl;
}
 
//4.二叉树不为空,也不是满二叉树,遇到左孩子不为空,右孩子为空的结点,则该节点之后的所有结点都为叶子节点
void test5()
{
    //        1
    //    2       3
    // 4    5   6
    TreeNode<int> *node1 = new TreeNode<int>(1);
    TreeNode<int> *node2 = new TreeNode<int>(2);
    TreeNode<int> *node3 = new TreeNode<int>(3);
    TreeNode<int> *node4 = new TreeNode<int>(4);
    TreeNode<int> *node5 = new TreeNode<int>(5);
    TreeNode<int> *node6 = new TreeNode<int>(6);
    node1->left = node2;
    node1->right = node3;
    node2->left = node4;
    node2->right = node5;
    node3->left = node6;
    cout << IsComplete<int>(node1) << endl;
}
 
int main()
{
    test1();
    /*test2();*/
    /*test3();*/
    /*test4();*/
    /*test5();*/
    return 0;
}

三、二叉树简介

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点非常多只能有两棵子树,且有左右之分。

二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点。

二叉树的特殊类型:

  • 满二叉树:如果一棵二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树 。
  • 完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树。

延伸阅读1:二叉树的性质

  • 二叉树的第i层上至多有2i-1(i≥1)个节点。
  • 深度为h的二叉树中至多含有2h-1个节点。
  • 若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1。
  • 具有n个节点的满二叉树深为log2(n+1)。
相关文章