【问题标题】:Facing the problem of Initializing the tree i.e. root of the tree面临初始化树的问题,即树的根
【发布时间】:2021-03-12 09:07:40
【问题描述】:

二叉搜索树操作。

第一次插入节点时遇到问题。

函数根的变化不会反映在主函数中。

尝试在主函数中初始化根,它工作正常,就像插入函数在这种情况下工作正常。但是当树是空的并且我们第一次必须添加一个元素时,它不会被添加到树中。

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
    int data;
    struct node *left, *right;
}node;

void insert(node *root, int x)
{
    node *newrec, *p, *q;
    newrec = (node *) malloc(sizeof(node));
    newrec->data = x;
    newrec->left = NULL;
    newrec->right = NULL;

    if(root == NULL)
    {
        root = newrec;
        return;
    }
    p = root;
    while(p != NULL)
    {
        q = p;
        if(x <= p->data)
            p = p->left;
        else
            p = p->right;
    }
    if(x <= q->data)
        q->left = newrec;
    else
        q->right = newrec;
}

void delete(node *root, int x)
{
    node *p, *q, *r;
    if(root == NULL)
    {
        printf("\nTree is Empty");
        return;
    }
    p = root;
    while(p != NULL && p->data != x)
    {
        q = p;
        if(x <= p->data)
            p = p->left;
        else
            p = p->right;
    }
    if(p == NULL)
    {
        printf("\nElement not Found");
        return;
    }
    if(p->left == NULL && p->right == NULL)     // 0 child
    {
        if(p == root)
            root = NULL;
        else if(q->left == p)
                q->left = NULL;
            else
                q->right = NULL;
        free(p);
        return;
    }
    if(p->left != NULL && p->right == NULL)     // (1 child) left child but not right child
    {
        if(p == root)
            root = p->left;
        else if(q->left == p)
                q->left = p->left;
            else
                q->right = p->left;
        p->left = NULL;
        free(p);
        return;
    }
    if(p->left == NULL && p->right != NULL)     // (1 child) right child but not left child
    {
        if(p == root)
            root = p->right;
        else if(q->left == p)
                q->left = p->right;
            else
                q->right = p->right;
        p->right = NULL;
        free(p);
        return;
    }
    // 2 child
    r = p->right;
    q = p;
    while(r->left != NULL)
    {
        q = r;
        r = r->left;
    }
    p->data = r->data;
    if(q->left == r)
        q->left = r->right;
    else
        q->right = r->right;
    r->left = NULL;
    r->right = NULL;
    free(r);
}

void inorder(node *root)
{
    if(root != NULL)
    {
        inorder(root->left);
        printf("%d ", root->data);
        inorder(root->right);
    }
}

void preorder(node *root)
{
    if(root != NULL)
    {
        printf("%d ", root->data);
        preorder(root->left);
        preorder(root->right);
    }
}

void postorder(node *root)
{
    if(root != NULL)
    {
        postorder(root->left);
        postorder(root->right);
        printf("%d ", root->data);
    }
}

int main()
{
    int ch, x;
    node *root1;
    /*
    root1 = (node *) malloc(sizeof(node));
    root1->data = 1;
    root1->left = NULL;
    root1->right = NULL;
    */
    root1 = NULL;

    while(1)
    {
        printf("\nMENU");
        printf("\n1.Insert 2.Delete 3.Display 4.Exit");
        printf("\nEnter choice : ");
        scanf("%d", &ch);
        if(ch == 4)
            break;
        switch(ch)
        {
            case 1: printf("\nEnter element to Insert : ");
                    scanf("%d", &x);
                    insert(root1, x);
                    printf("\n%d ", root1->data);
                    break;
            case 2: printf("\nEnter element to delete : ");
                    scanf("%d", &x);
                    delete(root1, x);
                    break;
            case 3: if(root1 == NULL)
                        printf("\nTree is Empty");
                    else
                    {
                        printf("\nInorder   : ");
                        inorder(root1);
                        printf("\nPreorder  : ");
                        preorder(root1);
                        printf("\nPostorder :");
                        postorder(root1);
                    }
                    break;
            default: printf("\nInvalid Choice");
        }
    }

    return 0;
}

