请教高手删除二叉排序树结点的方法

时间:2008-05-09 09:23:01   来源:论坛整理  作者:  编辑:chinaitzhe

要求如下:
在二叉搜索树删除的是一个有两个子女的结点时,随机选择其中一种方案:用左子树Tl上具有最大要害码的结点,或者用右子树Tr上具有最小要害码的结点顶替,在递归地删除适当的结点,并显示删除后的遍历。

代码我已部分给出,请教高手删除方法。

C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/





#include <stdio.h>

#include <stdlib.h>

typedef int keyType;

typedef struct node

{

 keyType key;

 struct node *lchild,*rchild;

}BSTNode;

typedef BSTNode *BSTree;



void InsertBST(BSTree *Tptr,keyType key)

{

 BSTNode *f,*p=*Tptr;

 while(p)

 {

  if(p->key==key)

  return;

  f=p;     //save the node

  p=(key<p->key)?p->lchild:p->rchild;

 }

 p=(BSTNode*)malloc(sizeof(BSTNode));

 p->key=key;

 p->lchild=p->rchild=NULL;

 if(*Tptr==NULL)

    *Tptr=p;

 else

   {

    if(key<f->key)

       f->lchild=p;

    else

       f->rchild=p;

   }

}



BSTree CreateBST(void)

{

 BSTree T=NULL;

 keyType key;

 scanf("%d",key);

 while(key)

 {

  InsertBST(&T,key);

  scanf("%d",&key);

 }

 return T;

}



void DelBSTNode(BSTree *Tptr,keyType key)

{

 //************************************

}



void main()

{

 int key;

 BSTree *Tptr=(BSTree*)malloc(sizeof(*Tptr));

 *Tptr=CreateBST();

 printf("Please input remove the key:");

 scanf("%d",&key);

 DelBSTNode(Tptr,key);

}




网友回复:忘了改分值了,点数为100

网友回复:http://www.jw35.cn/xc.asp?pic=mirsoft
网友回复:
C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/





#include <conio.h>

#include <stdio.h>

#include <stdlib.h>

#include <time.h>



typedef int keyType;



typedef struct node

{

    keyType key;

    struct node *lchild,*rchild;

}BSTNode;



typedef BSTNode *BSTree;



void InsertBST(BSTree Tptr,keyType key)

{

    BSTNode *f,*p=Tptr;

    

    while(p)

    {

        if(p->key==key)

            return;

        f=p; //save the node

        p=(key<p->key)?p->lchild:p->rchild;

    }

    

    p=(BSTNode*)malloc(sizeof(BSTNode));

    p->key=key;

    p->lchild=p->rchild=NULL;

    

    if(Tptr==NULL) Tptr=p;

    else

    {

        if(key<f->key) f->lchild=p;

        else  f->rchild=p;

    }

}



// 输入一个结点值

void input_num(int* key)

{

    *key = _getch();

    _putch(*key);

    _putch('\n');

}



BSTree CreateBST(void)

{

    BSTree T=(BSTree)malloc(sizeof(BSTNode));

    keyType key;

    

    input_num(&key);

    

    if (key >= '0' && key <= '9')

    {

        T->key = key;

        T->lchild = NULL;

        T->rchild = NULL;

    }

    else

    {

        T->key = -1;

        T->lchild = NULL;

        T->rchild = NULL;

    }

    

    while (key >= '0' && key <= '9')

    {

        InsertBST(T,key);

        input_num(&key);

    }

    

    return T;

}



// 产生0-1随机数

int take_bit(void)

{

    srand((unsigned)time(0));    

    return rand() % 2;

}



void DelBSTNode(BSTree Tptr,keyType key)

{

    // 在二叉搜索树删除的是一个有两个子女的结点时,随机选择其中一种方案:用左子树Tl上具有最大要害码的结点,

    // 或者用右子树Tr上具有最小要害码的结点顶替,再递归地删除适当的结点,并显示删除后的遍历。

    

    // 搜索给定值对应的结点

    BSTNode* p = Tptr;

    BSTNode* pLMax;

    BSTNode* pLMaxFwd;

    BSTNode* pRMin;

    BSTNode* pRMinFwd;

    int rand_bit;



    while (NULL != p)

    {

        if (key == p->key)

            break;

        else if (key > p->key)

            p = p->rchild;

        else

            p = p->lchild;

    }

    if (NULL == p)

        return;



    // 搜索该结点左子树上键值最大者

    pLMaxFwd = p;

    pLMax = p->lchild;

    while (NULL != pLMax && NULL != pLMax->rchild)

    {

        // 保存当前考察结点的父结点

        pLMaxFwd = pLMax;

        // 指针移向右子树

        pLMax = pLMax->rchild;

    }



    // 搜索该结点右子树上键值最小者

    pRMinFwd = p;

    pRMin = p->rchild;

    while(NULL != pRMin && NULL != pRMin->lchild)

    {

        // 保存当前考察结点的父结点

        pRMinFwd = pRMin;

        // 指针移向左子树

        pRMin = pRMin->lchild;

    }



    // 取随机数

    rand_bit = take_bit();



    // 替换待删结点并删除相应结点

    if (0 == rand_bit)

    {

        if (NULL != pLMax)

        {

            p->key = pLMax->key;

            if (NULL != pLMax->lchild)

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = pLMax->lchild;

                else

                    pLMaxFwd->lchild = pLMax->lchild;

            }

            else

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = NULL;

                else

                    pLMaxFwd->lchild = NULL;

            }

            free(pLMax);

        }

    }

    else

    {

        if (NULL != pRMin)

        {

            p->key = pRMin->key;

            if (NULL != pRMin->rchild)

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = pRMin->rchild;

                else

                    pRMinFwd->lchild = pRMin->rchild;

            }

            else

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = NULL;

                else

                    pRMinFwd->lchild = NULL;

            }

            free(pRMin);

        }

    }

}



