以下是我在VS2008中编写的两个示例代码。第一个示例代码工作正常,而第二个(树的)产生一些错误。
1)
#include<iostream>
using namespace std;
struct node{
int number;
struct node *right;
struct node *left;
}nodeType;
int insert(struct node *,int);
int main(){
struct node * root=(struct node *)malloc(sizeof(node));
root->left=NULL;
root->right=NULL;
root->number=10;
insert(root,100);
cout<<root->right->number; //This works fine
return 1;
}
int insert(struct node * leaf,int data){
leaf->left =(struct node *)malloc(sizeof(node));
leaf->right =(struct node *)malloc(sizeof(node));
struct node *temp = leaf;
temp->right->number=12;
temp->left->number=11;
temp->right->right=NULL;
temp->right->left=NULL;
temp->left->left=NULL;
temp->left->right=NULL;
return 1;
}
2)
#include<iostream>
using namespace std;
struct node{
int number;
struct node *right;
struct node *left;
}nodeType;
int insert(struct node *,int);
int main(){
int data[50];
int i;
for(i=0;i<50;i++){
data[i]=rand()%100;
}
struct node * root=(struct node *)malloc(sizeof(node));
root->left=NULL;
root->right=NULL;
root->number = 36;
for(i=0;i<50;i++){
insert(root,data[i]);
}
cout<<root->right->number; //This doesn't work, and it throws some memory error. Though it assigns a value(it is 41) which goes to the right side in the insert function, the root's right side pointer is not able to point into that memory location. Similar case with root->.... also.
return 1;
}
int insert(struct node * leaf,int data){
if(leaf==NULL){
leaf = (struct node *)malloc(sizeof(node));
leaf->number=data;
leaf->left=NULL;
leaf->right=NULL;
}
else if(data>=leaf->number){
insert(leaf->right,data);
}
else if (data<leaf->number){
insert(leaf->left,data);
}
else
{
}
return 1;
}
为什么在第二个程序中它无法指向该位置?
编辑: 我在运行时得到的错误是:
test.exe中0x004114b4处的未处理异常:0xC0000005:Access 违规读取位置0x000000004。
中断继续忽略
答案 0 :(得分:4)
首先,您通常不应在C ++代码中使用malloc
(也不应使用struct xxx
来定义结构的实例)。
其次,main
和insert
中的代码都在执行应该由node
的ctor真正处理的工作(例如,将节点的子指针设置为NULL)。
第三,在insert
你正在测试一个永远不会是假的条件,然后添加一个永远不能执行的空else
(但无论如何都不做)。
我首先重写node
看起来像这样:
struct node{
int number;
node *right;
node *left;
node(int n) : number(n), right(NULL), left(NULL) {}
};
这样,节点的ctor将其子指针初始化为NULL,并将所需的值放入节点本身。
这让我们可以大大简化其他代码。例如,insert
最终看起来像这样:
void insert(node *&leaf, int data){
if (leaf == NULL)
leaf = new node(data);
else if (data < leaf->number)
insert(leaf->left, data);
else
insert(leaf->right, data);
}
由于这是二叉树,实际上只有三种可能:1)没有“当前”节点 - 在这种情况下,我们插入新数据“here”,或2)新数据属于左边当前节点,或3)它属于当前节点的右侧。这段代码直接反映了三方决策过程。
main
中的相当多的代码似乎也是不必要的。例如,如果我们只想在树中插入一些数字,则可以很容易地将代码简化为以下内容:
node *root = NULL;
for (int i = 0; i < 50; i++)
insert(root, rand() % 100);
首先不需要将数据放入数组中 - 我们可以将每个项目直接放入树中生成。
当然,要了解发生了什么,我们可能不仅要打印树中的一个特定节点,而且(可能)打印所有数据。幸运的是,这也很容易做到:
void show(node *tree) {
if (tree == NULL)
return;
show(tree->left);
std::cout << "\t" << tree->number;
show(tree->right);
}
这会对树进行简单的有序遍历,在遍历每个节点时打印它们。为了避免泄漏您为树创建的内存,您可能希望执行类似于删除树中节点的操作。主要区别在于,您可能希望进行后序遍历(递归删除两个子节点,然后删除当前节点)。
另一点是,树应该是它自己的一个类,insert
作为成员函数(并且可能还有一个dtor来销毁一个树并删除它的所有内容,如果你想要类似于上面的show
,也许operator<<
过载,等等。)
答案 1 :(得分:3)
第二个插入函数是通过值传递节点指针;不是通过引用或地址。因此,对它的修改不会在函数范围之外进行。
改变这个:
int insert(struct node * leaf,int data)
对此:
int insert(struct node*& leaf,int data)
在原型和的实现中。
保留有关在{+ 1}}中使用C ++程序的所有注释。虽然很糟糕,但它与你的问题毫无关系。