如何在不使用动态内存分配的情况下创建基于指针的二进制树

How do you create a pointer-based binary tree without using dynamic memory allocation?

本文关键字:于指针 指针 二进制 创建 情况下 动态 分配 内存      更新时间:2023-10-16

一些C++程序员说动态内存分配不好,应该尽可能避免。我尝试在不使用动态内存分配的情况下制作一个二叉树数据结构,但它不起作用。以下是我尝试过的:

struct BTNode {
    BTNode *left = 0, *right = 0;
    int data;
    BTNode(int d_) { data = d_; }
    void insert(int d_) {
        BTNode n(d_);
        if (d_ <= data)
            if (left == 0) left = &n;
            else left->insert(d_);
        else 
            if (right == 0) right = &n;
            else right->insert(d_);
    }
}

然后主要这样做。。。

BTNode root(8);
root.insert(9);
root.insert(10);
cout << root.right->right->data;

导致segfault,因为包含数据的BTNode很久以前就超出了作用域。

我的问题是,在不使用newdelete的情况下,如何构建这样一个基于指针的二叉树?

简单的答案是:你几乎不能。

唯一可能的方法是使整个树处于自动或全局范围内,并手动构建:

BTNode root;
BTNode left, right;
root.left=&left;
root.right=&right;

但是,当自动作用域被保留时,要么整个事情都被破坏了,要么你现在有一堆丑陋的全局变量。

动态范围和动态内存分配没有错;前提是正确使用。

您可以将所有节点都放在一个std::array<>中。它们可以自由地相互指向,当您释放阵列时,所有节点也会安全释放。您只需要确保知道数组中的哪些元素已经被使用。

无论如何,出于教育原因,或者如果您有非常、非常、非常好的理由不使用标准库提供的树和类似容器,请只使用您自己的树和容器。在后一种情况下,尽可能地模仿标准接口,以便启用标准算法、基于范围的循环以及其他C++开发人员易于理解的代码。

insert方法在堆栈上分配BTNode对象,这意味着一旦insert函数返回,对象的内存就无效。

你可以做

       BTNode newObj( 9 ) 
       root.insert( newObj );

您还必须将插入方法修改为

       void insert(BTNode &node) { ...

在这种情况下,newObj对象将保留在作用域中,直到您离开主函数为止。更好的是,你可以使它具有静态范围,然后它将在程序的持续时间内存在。