【问题标题】:Where is the bug in this search code for a binary search tree?二叉搜索树的搜索代码中的错误在哪里?
【发布时间】:2017-12-24 06:55:10
【问题描述】:

我为严格的二叉搜索树编写了这段代码。 (如果二叉树中的每个非叶子节点都有非空的左子树和右子树,则该树称为严格二叉树。或者,换句话说,严格二叉树中的所有节点的度数均为 0 或 2 ,从不一阶。具有 N 个叶子的严格二叉树总是包含 2N – 1 个节点。)不幸的是,它不能正确打印值。我不知道有什么问题。我在互联网上看过其他网站,代码几乎相同,但我仍然无法在我的代码中找到错误。

#include <stdio.h>
#include <stdlib.h>
struct node
{
    struct node* prev;
    int data;
    struct node* next;
};
void Binary_Search_Tree(struct node *newnode,struct node *p);
void print(struct node* p);

main()
{
    struct node *root,*nnode,*temp;
    int c,d;
    root=malloc(sizeof(struct node));

    printf("Enter the root data\t");
    scanf("%d",&d);
    root->data=d;
    root->prev=NULL;
    root->next=NULL;

    while(1)
    {
        printf("Enter your choice\n1 insert element.\n2 print tree.\n3 Exit");
        scanf("%d",&c);
        switch(c)
        {
            case 1:
                nnode=malloc(sizeof(struct node));
                printf("Enter the node data\t");
                scanf("%d",&d);

                nnode->data=d;
                nnode->prev=NULL;
                nnode->next=NULL;
                temp=root;

                Binary_Search_Tree(nnode,temp);
                break;
            case 2:
                temp=root;
                print(temp);
                break;
            case 3:
                free(root);
                free(nnode);
                free(temp);
                temp=nnode=root=NULL;
                exit(1);
                break;
        }
    }
    return 0;
}

void Binary_Search_Tree(struct node *newnode,struct node *p)
{

    if(newnode->data<p->data)
    {
        if(p->prev=NULL)
        {
            p->prev=newnode;
        }
        else if(p->prev!=NULL)
        {
            p=p->prev;
            Binary_Search_Tree(newnode,p);
        }
    }
    else if(newnode->data>p->data)
    {
        if(p->next=NULL)
        {
            p->next=newnode;
        }
        else if(p->next!=NULL)
        {
            p=p->next;
            Binary_Search_Tree(newnode,p);
        }
    }
}

void print(struct node* p)
{
    if(p!=NULL)
    {
        print(p->prev);
        printf("%d\n",p->data);
        print(p->next);
    }
}

【问题讨论】:

  • “正确打印值” - 请指定预期值和实际值
  • 您应该展示一些示例输入,以及实际和预期的输出(ir 是创建 MCVE 的重要部分 — minimal reproducible example)。当您一次添加一个节点时,如何确保严格的二叉树尚不清楚。不需要添加 1,然后 2,然后 4,然后 8 个节点吗?
  • 好吧,我添加了 2 个字符并解决了问题...if(p-&gt;prev=NULL)-->if(p-&gt;prev==NULL)p-&gt;next=NULL--> p-&gt;next==NULL
  • 如果您在二元运算符周围放置空格,那么阅读代码会容易得多。阅读else if(newnode-&gt;data&gt;p-&gt;data) 而不是else if (newnode-&gt;data &gt; p-&gt;data) 更难;找到标记需要更多的努力,尤其是当箭头和&gt; 是按顺序排列的时候。如果你写if(p-&gt;next = NULL),它也更容易发现if(p-&gt;next=NULL)是错误的;更明显的是应该是if(p-&gt;next == NULL)
  • 下一次,使用所有警告和调试信息进行编译:gcc -Wall -Wextra -gGCC。改进代码以获得没有警告。使用调试器gdb

标签: c binary-search-tree


【解决方案1】:

主要问题是您使用赋值代替相等。

if( p->next=NULL )

与您预期的完全不同。会是

if ( p->next == NULL )
             ^^^

对于p-&gt;prev,支票将是p-&gt;prev == NULL

所以让我们分析一下您犯错误的第一种情况。

if( p-&gt;next = NULL )

首先给p-&gt;next赋值NULL,然后我们知道赋值语句的结果就是赋值。所以条件是

 if( NULL ) 

所以永远不会输入if 语句。 else 也是如此,因为那时 p-&gt;next = NULL。所以它不会添加新节点。树保持不变。

它并没有止步于此。由于您丢失了新分配节点的地址 - 您这里有内存泄漏。

然后解决办法

if( p->next == NULL )

好吧,当我们达到叶级别时,它将等于NULL,然后您将新分配的节点的地址分配给它。这样就解决了问题。

几件事 -

  1. 检查malloc的返回值。如果失败,它将返回NULL1

    root=malloc(sizeof(struct node));
    if( root == NULL ){
       perror("Malloc failure");
       exit(EXIT_FAILURE);
    }
    
  2. 使用完后释放动态分配的内存。

    void freeTree(struct node *root){
       if( root ){
          freeTree(root->prev);
          freeTree(root->next);
          free(root);
       }
    }
    
  3. 启用编译器警告-Wall -Werror。如果你这样做了,那个编译器就会清楚地告诉你问题。

    error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
             if(p->next=NULL)
             ^~
    
  4. 另外,检查scanf 的返回值。

    if( scanf("%d",&d) != 1 ){
      // Input failed 
      exit(EXIT_FAILURE); // or handle error.
    }
    
  5. 正如 Jonathan Leffler 在评论中提到的那样,如果您以适当的间距编写语句,可读性将会提高。 else if(newnode-&gt;data&gt;p-&gt;data) 很难阅读。与 else if (newnode-&gt;data &gt; p-&gt;data) 相比更具可读性。当您编写语句if(p-&gt;next = NULL) 时,您的眼睛会很容易看到该错误。显而易见的是if(p-&gt;next == NULL)

释放树有点棘手,因为您必须始终执行后序遍历。您需要先释放孩子,然后再释放父母。否则会出现内存泄漏。

1。之前我提到fprintf(stderr,...) Basile Starynkevitch 使用perror,这是打印诊断错误消息的好选择。

【讨论】:

  • @BasileStarynkevitch.:检查答案。我已编辑。谢谢。
  • 有趣的是perrorfprintf少打字很多:)
  • @DavidC.Rankin.: 是的,看起来是这样。
  • @DavidC.Rankin.:您认为我可以对答案进行任何修改吗?随意提及/建议
  • 我找不到任何未涵盖的内容,并结合 Leffler 对原始问题的评论,我认为涵盖了它 - 以及一些阿司匹林,用于尝试挑选原始的混杂在一起的代码...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多