c++ - 为什么打印指针地址会触发断点?

标签 c++ binary-tree

我正在尝试实现一个用于学习目的的二叉树。当我第一次收到错误时,我想我可能删除了一个节点两次。然后我意识到即使是 print 语句也会触发断点。整个程序的其他地方都没有删除,所以问题一定出在这里。

这里是BinaryTree.cpp

#include "BinaryTree.h"
#include<iostream>

BinaryTree::BinaryTree(void):root(nullptr){}
BinaryTree::~BinaryTree(void){removeWithChildren(root);}

void BinaryTree::insert(Node *n){
    cout<<"\nInserting: "<<(void*)n;
    Node *y = nullptr;
    Node *x = root;
    while(x != nullptr){
        y = x;
        if(n->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    n->parent = y;
    if(y == nullptr)
        root = n;
    else if (n->key < y->key)
        y->left = n;
    else
        y->right = n;
}

void BinaryTree::removeWithChildren(Node *n){   
//forgetChild(n);
    if(n->left)
        removeWithChildren(n->left);
    if(n->right)
        removeWithChildren(n->right);
    cout<<"\nDeleting: "<<(void*)n;
    delete n;

}
void BinaryTree::remove(Node *n){
    if(n->left == nullptr) {
        transplant(n,n->right);     
    } else if(n->right == nullptr) {
        transplant(n,n->left);
    } else {
        Node *y = minimum(n->right);
        if(y->parent != n){
            transplant(y,y->right);
            y->right = n->right;
            y->left = n->left;          
        }
        transplant(n,y);
        y->left = n->left;
        y->left->parent = y;
    }
    cout<<"\nDeleting: "<<(void*)n;
    delete n;
}
void BinaryTree::transplant(Node *u,Node *v){
    if(u->parent == nullptr) root = v;
    else if (u == u->parent->left) u->parent->left = v;
    else u->parent->right = v;
    if(v) v->parent == u->parent;   
}
string BinaryTree::prewalk(Node *n){
    string output = "";
    if(n!=nullptr){
        output += prewalk(n->left);
        output += prewalk(n->right);
        output += to_string(n->key);
    }
    return output;
}

string BinaryTree::inwalk(Node *n){
    string output = "";
    if(n!=nullptr){
        output += inwalk(n->left);
        output += to_string(n->key);
        output += inwalk(n->right);
    }
    return output;
}

Node* BinaryTree::search(Node *sub_tree,int key){
    if(sub_tree == nullptr) return nullptr;
    if(sub_tree->key == key) return sub_tree;
    if(sub_tree->key < key) return search(sub_tree->right,key);
    else return search(sub_tree->left,key);
}

Node* BinaryTree::getSuccessor(Node *n){
    if(n->right)
        return minimum(n->right);
    Node *y = n->parent;

    while(y){
        if(n != y->right) break;
        n = y;
        y = y -> parent;
    }
    return y;
}
Node* BinaryTree::minimum(Node *sub_tree){
    while(sub_tree->left)
        sub_tree = sub_tree ->left;
    return sub_tree;
}
Node* BinaryTree::maximum(Node *sub_tree){
    while(sub_tree->right)
        sub_tree = sub_tree ->right;
    return sub_tree;
}
void BinaryTree::forgetChild(Node *n){
    if(n->parent){
        if(n == n->parent->left) n->parent->left = nullptr;
        else n->parent->right = nullptr;
    }
}

这是main.cpp

#include"BinaryTree.h"

#include<iostream>
#include<random>

using namespace std;

int main(){
    {
        BinaryTree bt;

        bt.insert(new Node(5));
        bt.insert(new Node(1));
        bt.insert(new Node(3));
        bt.insert(new Node(4));
        bt.insert(new Node(9));

        //cout<<bt.inwalk(bt.getRoot())<<endl;

        bt.remove(bt.search(bt.getRoot(),3));

        //cout<<bt.inwalk(bt.getRoot())<<endl;
    }
    char x;cin>>x;
    return 0;
}

这里是BinaryTree.h

#pragma once
#include<string>

using namespace std;

struct Node{
    Node *left,*right,*parent;
    int key;
    Node():left(nullptr),right(nullptr),parent(nullptr),key(0) {}
    Node(int x):left(nullptr),right(nullptr),parent(nullptr),key(x) {}
};

class BinaryTree
{
private:
    Node *root; 

public:
    BinaryTree(void);
    ~BinaryTree(void);
    Node* getRoot() { return root; }

    void insert(Node *n);
    void removeWithChildren(Node *n);
    void remove(Node *n);
    string prewalk(Node *n);
    string inwalk(Node *n);

    Node* search(Node *sub_tree,int key);
    Node* minimum(Node *sub_tree);
    Node* maximum(Node *sub_tree);
    Node* getSuccessor(Node *n);
    void forgetChild(Node *n);
    void transplant(Node* u,Node*v);

};

析构函数调用 removeWithChildren(Node *n) 函数,参数是树的根。

我正在调用 remove(Node *n) 一次。当我不调用它时,没有错误。我逐步检查了代码,removeWithChildren 函数并未尝试删除被 remove 函数删除的节点。还是有错误。

编辑:我使用的是 Microsoft Visual Studio 2012 Express 版。 我不知道什么样的断点。 Breakpoint

EDIT2:出于某种原因在 removeWithChildren 中注释掉 forgetChild 修复了错误。

最佳答案

您没有发布代码的相关部分,但您发布的内容让人猜测您既没有提供有效的复制构造函数,也没有阻止使用默认复制构造函数。然后你犯了按值传递对象的错误(当你应该按引用传递时)从而调用默认的复制构造函数和析构函数并破坏内存。

当使用复制构造困难且可能不必要的类时,请确保默认复制构造函数不可访问。

关于c++ - 为什么打印指针地址会触发断点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31702898/

相关文章:

c++ - 如何制作一个值超过允许的最大整数的枚举?

binary-tree - 计算二叉树中叶节点的数量

arrays - 将二叉树展平为数组 : Is there a way to find a node's index in the array when traversing depth-first?

c++ - 输入迭代器 + 输出迭代器 + X = 前向迭代器

c++ - 如何在 C 风格数组上使用 find_if 和 reverse_iterator?

c++ - 关于删除表达式,C++ 中缺少 "placement delete"

c++ - 图书馆没有可用的密码

python - Python中二叉树实现的错误

java - 如何生成哈夫曼树(类似于二叉树)

c - 二叉树不从文件中添加字符串