我编写了一个程序,它将两个文件名作为参数,f1和f2,两个文件都带有数字。 程序应该可以调用如下:tree f1 f2
f1拥有数百万个唯一数字,每行一个。应读取每个数字并将其插入二进制搜索树。
插入这些文件后,程序应从第二个文件中读取数字。对于每个号码,必须完成以下操作:
现在,我的插入和搜索代码正在给出正确的结果,但是,在删除的部分,有一些错误。
请修改我的代码来帮助我:
#include <stdio.h>
#include <stdlib.h>
struct node {
int info;
struct node *left, *right;
};
struct node *insert (struct node *root, int item)
{
struct node *temp, *temp1, *pre;
temp = (struct node *) malloc (sizeof (struct node));
temp->info = item;
temp->left = temp->right = NULL;
if (root == NULL)
root = temp;
else {
temp1 = root;
while (temp1 != NULL) {
pre = temp1;
if (item < temp1->info)
temp1 = temp1->left;
else
temp1 = temp1->right;
}
if (item < pre->info)
pre->left = temp;
else
pre->right = temp;
}
return root;
}
struct node *create (struct node *root)
{
int num;
root = NULL;
FILE *fp1 = fopen ("myFile1.txt", "r");
if (fp1 == NULL) {
printf ("cannot open this file");
exit (0);
}
while (fscanf (fp1, "%d", &num) == 1)
root = insert (root, num);
return root;
fclose (fp1); /* (note: unreachable code) */
}
struct node *min (struct node *ptr)
{
struct node *current = ptr;
while (current->left != NULL)
current = current->left;
return current;
}
struct node *delete (struct node *root, int n)
{
if (root == NULL)
return root;
if (n < root->info)
root->left = delete (root->left, n);
else if (n > root->info)
root->right = delete (root->right, n);
else {
if (root->left == NULL) {
struct node *p;
p = root->right;
free (root);
return p;
}
else if (root->right == NULL) {
struct node *p;
p = root->left;
free (root);
return p;
}
struct node *p;
p = min (root->right);
root->info = p->info;
root->right = delete (root->right, p->info);
}
return root;
}
void search (struct node *root)
{
int Y, X;
struct node *t;
t = root;
char ch = 'n';
FILE *fp2 = fopen ("myFile2.txt", "r");
if (fp2 == NULL) {
printf ("cannot open this file");
exit (0);
}
X = 0;
while (fscanf (fp2, "%d", &Y) == 1) {
while (t != NULL && X == 0) {
if (Y == t->info) {
X = 1;
break;
} else if (Y < t->info)
t = t->left;
else
t = t->right;
}
if (X == 1)
printf (" %d is found %d\n", Y, X);
printf ("if you want to delete a number ");
scanf ("%c", &ch);
if (ch == 'y') {
root = delete (root, Y);
return root;
}
else
printf ("%dNot found %d\n", Y, X);
}
fclose (fp2);
}
void inorder (struct node *root)
{
if (root != NULL) {
inorder (root->left);
printf ("%d ", root->info);
inorder (root->right);
}
}
void main ()
{
struct node *root = NULL;
struct node *ptr = NULL;
root = create (root);
inorder (root);
search (root);
inorder (root);
}
答案 0 :(得分:0)
以下是更正后的代码:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int info;
struct node *left, *right;
};
struct node* insert(struct node* root, int item)
{
struct node *temp,*temp1,*pre;
temp = (struct node *)malloc(sizeof(struct node));
temp->info = item;
temp->left = temp->right = NULL;
if (root == NULL)
{
root=temp;
}
else
{
temp1=root;
while(temp1!=NULL)
{
pre=temp1;
if(item<temp1->info)
{
temp1=temp1->left;
}
else
{
temp1=temp1->right;
}
}
if(item<pre->info)
{
pre->left=temp;
}
else
{
pre->right=temp;
}
}
return root;
}
struct node *create(struct node *root)
{
int num;
root=NULL;
FILE *fp1=fopen("myFile1.txt","r");
if (fp1 == NULL)
{
printf("cannot open this file");
exit(0);
}
while(fscanf(fp1,"%d",&num)==1)
root=insert(root,num);
fclose(fp1);
return root;
}
struct node * min(struct node* ptr)
{
struct node* current = ptr;
while (current->left != NULL)
current = current->left;
return current;
}
struct node* delete(struct node* root,int n)
{
if(root==NULL)
{
return root;
}
if(n<root->info)
{
root->left=delete(root->left,n);
}
else if(n>root->info)
{
root->right=delete(root->right,n);
}
else
{
if(root->left==NULL)
{
struct node *p;
p=root->right;
free(root);
return p;
}
else
if(root->right==NULL)
{
struct node *p;
p=root->left;
free(root);
return p;
}
struct node *p;
p=min(root->right);
root->info=p->info;
root->right=delete(root->right,p->info);
}
return root;
}
void search(struct node *root)
{
int Y,X;
struct node *t;
char ch='n';
FILE *fp2=fopen("myFile2.txt","r");
if (fp2 == NULL)
{
printf("cannot open this file");
exit(0);
}
while(fscanf(fp2,"%d",&Y)==1)
{
t = root;
X = 0;
while(t!=NULL && X==0)
{
if(Y==t->info)
{
X=1;
break;
}
else
{
if(Y<t->info)
{
t=t->left;
}
else
{
t=t->right;
}
}
}
if(X==1)
{
printf("\n%d is found\n",Y);
printf("\nDo you want to delete %d (y/n): ",Y);
scanf(" %c",&ch);
if(ch=='y')
{
root=delete(root,Y);
}
}
else
{
printf("\n%d Not found %d\n",Y,X);
}
}
fclose(fp2);
}
void inorder(struct node *root)
{
if (root != NULL)
{
inorder(root->left);
printf("%d ", root->info);
inorder(root->right);
}
}
void main()
{
struct node *root = NULL;
struct node *ptr = NULL;
root=create(root);
inorder(root);
printf("\n");
search(root);
printf("\n");
inorder(root);
printf("\n");
}
除了格式的微小更改外,以下是主要更改:
始终记得为每个控制语句(if,while,else等)添加{}
大括号,即使它有一个操作,因为稍后可能会添加代码对于相同的控制语句,忘记大括号意味着控制语句不会应用于该代码。对于例如你忘记了括号:
if(X==1)
printf(" %d is found %d\n",Y,X);
printf("if you want to delete a number ");
scanf("%c",&ch);
if(ch=='y')
{
root=delete(root,Y);
return root;
}
else
printf("%dNot found %d\n",Y,X);
现在由于缺少大括号,其他内容正在应用于if(ch=='y')
而不是if(X==1)
。
其次,无论何时将条件变量初始化为值并对其进行检查,都在嵌套循环内,并且对于多个输入或案例重复操作,初始化也需要在内部完成循环。在t = root;
函数中X = 0;
和search
的情况也是如此,它们只是设置了一次,当从文件中读取下一个数字时,它们没有再次初始化。
您在return root;
函数中调用void search(struct node *root)
,其返回类型为void
,这意味着它返回无:
if(ch=='y')
{
root=delete(root,Y);
return root;
}
并且,return
调用意味着该函数将停止进一步执行,然后在那里,return
调用之下的剩余代码将不会被执行,这不是什么你想要的,如:
struct node *create(struct node *root)
{
int num;
...
while(fscanf(fp1,"%d",&num)==1)
root=insert(root,num);
return root;
fclose(fp1);
}
这里,fclose(fp1);
永远不会被调用。
最后但并非最不重要的是,更好的代码缩进可以帮助理解每个控制语句的范围所在,而不必跟踪每个左括号{
到其结束{{1} }}
答案 1 :(得分:-1)
从长远来看,您还有其他几个方面可以避免给自己造成问题。您希望避免代码主体中的硬编码文件名,更不用说硬编码隐藏在函数中的文件名。如果您需要对某个文件进行操作,例如create
或search
,请将FILE*
参数(或文件名)传递给该函数。这将使您的代码更易于维护和重用。对于create
,你会做类似的事情:
struct node *create (struct node *root, FILE *fp)
{
int num;
root = NULL;
while (fscanf (fp, "%d", &num) == 1)
root = insert (root, num);
return root;
}
对于您当前的search
,您可以执行以下操作:
void search (struct node *root, FILE *fp)
{
int v;
while (fscanf (fp, "%d", &v) == 1) {
struct node *t = root;
char ch = 'n';
while (t != NULL) {
if (t->info == v) {
printf ("\n%d is found\n", v);
printf ("\nDo you want to delete %d (y/n): ", v);
scanf (" %c", &ch);
if (ch == 'y') {
root = delete (root, v);
}
break;
}
else {
if (v < t->info)
t = t->left;
else
t = t->right;
}
}
if (!t)
printf ("\n%d Not found\n", v);
}
}
但为什么要将FILE *
指针传递给search
开始? search
不应只搜索您的树并返回指向包含匹配值(如果存在)的节点的指针,否则返回NULL
?这肯定会使search
在您的树的许多不同情况下使用一般函数,而不是对第二个文件中的匹配值进行一次性检查。
如何获取代码所需的文件名信息?就像您将所需参数传递给您在代码中调用的每个函数一样,您可以以相同的方式将所需信息传递给main
。 main
接受命令行中给出的参数并将它们传递给您的程序。 main
的一般形式是:
int main (int argc, char **argv)
(您还会看到等效形式int main (int argc, char *argv[])
,它只是反映argv
的替代形式,而不显示数组作为函数传递时自动发生的数组转换结果参数)
使用参数获取main
的信息而不是硬编码。这并不意味着您不能在代码中提供默认文件名,如果没有提供参数,将使用这些文件名。您可以使用三元运算符,它基本上是if-else
形式的简写(condition) ? true_value : false_value
语句。有了它,你可以从命令行获取文件名,同时仍然提供在没有提供参数的情况下使用的文件名的默认值(注意:第一个参数将始终用作fp1
)。 e.g:
int main (int argc, char **argv)
{
FILE *fp1 = fopen (argc > 1 ? argv[1] : "myfile1.txt", "r");
FILE *fp2 = fopen (argc > 2 ? argv[2] : "myfile2.txt", "r");
if (fp1 == NULL) {
fprintf (stderr, "cannot open fp1\n");
return 1;
}
if (fp2 == NULL) {
fprintf (stderr, "cannot open fp2\n");
return 1;
}
然后,您可以将FILE*
指针(fp1
,fp2
)传递给任何需要它们的函数,例如:
root = create (root, fp1);
从create
和search
删除了硬编码文件名后,您可以将注意力转移到创建search
,这比仅检查第二个文件中的匹配值更有用。重写search
,它只需要一个指向root
的指针和要搜索的值,然后它可以返回指示是否在树中找到该值(通常是指向包含该节点的节点的指针)是否值,返回NULL
指针。例如:
struct node *search (struct node *root, int v)
{
struct node *t = root;
while (t != NULL) {
if (t->info == v)
return t;
else {
if (v < t->info)
t = t->left;
else
t = t->right;
}
}
return t;
}
要以可维护的方式完成代码,您只需编写一个函数来读取第二个文件search
树的值,然后在找到值时提示允许删除。同样,它只需要作为参数指向root
和FILE*
指针来读取值。然后它可以从那里处理调用search
和delete
。 (注意:delete
可以被重写以直接对search
返回的指针进行操作,以避免第二次遍历,但这是另一天)。例如,您的检查和提示删除功能可能是:
void check_delete (struct node *root, FILE *fp)
{
int v;
while (fscanf (fp, "%d", &v) == 1) {
char ch = 'n';
if (search (root, v)) {
printf ("\n%d is found\n", v);
printf ("\nDo you want to delete %d (y/n): ", v);
scanf (" %c", &ch);
if (ch == 'y')
root = delete (root, v);
}
else
printf ("\n%d Not found\n", v);
}
}
将拼图的所有部分放在一起,并在main
上方提供函数原型(最终将其与结构一起移动到正确的头文件中)和函数定义(最终将移动到一个单独的源文件),您将结束类似于以下代码的内容。请注意,这并不是一个包含所有建议的更改或改进的详尽重写,但重要的是以正确的方式开始处理代码所需的信息,并避免尽早陷入不良习惯。如果您还有其他问题,请与我们联系:
#include <stdio.h>
#include <stdlib.h>
struct node {
int info;
struct node *left, *right;
};
/* function prototypes */
struct node *insert (struct node *root, int item);
struct node *create (struct node *root, FILE *fp);
struct node *min (struct node *ptr);
struct node *delete (struct node *root, int n);
struct node *search (struct node *root, int v);
void check_delete (struct node *root, FILE *fp);
void inorder (struct node *root);
int main (int argc, char **argv)
{
FILE *fp1 = fopen (argc > 1 ? argv[1] : "myfile1.txt", "r");
FILE *fp2 = fopen (argc > 2 ? argv[2] : "myfile2.txt", "r");
if (fp1 == NULL) {
fprintf (stderr, "cannot open fp1\n");
return 1;
}
if (fp2 == NULL) {
fprintf (stderr, "cannot open fp2\n");
return 1;
}
struct node *root = NULL;
root = create (root, fp1);
fclose (fp1);
inorder (root);
putchar ('\n');
check_delete (root, fp2);
fclose (fp2);
putchar ('\n');
inorder (root);
putchar ('\n');
return 0;
}
struct node *insert (struct node *root, int item)
{
struct node *temp, *temp1, *pre;
temp = malloc (sizeof *temp);
temp->info = item;
temp->left = temp->right = NULL;
if (root == NULL) {
root = temp;
}
else {
temp1 = root;
while (temp1 != NULL) {
pre = temp1;
if (item < temp1->info)
temp1 = temp1->left;
else
temp1 = temp1->right;
}
if (item < pre->info)
pre->left = temp;
else
pre->right = temp;
}
return root;
}
struct node *create (struct node *root, FILE *fp)
{
int num;
root = NULL;
while (fscanf (fp, "%d", &num) == 1)
root = insert (root, num);
return root;
}
struct node *min (struct node *ptr)
{
struct node *current = ptr;
while (current->left != NULL)
current = current->left;
return current;
}
struct node *delete (struct node *root, int n)
{
if (root == NULL) {
return root;
}
if (n < root->info) {
root->left = delete (root->left, n);
} else if (n > root->info) {
root->right = delete (root->right, n);
} else {
if (root->left == NULL) {
struct node *p;
p = root->right;
free (root);
return p;
} else if (root->right == NULL) {
struct node *p;
p = root->left;
free (root);
return p;
}
struct node *p;
p = min (root->right);
root->info = p->info;
root->right = delete (root->right, p->info);
}
return root;
}
struct node *search (struct node *root, int v)
{
struct node *t = root;
while (t != NULL) {
if (t->info == v)
return t;
else {
if (v < t->info)
t = t->left;
else
t = t->right;
}
}
return (t);
}
void check_delete (struct node *root, FILE *fp)
{
int v;
while (fscanf (fp, "%d", &v) == 1) {
// struct node *t = root;
char ch = 'n';
if (search (root, v)) {
printf ("\n%d is found\n", v);
printf ("\nDo you want to delete %d (y/n): ", v);
scanf (" %c", &ch);
if (ch == 'y')
root = delete (root, v);
}
else
printf ("\n%d Not found\n", v);
}
}
void inorder (struct node *root)
{
if (root != NULL) {
inorder (root->left);
printf ("%d ", root->info);
inorder (root->right);
}
}