【问题讨论】:

  • insert 函数中赋值root = newrec 不会做任何事情。一旦函数结束,root 的生命周期也会结束,对它的所有修改都将丢失。您需要在此处模拟通过引用传递。或者返回新的根目录。
  • 此外,树的迭代处理增加了很多复杂性。使用递归可以更好、更简单地处理树。
  • 如何通过引用从主函数传递root1?并且在您告诉搜索的情况下进行迭代处理?
  • 如果问题在于引用,那么为什么插入(当 root 不为 NULL)和删除工作正常?

标签: c tree binary-search-tree


【解决方案1】:

问题就在这里:

void insert(node *root, int x)
{
    ...
    if(root == NULL)
    {
        root = newrec;
        return;
    }

这个操作没有做任何事情,因为root 是一个局部变量。 我建议从insert() 返回一个新根。

node* insert(node *root, int x)
{
    ...
    if(root == NULL)
    {
        return newrec;
    }
    ...
    return root;
}

用法:

root1 = insert(root1, x);

如果树变得自动平衡,这种方法可能会很方便,因为根可能会因树的旋转而改变。

【讨论】:

  • 是的。我对插入和删除功能做了同样的事情。现在它工作正常。但即使删除的返回类型为 void 并且 node* 代码也不能正常工作。根据我的说法,它不应该工作。
【解决方案2】:

在 C 语言中,所有函数参数都按值传递。这意味着调用中的值被复制到函数的局部参数变量中。

让我们举一个简单的示例程序:

#include <stdio.h>

void foo(int x)
{
    x = 10;
}

int main(void)
{
    int a = 0;
    foo(a);   // Here the value of a is copied into the foo argument variable x
    printf("a = %d\n", a);
}

对于上述程序,输出将是

a = 0

通过调用foo(a)a 的当前值被复制到foo 变量x 中(如评论中所述)。 foo函数内部的赋值x = 10只会修改局部变量x的值。 main函数中的变量a不会被修改。

到目前为止,我希望这应该不难理解。

现在对于指针,它是同样的事情。如果将指针传递给函数,则指针变量的值将被复制到函数内部的局部变量中。而函数内部对局部变量的赋值只会修改局部变量本身。

让我们再举一个简单的例子,使用字符串:

#include <stdio.h>

void foo(const char *x)
{
    x = "bar";
}

int main(void)
{
    const char *a = "hello";
    foo(a);
    printf("a = %s\n", a);
}

这将打印:

a = 你好

和第一个程序一样,变量a 的值被复制到foo 变量x。当函数返回时,对x 的赋值将丢失。

这是rootinsertdelete 函数中遇到的问题。当您分配给root 时,您只分配给这些函数内的局部变量,调用中使用的原始变量不会被修改,因为它的值被复制了。

解决该问题的一种方法是模拟按引用传递(因为 C 没有按引用传递)。这是通过将指向变量的指针传递给函数来完成的。

让我们修改第二个例子:

#include <stdio.h>

void foo(const char **x)
{
    // x is a pointer to a pointer, dereference it to get the
    // original pointer
    *x = "bar";
}

int main(void)
{
    const char *a = "hello";
    foo(&a);  // Pass a pointer to the variable `a`
    printf("a = %s\n", a);
}

与之前的程序不同,这个新程序将打印:

a = 酒吧

您也需要在函数中使用这种技术。


如果我们采用最后一个程序,我们在其中模拟通过引用传递,并绘制出指针,它在分配给x之前看起来像这样:

+----------+ +------------+ +---------+ | x in foo | -> |一个主要的| -> | “你好” | +----------+ +------------+ +---------+

那么在赋值之后会是这样的:

+----------+ +------------+ +--------+ | x in foo | -> |一个主要的| -> | “酒吧” | +----------+ +------------+ +--------+

【讨论】:

  • 好的。但是当我使插入函数返回根时,它就可以正常工作了。我保持删除功能不变。然后根据你的元素应该已经在本地删除。但它反映在结果中。那件事我不明白。
猜你喜欢
  • 2011-05-15
  • 2011-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2021-07-29
  • 1970-01-01
相关资源
最近更新 更多