0

我正在研究二叉搜索树 (BST) 程序。根据作业的要求,用户加载一个文本文件来构建树。如果用户愿意,他们可以通过加载新的文本文件来创建新树。加载新的文本文件应该会破坏旧树。

为了适应这个要求,我创建一棵新树的方法readNewFile(),首先检查一棵树是否已经存在。如果是这样,它将在树上运行析构函数。但是,然后我需要创建一个存在于 范围之外的新树,readNewFile()以便可以全局访问它。这可能吗?如果是这样,你能解释一下如何吗?

我的简化代码:

int main() {

    //BST
    BST rootTree;

    readNewFile(rootTree);
    readNewFile(rootTree);

    return 0;
}


void readNewFile(BST& tree) {
    ifstream inFile;
    string fileName;

    // if tree was previously filled, destroy it
    if (tree.rootPtr() != NULL) {
        tree.~BST();
        BST tree = new BST();
    }

    cout << "\nEnter file to load: ";
    cin.ignore();
    getline(cin, fileName);
    cout << "Opening file " << fileName << endl;
    inFile.open(fileName.c_str(), ios::in);

    // Populates tree... //

}

析构函数(在 BST.hpp 中):

BST::~BST() {
    destroyTree(root);
}

void BST::destroyTree(TreeNode*& treePtr) {
    if (treePtr != NULL) {
        destroyTree(treePtr->leftChildPtr);
        destroyTree(treePtr->rightChildPtr);
        delete treePtr;
    }
}

这会返回一个段错误,这是有道理的,因为树被破坏了。但是,有没有办法可以创建一个与被破坏的范围相同的新树BST rootTree

4

3 回答 3

1

满足要求的一种方法是del()在您的BST类中调用一个方法。它所做的只是删除树的所有节点,但不删除根指针。这是指向根节点的指针。调用后del(),您可以开始创建新树。伪代码看起来像这样:

// if tree was previously filled, destroy it
if (tree.rootPtr() != NULL) {
   tree.del()
}

// read the input file
// Start inserting the new nodes
于 2013-01-27T22:28:57.607 回答
1

首先:代码有什么问题。

正如您已经指出的那样,如果树被破坏,您将无法再次使用它。在这种情况下,它是双重坏的:通过在BSTin上调用析构函数readNewFile(),你会导致析构函数被调用两次——一次是当你显式调用它时,第二次是当本地实例 inmain()超出范围时。 这是不好的。


现在关于如何修复它:

最简单的方法就是在rootTree内部声明为指针main(),然后将readNewFile()指向指针的指针作为参数。 readNewFile()将破坏指针指向的现有树,然后将指针重置为指向它创建的新树。简单的。

但是,更好的设计是readNewFile()创建BST. 然后main()应该构造一个新的BST并调用该实例的readNewFile().

于 2013-01-27T22:29:16.307 回答
0

除非您非常清楚自己在做什么,否则您永远不会直接调用析构函数。然后,这通常是因为它是使用 Placement new 创建的。此外,“T t = 新 T;” 没有意义,将指向 T 的指针分配给 T。我的猜测是您在这里复制 Javaism,但是这两种语言的对象模型太不同了。

于 2013-01-27T22:27:01.117 回答