C++顺序存储实现二叉树并可视化(附源代码)

文件结构 : 

文件名字用途
CmakeList.txtcmake文件
how.md简述思路以及其他说明
main.cpp主测试程序
Tree.cpp核心实现文件
Tree.h

核心头文件

注意 : test.md是对二叉树可视化的markdown文件,程序会自动生成关于二叉树样貌的mermaid流程图代码,请放入markdown文件中

Tree.cpp

//
// Created by A Luck Boy on 2023/1/31.
//
#include "Tree.h"

BinaryTree::BinaryTree(const int *args) {
    H = args[0];
    int N = (int)pow(2, H)-1;
    data = new int[N];
    // 这里就不检测层数是否不小于1
    // 同时也不检测一个数组按照从索引1与树状图对应,是否是二叉树,比如说 : 树的某结点不存在,其后面结点也不存在
    // 但是我的程序可以自动修复用户的数据,不满足添加的换成0(即不存在结点),用户的数据存在data了,正确的存在_true_data里面
    // 另外,如果你给的层数为k,那么最大结点数目为2^k-1个,但是如果你的数组数据超过了,代码只会取2^k-1个;
    // 不够的话,程序可能会分配内存中的脏数据,导致程序不正确
    for (int i=0;i<N;i++){
        data[i] = args[1+i];
    }
    _true_data = new int[N];
    for (int i=1;i<H;i++){
        // 第i层最多有2^(i-1)个
        for (int j=(int) pow(2, i-1);j<(int) pow(2, i);j++){
            int pa = data[j-1];
            int ch1 = data[ 2 * j - 1];
            int ch2 = data[ 2 * j];
            if (pa == 0){
                data [2 * j - 1] = 0;
                data[2 * j] = 0;
                _true_data[j-1] = 0;
                _true_data[j * 2-1] = 0;
                _true_data[j * 2] = 0;
            } else if (pa != 0 && ch1 == 0 && ch2 != 0){
                _true_data[j-1] = pa;
                _true_data[j * 2-1] = 0;
                _true_data[j * 2] = ch2;
            } else if (pa != 0 && ch2 == 0 && ch1 != 0){
                _true_data[j-1] = pa;
                _true_data[j * 2-1] = ch1;
                _true_data[j * 2] = 0;
            } else if (pa != 0 && ch1 == 0 && ch2 == 0){
                _true_data[j-1] = pa;
                _true_data[j * 2-1] = 0;
                _true_data[j * 2] = 0;
            } else // here is pa != 0 && ch1 != 0 && ch2 != 0
            {
                _true_data[j-1] = pa;
                _true_data[j * 2-1] = ch1;
                _true_data[j * 2] = ch2;
            }
        }
    }
}

BinaryTree::~BinaryTree() {
    delete[] data;
    delete[] _true_data;
}

void BinaryTree::show() {
    cout << "```mermaid" << endl << "graph TD" << endl;
    for (int i=1;i<H;i++){
        // 第i层最多有2^(i-1)个
        for (int j=(int) pow(2, i-1);j<(int) pow(2, i);j++){
            // 按照正确的结点返回
            cout << j << "[" << data[j-1] << "]" << "-->" << j * 2 << "[" << _true_data[ 2 * j - 1] << "]" <<endl;
            cout << j << "[" << data[j-1] << "]" << "-->" << j * 2 + 1 << "[" << _true_data[ 2 * j] << "]" <<endl;
        }
    }
    cout << "```"<<endl;
}

int BinaryTree::getSize() const {
    int _size  =0;
    for (int i=0;i< pow(2, H)-1;i++){
        if (_true_data[i ] != 0) {
            _size++;
        }
    }return _size;
}

int BinaryTree::depth() const {
    // 考虑一个问题 : 如果传入不合法数据,导致最后一层全是0,即不存在结点
    // 解决 : 第k行的0数目不等于2^(k-1)个,说明此行存在结点
    int _true_H = 0;
    for (int i=1;i<1+H;i++) {
        int line_0 = 0;
        for (int j = (int) pow(2, i - 1); j < (int) pow(2, i); j++) {
            if (_true_data[j - 1] != 0) {
                _true_H++;
                break;
            } else{
                line_0++;
                if (line_0 == (int ) pow(2, i-1)){
                    return _true_H;
                } else{ continue;}
            }
        }
    }
}

