无法破解我的老师的伪代码

时间:2019-05-31 00:26:35

标签: c binary-search-tree nodes

我正在为课程设计二进制搜索树分配,为此功能,我需要遵循教授的伪代码。不幸的是,我不确定一个具体细节,她拒绝澄清。

链接到伪代码在这里: https://imgur.com/a/rhjhEIa

SUBROUTINE insert(current, parent, node)
    IF current is null
        IF parent is null
            root = node
        ELSE
            ID node.value < parent.value
                parent.left = node
            ELSE
                parent.right = node
            END IF
            RETURN true
        END IF
    ELSE IF node.value = current.=value
        RETURN false
    ELSE IF ode.value < current.value
        insert(current.left, current, node)
    ELSE
        insert(current.right, current, node)
    END IF
END SUBROUTINE

代替node,我似乎尝试了大多数允许的变量,包括当前变量,父变量(甚至是无效的值,令人震惊。)

bool recursiveInsert(Node* current, Node* parent, double value)
{

    if (current == NULL)
    {
        if (parent == NULL)
        {
        }
        else
        {
            if (current->value < parent->value)
            {
                parent->left = current;
            }
            else
            {
                parent->right = current;
            }
            return true;
        }
    }
    else if(parent->value == current->value)
    {
        return false;
    }
    else if (parent->value < current->value)
    {
        insert(current->left, current->value, current);
    }
    else
    {
        insert(current->right, current->value, current);
    }   
}

我希望输出将值添加到二叉搜索树中并返回true,但是当我到达需要“节点”的部件时,程序当前只会抛出错误。

2 个答案:

答案 0 :(得分:1)

正如您已经提到的,这是在二进制搜索树中插入节点的功能。参数如下

  1. parent是被检查节点的父节点。这将用树的来调用。
  2. current是要检查的父节点的左侧或右侧。首次调用该函数时,如果当前节点的值小于根,则应使用root->left,如果该值大于root->right,则应使用root。如果root为空,则current也应为NULL

    if (root == NULL)
    {
        ret = recursiveInsert(NULL, NULL, node);
    } 
    else if (root->value < node->value)     
    {
        ret = recursiveInsert(root->left, root, node);
    }
    else if (root-> value > node->value)
    {
        ret = recursiveInsert(root->right, root, node);
    }
    else 
    {
        //same value, handle error
    }
    
  3. node是要添加到树中的新节点。应该在调用recursiveinsert之前完成该节点的内存分配,并指定值。

现在,让我们看看您编写的代码。

第一个错误是将第三个参数设为double。这应该是类型node的参数,该参数之前应该已经分配过。

从条件检查来看

ELSE IF node.value = current.=value
    RETURN false

似乎node->value是整数类型。

考虑到所有这些,更新的代码如下。

Node* root = NULL;  //global variable
...
bool recursiveInsert(Node* current, Node* parent, Node* node)
{

    if (current == NULL)
    {
        if (parent == NULL)
        {
            root = node;
        }
        else
        {
            if (current->value < parent->value)
            {
                parent->left = node;
            }
            else
            {
                parent->right = node;
            }
            return true;
        }
    }
    else if(node->value == current->value)
    {
        return false;
    }
    else if (parent->value < current->value)
    {
        recursiveInsert(current->left, current, node);
    }
    else
    {
        recursiveInsert(current->right, current, node);
    }   
}

答案 1 :(得分:1)

伪代码上下文中的

node是先前分配的节点,其中包含要插入树中的数据。最初的调用者分配它(这是毫无意义的,并且在RW代码中从来没有完成过)。实际上,除非您考虑使用一个可能将 个节点移出的库,否则实际上不太可能实际执行此模式。一棵树变成另一棵树,而您想避免建立/删除节点本身的开销。

关于算法,它相当简单,尽管不是很漂亮:

  1. 如果currentparent都为空,则意味着这必须是某个全局指针root所跟踪的树中的第一个节点。因此,root被直接分配了传入节点。

  2. 否则,如果current为空,但parent不是 ,则意味着parent是树中的某个潜在叶子(这意味着它具有向左,向右或同时包含都为null的指针),那么您已经落在了null指针上。插入操作需要与父值进行比较,以了解您是将节点挂在左侧还是右侧。请注意,这是低效率的,因为您已经进行了比较(这是您首先到达此处的方式)。

  3. 否则,如果current不为空,我们只需检查值是否等于或小于(如果两个都不为真,则假定更大),然后驱动到left或right的子树中保证。在这种情况下,current.leftcurrent.right成为递归的current,而current成为上述递归调用的parent

就是这样。这就是该算法的工作方式。坦率地说,这是微不足道的。

要通过您的参数列表(需要一个值而不是最后一个参数的节点)来实现该算法,只需确保仅在实际挂起节点时才分配节点,并且仅然后(有两种情况。

bool recursiveInsert(Node* current, Node* parent, double value)
{
    bool result = false;

    if (current == NULL)
    {
        if (parent == NULL)
        {
            root = malloc(sizeof *root);
            root->value = value;
            root->left = root->right = NULL;
        }
        else
        {
            Node *p = malloc(sizeof *p);
            p->value = value;
            p->left = p->right = NULL;

            if (value < parent->value)
            {
                parent->left = p;
            }
            else
            {
                parent->right = p;
            }
            result = true;
        }
    }
    else if (value < parent->value)
        result = recursiveInsert(current->left, current, value);

    else if (parent->value < value)
        result = recursiveInsert(current->right, current, value);

    return result;
}

在树中插入一个值时,调用将看起来像这样:

recursiveInsert(root, NULL, value);

虽然不漂亮,但是可以。它依赖于全局root存在可能是该算法最糟糕的部分。多重比较可能在yuck列表中排名第二。


一种不同的方法

理想情况下,将树的根作为参数传递。此外,我们可以使算法像现在这样递归,但不再依赖某些全局root。最后,我们可以将参数计数减少为两个:指针的地址(最初是根指针的地址),以及要插入的值。不管树是否使用递归,将指针指向指针作为树访问方法使该算法更加优雅。两者都在下面提供:

递归插入

bool treeInsert(Node **pp, double value)
{
    bool result = false;
    if (!*pp)
    {
        *pp = malloc(sizeof **pp);
        (*pp)->value = value;
        (*pp)->left = (*pp)->right = NULL;
        result = true;
    }
    else if (value < (*pp)->value)
    {
        result = recursiveInsert(&(*pp)->left, value);
    }
    else if ((*pp)->value < value)
    {
        result = recursiveInsert(&(*pp)->right, value);
    }
    return result;
}

迭代插入

bool treeInsert(Node **pp, double value)
{
    bool result = false;

    while (*pp)
    {
        if (value < (*pp)->value)
            pp = &(*pp)->left;

        else if ((*pp)->value < value)
            pp = &(*pp)->right;

        else break;
    }

    if (!*pp)
    {
        *pp = malloc(sizeof **pp);
        (*pp)->value = value;
        (*pp)->left = (*pp)->right = NULL;
        result = true;
    }

    return result;
}

无论哪种情况,您都通过传递根指针(因此是指向指针的指针)的地址来调用,其中空尝试由NULL根表示:

treeInsert(&root, value);

这两个功能都可以完成手头的任务。我将错误强化作为一项任务留给您(检查您的malloc)。