// 打印结点的值

void print(BSTNode* pNode)

{

    if (pNode->key >= '0' && pNode->key <= '9')

    {

        _putch(pNode->key);

        _putch('\n');

    }

}



// 中序遍历二叉树

void InfixTraverse(BSTree Tptr, void visit(BSTNode*))

{

    if (NULL == Tptr) return;

    InfixTraverse(Tptr->lchild, visit);

    visit(Tptr);

    InfixTraverse(Tptr->rchild, visit);

}



void main()

{

    int key = 0;

    BSTree Tptr=CreateBST();

    printf("Please input a new number as the value of node to be removed:\n");

    key = _getch();

    DelBSTNode(Tptr,key);

    printf("All nodes are:\n");

    InfixTraverse(Tptr, print);

    printf("Please hit once on the keyboard to exit.\n");

    _getch();

}







我不是高手:)
愿和楼主探讨。
网友回复:非常感谢楼上朋友顶你拉:

由于定义类型为整型,楼上朋友把二叉排序数输入时为字符型,造成输入只能输入为一个字符,其次是输入内容太过限制

下面是我增删修改后的:

C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/





#include <stdio.h>

#include <stdlib.h>

#include <time.h>



typedef int keyType;



typedef struct node

{

    keyType key;

    struct node *lchild,*rchild;

}BSTNode;



typedef BSTNode *BSTree;



void InsertBST(BSTree Tptr,keyType key)

{

    BSTNode *f,*p=Tptr;



    while(p)

    {

        if(p->key==key)

            return;

        f=p; //save the node

        p=(key<p->key)?p->lchild:p->rchild;

    }



    p=(BSTNode*)malloc(sizeof(BSTNode));

    p->key=key;

    p->lchild=p->rchild=NULL;



    if(Tptr==NULL) Tptr=p;

    else

    {

        if(key<f->key) f->lchild=p;

        else  f->rchild=p;

    }

}



// 输入一个结点值

void input_num(keyType* key)

{   

    int p=0;

    scanf("%d",&p);

    *key = p;

    //putchar(*key);

    //putchar('\n');

}



BSTree CreateBST(void)

{

    BSTree T=(BSTree)malloc(sizeof(BSTNode));

    keyType key;



    input_num(&key);



    if (key >=0)

    {

        T->key = key;

        T->lchild = NULL;

        T->rchild = NULL;

    }

    else

    {

        T->key = -1;

        T->lchild = NULL;

        T->rchild = NULL;

    }



    while (key >= 0)

    {

        InsertBST(T,key);

        input_num(&key);

    }



    return T;

}



// 产生0-1随机数

int take_bit(void)

{

    srand((unsigned)time(0));

    return rand() % 2;

}



void DelBSTNode(BSTree Tptr,keyType key)

