BST的Seg-Fault删除()函数

时间:2013-04-24 23:17:37

标签: c++ segmentation-fault binary-search-tree

基本上,程序包含一个BST类,它指向二叉树的第一个节点,节点也是它们自己的类。

BST调用此成员函数:

void remove(const T& x)
{
    removeNode(m_root, x);
    return;
}

这是remove节点的递归部分,它运行完成:

template <typename T>
void removeNode(TreeNode<T>* &p, const T& x)
{
    if(p == NULL)
        return;

    if(x < p -> m_data)
        removeNode(p -> m_left, x);
    else if(x > p -> m_data)
        removeNode(p -> m_right, x);

    else
    {
        TreeNode<T>* tmp = new TreeNode<T>;

        if(p -> m_left == NULL)
        {
            tmp = p -> m_right;
            delete p;
            p = tmp;
        }
        else if(p -> m_right == NULL)
        {
            tmp = p -> m_left;
            delete p;
            p = tmp;
        }
        else
        {
            tmp = p -> m_right;
            TreeNode<T>* tmp2 = new TreeNode<T>;

            while(tmp -> m_left != NULL)
            {
                tmp2 = tmp;
                tmp = tmp -> m_left;
            }

            p -> m_data = tmp -> m_data;

            if(tmp2 != NULL)
                removeNode(tmp2 -> m_left, tmp -> m_left -> m_data);
            else
                removeNode(p -> m_right, p -> m_right -> m_data);
        }
    }

    return;
}

当remove()函数返回时,我是正确的,我想知道为什么?

1 个答案:

答案 0 :(得分:1)

用户@WhozCraig指出代码中最重要的错误:你分配了你从未使用过的对象(永远不会破坏!):

TreeNode<T>* tmp = new TreeNode<T>;

TreeNode<T>* tmp2 = new TreeNode<T>;

后一项任务导致条件

if(tmp2 != NULL)

始终满意,这会阻止您执行

else
    removeNode(p -> m_right, ...)

分支。

修改

假设您有一个带有键2,5和7的三节点树。让我们分别表示节点node2node5node7。假设node5是树根。假设您正在移除键5.
然后:

  • *p == node5;
  • 前三个if不满意,控件传递给else分支;
  • tmp被指定为p->m_right;
  • &node7
  • tmp2被分配了一个新的“空”对象 - 让我们称之为nodeEmpty;
  • node7没有子节点,因此tmp->m_leftNULL并且跳过while循环而不进行迭代;
  • 分配说明p->m_data = tmp->m_data会导致node5获取密钥7;
  • tmp2 == &nodeEmpty而非NULL,您致电
    • removeNode(tmp2 -> m_left, tmp -> m_left -> m_data)

显然会从nodeEmpty(?!)的不存在左子树中删除某些内容,但是......
但是tmp == &node7此时node7没有孩子,所以tmp->m_left == NULL。因此,访问tmp->m_left->m_data会触发内存访问错误,并且在递归调用removeNode之前进程崩溃。