问题就在一行代码:二叉搜索树的删除函数

之前问的有点不清楚,现在修改一下。有问题的一行注释了
BinTree Delete( BinTree BST, ElementType X )
{ Position pl,temp;
if(!BST) printf("Not Found\n");
else{
if(XData)
BST->Left = Delete(BST->Left,X);

    else if(X>BST->Data) 
         BST->Right = Delete(BST->Right,X);
    else{  
        if(BST->Left&&BST->Right){
            pl = FindMax(BST->Left);
            BST->Data = pl->Data;
            BST->Left = Delete(BST->Left,BST->Data);
            }else {
                temp = BST;
                if(BST->Left)BST = BST ->Left;
                else if(BST->Right)BST = BST ->Right;
                else BST=NULL;//如果把这一行删除程序就无法通过,为什么?
                free(temp);
            }  
        }
    }
    return BST;

}

你说的,没错。你标注的这两个地方写的有问题,代码不能正常运行的。
我不清楚你的这份代码是从哪来的,这里有个链接有正确执行的代码,你可以参考一下

https://blog.csdn.net/cuideman/article/details/53573106

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
情况1可以归类到2或者3
对于上述情况,相应的删除方法如下:
a. 直接删除该结点
b. 删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点
c. 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
d. 在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,在来处理该结点的删除问题

int BSTreeNodeDel(BSTreeNode **tree,DataType x) //删除
{

    BSTreeNode *cur = *tree;
    BSTreeNode *parent = *tree;
    BSTreeNode *del = NULL;

    while (cur)
    {
        if (cur->_data > x)
        {
            parent = cur;
            cur = cur->_left;
        }
        else if (cur->_data < x)
        {
            parent = cur;
            cur = cur->_right;
        }
        else
        {
            del = cur;

            if (cur->_left == NULL) //1、左孩子为空
            {
                if (parent->_left == cur)
                    parent->_left = cur->_right;
                else if (parent->_right == cur)
                    parent->_right = cur->_right;
                else if (parent == cur) //没有父亲节点时
                   *tree = parent->_right;
            }
            else if (cur->_right == NULL) //2、右孩子为空
            {
                if (parent->_left == cur)
                    parent->_left = cur->_left;
                else if (parent->_right == cur)
                    parent->_right = cur->_left;
                else if (parent == cur) //没有父亲节点时
                    *tree = parent->_left;
            }
            else//3、左右孩子都不为空
            {
                BSTreeNode *sub = cur->_right;
                while (sub->_left)
                {
                    parent = sub;
                    sub = sub->_left;
                }

                del = sub;
                cur->_data = sub->_data;

                if (parent->_left == sub)
                    parent->_left = sub->_right;
                else 
                    parent->_right = sub->_right;
            }

            free(del);
            del = NULL;
            return 0;

        }
    }

    return -1;
}

递归实现

int BSTreeNodeDelR(BSTreeNode **tree,DataType x) //删除
{
    if (!*tree)
        return -1;

    if ((*tree)->_data > x)
        return BSTreeNodeDelR(&(*tree)->_left,x);
    else if ((*tree)->_data < x)
        return BSTreeNodeDelR(&(*tree)->_right,x);
    else
    {
        BSTreeNode *del = *tree;
        if (!(*tree)->_left) //左为空
            *tree = (*tree)->_right;
        else if (!(*tree)->_right) //右为空
             *tree = (*tree)->_left;
        else //左右都不为空
        {
            BSTreeNode *sub = (*tree)->_right;
            while (sub->_left)
                sub = sub->_left;

            (*tree)->_data = sub->_data;
            return BSTreeNodeDelR(&(*tree)->_right,sub->_data);
        }

        free(del);
        del = NULL;
        return 0;
    }
}

数据结构全部内容我都写在专栏里,专栏链接:https://blog.csdn.net/column/details/20027.html

我明白了。
当被删除结点无左右儿子时,要返回NULL指针给该结点的双亲结点。
所以必须要加上BST=NULL,再return。

如果没有这一步,那在free(temp)后,BST指向的内存被释放,则BST指向内存的数据会被无意义数据替换(有些机器不会替换数据,但系统已经标记该内存可被再利用)。
这种情况下递归返回BST后就相当于该结点的双亲节点一个儿子指针指向了无意义的“内存海”,当中序遍历走到该结点时就会出现错误。

错误的根源是误以为free(temp)的操作等价于BST=NULL;