int BinaryTree::getValue(int i, int j) const {
    // 先判断是否在范围内,不在就返回0(代表不支持结点,下同)
    if (pow(2, i-1) < j || i > H){
        return 0;
    } else{
        return _true_data[(int ) pow(2, i-1)+j-2];
    }
}

int BinaryTree::getValue(int k) const {
    // 先看看超出范围了吗
    if (pow(2, H)-1 < k){
        return 0;
    } else{
        return _true_data[k-1];
    }
}

bool BinaryTree::isFullTree() const {
    return getSize() == (int) pow(2, H)-1;
}

bool BinaryTree::isCompleted() const {
    // 只需要从_true_data中的尾部开始查看
    // 从尾部开始连续n个是0(n可以为0,0代表不存在),其他不是
    int default_not = 0;
    for (int i=1;i<1+H;i++) {
        for (int j = (int) pow(2, i - 1); j < (int) pow(2, i); j++) {
            if (_true_data[j -1] != 0){
                default_not++;
            }else{
                return getSize() == default_not;
            }
        }
    }
    return default_not == getSize();
}

BinaryTree BinaryTree::childTree(char direct) const {
    // direct必须是l和r之一,否则程序强制退出
    // 不考虑以下特例  ;只有根的树(H=1)
    if (direct == 'r'){
        int *_dat = new int[(int ) pow(2, H-1)];
        // 获取右子树所有数据,包含不存在的0,下同
        _dat[0] = H - 1;
        int index = 1;
        for (int i=2;i<H+1;i++){
            for (int j=(int) (pow(2, i-1) + pow(2, i-2));j<(int ) pow(2, i);j++){
                _dat[index] = _true_data[j-1];
                cout << " J  == " << j << "  " ;
                index++;
            }cout <<endl;
        }
        return BinaryTree(_dat);
    } else if (direct == 'l'){
        int *_dat = new int[(int ) pow(2, H-1)];
        // 获取右子树所有数据,包含不存在的0,下同
        _dat[0] = H - 1;
        int index = 1;
        for (int i=2;i<H+1;i++){
            for (int j=(int)pow(2, i-1);j<(int )(pow(2, i-2)+pow(2, i-1));j++){
                _dat[index] = _true_data[j-1];
                index++;
            }
        }
        return BinaryTree(_dat);
    }else{
        cout << "The parameter direct must be either r or l"<<endl;
        exit(EXIT_FAILURE);
    }
}

Tree.h

//
// Created by A Luck Boy on 2023/1/31.
//

// 顺序存储实现二叉树
// 但是有明显的缺点 : 对空结点需要存储,这里用0代表此结点不放值
#include <iostream>
#include <cmath>

using namespace std;
#define Waring cout << "此处代码错误!\n";

// 数组索引1开始数据的位置,代表结点的位置

class BinaryTree{
private:
    // 用户存入的数据(但不一定是符合二叉树的值)
    int *data;
    // 真值,符合二叉树
    int *_true_data;
    // 用户传入的最大层数(但不一定是真实的,但是不影响其他核心程序)
    int H;
    BinaryTree * leftTree;
    BinaryTree * rightTree;
public:
    // methods
    // arg是数组,按照满二叉树对应位置布局,第0个索引处放入层数(算入根结点所在层),第一个索引值代表根结点
    explicit BinaryTree(const int *args);
    ~BinaryTree();

    // 遍历
    // 生成可在markdown中展示的mermaid代码,复制下来就可以在markdown中查看树形结构布局
    void show();

    // 获取合理结点
    [[nodiscard]] int getSize() const;

    // 获取真实的深度
    [[nodiscard]] int depth() const;

    // 访问第i层,第j个结点,或者说,按照满二叉树的顺序,访问第k个元素
    // i, j, k都是正常访问位置,不是索引位置
    // 比如说 二叉树 :
    //              1
    //            11 21
    //          10 15 2 23
    // 按照第一种方法  :第2行,第1个是11
    // 按照第二种方法  :第4个元素是10
    [[nodiscard]] int getValue(int i, int j) const;
    [[nodiscard]] int getValue(int k) const;

    // 判断是不是满二叉树
    [[nodiscard]] bool isFullTree() const;

    // 判断是不是完全二叉树
    [[nodiscard]] bool isCompleted() const;

    // 返回左(右)子树
    [[nodiscard]] BinaryTree childTree(char direct) const;

};

main.cpp

//
// Created by A Luck Boy on 2023/1/31.
//
#include "Tree.h"


