请考虑以下代码段:
#include <iostream>
#include <queue>
struct node {
int key;
node *l;
node *r;
node(int key)
:key(key), l(nullptr), r(nullptr) {
}
};
struct bst {
node *root;
bst() :root(nullptr) {
}
node* find(int key) {
return find(root, key);
}
node* find(node *root, int key) {
if (!root) {
return nullptr;
} else {
if (root->key < key) {
return find(root->l, key);
}
else if (root->key > key) {
return find(root->r, key);
} else {
return root;
}
}
}
void insert(int key) {
insert(root, key);
}
void insert(node *&root, int key) {
if (!root) {
root = new node(key);
} else {
if (root->key < key) {
insert(root->r, key);
} else if (root->key > key) {
insert(root->l, key);
} else {
return;
}
}
}
void print_by_level(std::ostream &o) {
if (!root) {
o << "(empty)";
return;
}
std::queue<node*> q;
int curr_lv = 1;
int next_lv = 0;
q.push(root);
while (!q.empty()) {
auto p = q.front();
q.pop();
curr_lv--;
o << p->key << ' ';
if (p->l) {
q.push(p->l);
next_lv++;
}
if (p->r) {
q.push(p->r);
next_lv++;
}
if (curr_lv == 0) {
o << '\n';
curr_lv = next_lv;
next_lv = 0;
}
}
o << '\n';
}
};
int main() {
bst t;
t.insert(5);
t.insert(10);
t.insert(15);
t.print_by_level(std::cout);
// return pointer to 5 which is root
node *p = t.find(5);
// modify it, ok
p->key = 100;
t.print_by_level(std::cout);
// now try to delete or change where p is pointing to
delete p;
p = nullptr;
// then it's not happy :(
t.print_by_level(std::cout);
return 0;
}
我希望从p
返回的find()
为root
,但事实并非如此!它似乎只返回了该指针的副本。但是p->key = 100
实际上更改了root
的值。有人能帮我解释一下吗?
另一方面,如果我手动删除t.root
,那么它会按预期工作。
int main() {
bst t;
t.insert(5);
t.insert(10);
t.insert(15);
t.print_by_level(std::cout);
// return pointer to 5 which is root
node *p = t.find(5);
// modify it, ok
p->key = 100;
t.print_by_level(std::cout);
delete t.root;
t.root = nullptr;
// ok happy now
t.print_by_level(std::cout);
return 0;
}
现在尝试更改p
指向的位置并返回node*&
:(请原谅我查看肮脏的黑客nullp
:()。
#include <iostream>
#include <queue>
struct node {
int key;
node *l;
node *r;
node(int key)
:key(key), l(nullptr), r(nullptr) {
}
};
struct bst {
node *root;
node *nullp;
bst() :root(nullptr), nullp(nullptr) {
}
node*& find(int key) {
return find(root, key);
}
node*& find(node *root, int key) {
if (!root) {
return nullp;
} else {
if (root->key < key) {
return find(root->l, key);
}
else if (root->key > key) {
return find(root->r, key);
} else {
return root;
}
}
}
void insert(int key) {
insert(root, key);
}
void insert(node *&root, int key) {
if (!root) {
root = new node(key);
} else {
if (root->key < key) {
insert(root->r, key);
} else if (root->key > key) {
insert(root->l, key);
} else {
return;
}
}
}
/**
* p q
* / \ / \
* q x3 => x1 p
* / \ / \
* x1 x2 x2 x3
*/
void rotate_w_left_child(node *&p) {
node *q = p->l;
p->l = q->r;
q->r = p;
p = q;
}
void print_by_level(std::ostream &o) {
if (!root) {
o << "(empty)";
return;
}
std::queue<node*> q;
int curr_lv = 1;
int next_lv = 0;
q.push(root);
while (!q.empty()) {
auto p = q.front();
q.pop();
curr_lv--;
o << p->key << ' ';
if (p->l) {
q.push(p->l);
next_lv++;
}
if (p->r) {
q.push(p->r);
next_lv++;
}
if (curr_lv == 0) {
o << '\n';
curr_lv = next_lv;
next_lv = 0;
}
}
o << '\n';
}
};
int main() {
bst t;
t.insert(5);
t.insert(4);
t.insert(1);
t.print_by_level(std::cout);
node *p = t.find(5);
// using root, happy
// t.rotate_w_left_child(t.root);
// t.print_by_level(std::cout);
// using p, not happy :(
t.rotate_w_left_child(p);
t.print_by_level(std::cout);
return 0;
}
答案 0 :(得分:1)
main
delete p
当你root
实际删除t
对象中的delete
指针时!不要这样做,否则你会有不确定的行为,这就是你在这里遇到的。
当您返回指针时,返回指针的副本,两个指针都将指向同一个对象。如果你然后{{1}}其中一个指针,另一个指针现在将指向一个已删除的对象。
答案 1 :(得分:0)
[这不一定是答案,而是带代码的评论]
您的代码可能受到变量阴影的影响,成员“root”与函数参数“root”明显冲突。
帮助避免此类问题的常见做法是为成员和其他特殊情况添加前缀,例如“m_”表示“成员”,“s_”表示静态,“g_”表示“全局”。不要把它与可怕的匈牙利人混淆 - 至少,not systems。
struct bst {
node *m_root;
node *m_nullp;
bst() : m_root(nullptr), m_nullp(nullptr) {
}
node*& find(int key) {
return find(m_root, key);
}
node*& find(node *root, int key) {
if (!root) { // definitely means the parameter
return nullp;
} else {
if (root->key < key) {
return find(root->l, key);
}
else if (root->key > key) {
return find(root->r, key);
} else {
return root;
}
}
}
void insert(int key) {
insert(m_root, key);
}