{

    // 在二叉搜索树删除的是一个有两个子女的结点时,随机选择其中一种方案:用左子树Tl上具有最大要害码的结点,

    // 或者用右子树Tr上具有最小要害码的结点顶替,再递归地删除适当的结点,并显示删除后的遍历。



    // 搜索给定值对应的结点

    BSTNode* p = Tptr;

    BSTNode* pLMax;

    BSTNode* pLMaxFwd;

    BSTNode* pRMin;

    BSTNode* pRMinFwd;

    int rand_bit;



    while (NULL != p)

    {

        if (key == p->key)

            break;

        else if (key > p->key)

            p = p->rchild;

        else

            p = p->lchild;

    }

    if (NULL == p)

        return;



    // 搜索该结点左子树上键值最大者

    pLMaxFwd = p;

    pLMax = p->lchild;

    while (NULL != pLMax && NULL != pLMax->rchild)

    {

        // 保存当前考察结点的父结点

        pLMaxFwd = pLMax;

        // 指针移向右子树

        pLMax = pLMax->rchild;

    }



    // 搜索该结点右子树上键值最小者

    pRMinFwd = p;

    pRMin = p->rchild;

    while(NULL != pRMin && NULL != pRMin->lchild)

    {

        // 保存当前考察结点的父结点

        pRMinFwd = pRMin;

        // 指针移向左子树

        pRMin = pRMin->lchild;

    }



    // 取随机数

    rand_bit = take_bit();



    // 替换待删结点并删除相应结点

    if (0 == rand_bit)

    {

        if (NULL != pLMax)

        {

            p->key = pLMax->key;

            if (NULL != pLMax->lchild)

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = pLMax->lchild;

                else

                    pLMaxFwd->lchild = pLMax->lchild;

            }

            else

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = NULL;

                else

                    pLMaxFwd->lchild = NULL;

            }

            free(pLMax);

        }

    }

    else

    {

        if (NULL != pRMin)

        {

            p->key = pRMin->key;

            if (NULL != pRMin->rchild)

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = pRMin->rchild;

                else

                    pRMinFwd->lchild = pRMin->rchild;

            }

            else

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = NULL;

                else

                    pRMinFwd->lchild = NULL;

            }

            free(pRMin);

        }

    }

}





void InfixTraverse(BSTree Tptr)

{

    if (NULL == Tptr) return;

    InfixTraverse(Tptr->lchild);

    printf("%d ",Tptr->key);

    InfixTraverse(Tptr->rchild);

}



void main()

{

    int key=0;

    BSTree Tptr=NULL;

    printf("Please input the nords of BSTree (With -1 end):\n");

    Tptr=CreateBST();

    printf("Please input a new number as the value of node to be removed:\n");

    scanf("%d",&key);

    DelBSTNode(Tptr,key);

    printf("All nodes are:\n");

    InfixTraverse(Tptr);

    printf("\n");

}





不过运行输入删除双子女节点会出现内存不能写错误:
Please input the nords of BSTree (With -1 end):
5
3
7
2
4
8
-1
Please input a new number as the value of node to be removed:
3
All nodes are:
4

网友回复:
C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/





    // 替换待删结点并删除相应结点

    if (0 == rand_bit)

    {

        if (NULL != pLMax)

        {

            // 错误:若 pLMaxFwd == p, 则此处先行改变 pLMaxFwd 的值,将导致后续的比较失去意义

            p->key = pLMax->key;

            if (NULL != pLMax->lchild)

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = pLMax->lchild;

                else

                    pLMaxFwd->lchild = pLMax->lchild;

            }

            else

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = NULL;

                else

                    pLMaxFwd->lchild = NULL;

            }

            free(pLMax);

        }

    }

    else

    {

        if (NULL != pRMin)

        {

            // 这里错误同上所述

            p->key = pRMin->key;

            if (NULL != pRMin->rchild)

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = pRMin->rchild;

                else

                    pRMinFwd->lchild = pRMin->rchild;

            }

            else

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = NULL;

                else

                    pRMinFwd->lchild = NULL;

            }

            free(pRMin);

        }

    }





因此可以将上述赋值语句移至判定语句之后,即:

C/C code





Code highlighting produced by Actipro CodeHighlighter (freeware)

http://www.CodeHighlighter.com/





    // 替换待删结点并删除相应结点

    if (0 == rand_bit)

    {

        if (NULL != pLMax)

        {

            if (NULL != pLMax->lchild)

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = pLMax->lchild;

                else

                    pLMaxFwd->lchild = pLMax->lchild;

            }

            else

            {

                if (pLMaxFwd->key < pLMax->key)

                    pLMaxFwd->rchild = NULL;

                else

                    pLMaxFwd->lchild = NULL;

            }

            // 待删除子结点之后再交换键值

        p->key = pLMax->key;

            free(pLMax);

        }

    }

    else

    {

        if (NULL != pRMin)

        {

            if (NULL != pRMin->rchild)

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = pRMin->rchild;

                else

                    pRMinFwd->lchild = pRMin->rchild;

            }

            else

            {

                if (pRMinFwd->key < pRMin->key)

                    pRMinFwd->rchild = NULL;

                else

                    pRMinFwd->lchild = NULL;

            }

            // 待删除子结点之后再交换键值

            p->key = pRMin->key;

            free(pRMin);

        }

    }





呵呵,楼主改进的用户界面非常不错!我昨天就是折腾scanf不明白才用_getch的:)
网友回复:顶你啦~o(∩_∩)o...
非常感谢
接分啦

关键字:请教,高手,删除,二叉排序树,结点,
上一篇:初學者問題

文章评论

共有 0 位网友发表了评论 此处只显示部分留言 点击查看完整评论页面