int main() {
    // 传参方式是数组,数组第一个数必须是层数,其他是结点数据,不存在结点用0表示
    int array[] = {4,9, 0, 5, 78, 0, 6, 0, 5
                   , 9, 7, 8, 10, 0, 0, 0};
    BinaryTree tree(array);
    tree.show();

    // 查看合理的结点个数 (答案是7,和mermaid流程图显示的一样,通过计算也是如此)
    cout << "total : " << tree.getSize() <<endl;
    // 两种方式获取值
    cout << tree.getValue(1) << endl;
    cout << tree.getValue(1, 1) << endl;
    cout << tree.getValue(6) << endl;
    cout << tree.getValue(3, 3) << endl;
    cout << tree.getValue(12) << endl;
    cout << tree.getValue(4, 5) << endl;

    // 创建一个满二叉树
    int arr[] = {3, 1, 2, 3, 4, 5, 6, 7};
    BinaryTree fullTree(arr);
    fullTree.show();
    if (fullTree.isFullTree()) {
        cout << "确实是满树\n";
    } else{
        Waring
    }
    // 判断真实的深度
    // 下面这个二叉树实际只有2层
    int arr2[] = {4,
                  2,
                  10, 0,
                  0,0, 6, 0,
               0,0, 0, 0, 0, 0, 0, 0};
    auto tree1 = BinaryTree(arr2);
    tree1.show();
    cout << tree1.depth()<<endl;

    // 创建一个完全二叉树
    int arr1[] = {3, 1, 2, 1, 4, 5, 0, 0};
    BinaryTree completeTree(arr1)   ;
    completeTree.show() ;
    if (completeTree.isCompleted()){
        cout << "确实是完全树\n";
    } else{Waring}

    // 创建一个不是完全二叉树的
    int arr3[]  ={3, 1, 2, 3, 0, 1, 4, 5};
    BinaryTree not_completeTree(arr3)   ;
    not_completeTree.show();
    if (!not_completeTree.isCompleted()){
        cout << "确实不是完全树\n";
    } else{Waring}

    // 获取左右子树,基于第一个实例
    auto rT = tree.childTree('r');
    rT.show();
    auto lT = tree.childTree('l');
    lT.show();
}

终端运行结果

```mermaid
graph TD
1[9]-->2[0]
1[9]-->3[5]
2[0]-->4[0]
2[0]-->5[0]
3[5]-->6[6]
3[5]-->7[0]
4[0]-->8[0]
4[0]-->9[0]
5[0]-->10[0]
5[0]-->11[0]
6[6]-->12[10]
6[6]-->13[0]
7[0]-->14[0]
7[0]-->15[0]
```
total : 4
9
9
6
6
10
10
```mermaid
graph TD
1[1]-->2[2]
1[1]-->3[3]
2[2]-->4[4]
2[2]-->5[5]
3[3]-->6[6]
3[3]-->7[7]
```
确实是满树
```mermaid
graph TD
1[2]-->2[10]
1[2]-->3[0]
2[10]-->4[0]
2[10]-->5[0]
3[0]-->6[0]
3[0]-->7[0]
4[0]-->8[0]
4[0]-->9[0]
5[0]-->10[0]
5[0]-->11[0]
6[0]-->12[0]
6[0]-->13[0]
7[0]-->14[0]
7[0]-->15[0]
```
2
```mermaid
graph TD
1[1]-->2[2]
1[1]-->3[1]
2[2]-->4[4]
2[2]-->5[5]
3[1]-->6[0]
3[1]-->7[0]
```
确实是完全树
```mermaid
graph TD
1[1]-->2[2]
1[1]-->3[3]
2[2]-->4[0]
2[2]-->5[1]
3[3]-->6[4]
3[3]-->7[5]
```
确实不是完全树
 J  == 3  
 J  == 6   J  == 7  
 J  == 12   J  == 13   J  == 14   J  == 15  
```mermaid
graph TD
1[5]-->2[6]
1[5]-->3[0]
2[6]-->4[10]
2[6]-->5[0]
3[0]-->6[0]
3[0]-->7[0]
```
```mermaid
graph TD
1[0]-->2[0]
1[0]-->3[0]
2[0]-->4[0]
2[0]-->5[0]
3[0]-->6[0]
3[0]-->7[0]
```

可视化结果

源代码  ;

BinaryTree · PythonnotJava/自己实现的数据结构与算法合集 - 码云 - 开源中国 (gitee.com)

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

若您有别的建议,请在评论区留言

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值