二叉排序树C语言实现二

在上一篇文章中(http://blog.csdn.net/xiaowang627/article/details/51332201),对二叉排序树的定义和查找、插入等操作进行了图文描述和C语言实现,本文将详解二叉搜索树的删除操作。

一、节点删除:如下图所示


(1)删除叶节点(2、4、9、20):直接删除

(2)删除的节点只有一个孩子(左孩子或右孩子)(7、13):将这个节点的孩子提升替换该节点即可


如图所示,删除节点7:


(3)删除的节点有两个孩子节点(6、15、18)。需要保证删除该节点后仍然满足二叉排序树的性质,则必须要用该节点的中序后继替换该节点!再对该节点和替换节点的子树进行处理。

根据求节点中序后继的算法,一个节点的中序后继为该节点右子树上的最左节点,该后继节点必不存在左孩子,考虑两种情况,a、该后继节点为其右孩子(如节点6后继节点7为其右孩子);b、该后继节点不为其右孩子(如节点15,其后继节点17不为其右孩子)

情况a:直接将后继节点替换该节点,如下图删除节点6:


情况b:先用后继节点右孩子替换该后继节点,再用后继节点替换源节点,如下图删除节点15


综上所述,将删除节点my_node的情形总结为以下几种:

1、my_node为叶节点

2、my_node仅有一个孩子

      2.1、my_node有仅左孩子

      2.2、my_node仅有右孩子

3、my_node既有左孩子又有右孩子

     3.1、my_node后继为my_node->rchild(my_node->rchild无左孩子)

     3.2、my_node后继不为my_node->rchild(my_node->rchild有左孩子)


代码:(此处代码以个人理解的通俗方式书写,可能比较冗长,有较大优化空间)

STnode *STree_Delete(STnode *tree, STnode *my_node)
{
    STnode *parent=my_node->p;
    STnode *suc_parent;
    STnode *successor;
    
    if(my_node->left==NULL && my_node->right==NULL)//叶节点
    {
        if(parent==NULL)//只有一个节点
            return NULL;
            
        if(my_node==parent->left)
            parent->left=NULL;
        else
            parent->right=NULL;
    }
    else if(my_node->left && my_node->right==NULL)//仅有左孩子
    {
        if(parent==NULL)//删除根节点
        {
            return tree->left;
        }
        
        if(my_node==parent->left)
        {
            parent->left=my_node->left;
            my_node->left->p=parent;
        }
        else
        {
            parent->right=my_node->left;
            my_node->left->p=parent;
        }
    }
    else if(my_node->left==NULL && my_node->right)//仅有右孩子
    {
        if(parent==NULL)//删除根节点
        {
            return tree->right;
        }
        
        if(my_node==parent->left)
        {
            parent->left=my_node->right;
            my_node->right->p=parent;
        }
        else
        {
            parent->right=my_node->right;
            my_node->right->p=parent;
        }
    }
    else//有两个孩子
    {
        successor=STree_Successor(my_node);
    
        if(successor == my_node->right)//my_node后继为my_node->rchild
        {
            if(my_node==parent->left)
            {
                parent->left=successor;
                successor->p=parent;
                successor->left=my_node->left;
            }
            else
            {
                parent->right=successor;
                successor->p=parent;
                successor->left=my_node->left;
            }
        }
        else //my_node后继不为my_node->rchild
        {
            suc_parent=successor->p;
            suc_parent->left=successor->right;
            successor->right->p=suc_parent;
            
            successor->right=my_node->right;
            successor->left=my_node->left;
            successor->p=my_node->p;          
        }
    }
    if(parent==NULL)//删除根节点
        return successor;
     else
        return tree;
}


二、主函数,测试用例及其头文件等

#include <stdio.h>
#include <stdlib.h>
typedef struct STnode
{
    int key;//数据信息
    struct STnode *left;//指向左孩子
    struct STnode *right;//指向右孩子
    struct STnode *p;//指向父节点
} STnode;
STnode* STree_Insert(STnode *tree, STnode *my_node);
void STree_Inorder(STnode *tree);
STnode *STree_Creat(STnode *tree, int arr[], int n);
STnode *STree_Find(STnode *tree, int my_key);
STnode *STree_Max(STnode *tree);
STnode *STree_Min(STnode *tree);
STnode *STree_Successor(STnode *my_node);
STnode *STree_Predecessor(STnode *my_node);
STnode *STree_Delete(STnode *tree, STnode *my_node);

int main(void)
{
    int i;
    int arr[]={15,6,20,3,7,17,21,4,13,19,9};
    STnode *tree=NULL;
    STnode *p;
     
    tree=STree_Creat(tree, arr, 11); 
    
    STree_Inorder(tree);
    printf("\n");
    
    p=STree_Find(tree, 7);
    printf("find the key: %d\n",p->key);
    
    p=STree_Max(tree);
    printf("the max key: %d\n", p->key);
    
    p=STree_Min(tree);
    printf("the min key: %d\n",p->key);
    
    p=STree_Successor(STree_Find(tree, 7));
    printf("the successor of 7 is %d\n",p->key);
    
    p=STree_Predecessor(STree_Find(tree, 7));
    printf("the predessor of 7 is %d\n",p->key);
    
    //以下三组删除操作在同一颗树上连续进行;
    p=STree_Delete(tree, STree_Find(tree, 4));
    printf("delete the leaf node 4:");
    STree_Inorder(p);
    printf("\n");
    
    p=STree_Delete(tree, STree_Find(tree, 20));
    printf("delete the node 20 which only have left child:");
    STree_Inorder(p);
    printf("\n");
    
    p=STree_Delete(tree, STree_Find(tree, 7));
    printf("delete the node 7 which only have right child:");
    STree_Inorder(p);
    printf("\n");
    
    //重置二叉排序树,实验删除节点6和15
    tree=NULL;
    tree=STree_Creat(tree, arr, 11); 
    
    p=STree_Delete(tree, STree_Find(tree, 6));
    printf("delete the node 6 which have two children:");
    STree_Inorder(p);
    printf("\n");
    
    p=STree_Delete(tree, STree_Find(tree, 15));
    printf("delete the node 15 which have two children:");
    STree_Inorder(p);
    printf("\n");
    
    return 0;
}



  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的二排序的 C 语言实现: ``` #include <stdio.h> #include <stdlib.h> // 定义二节点 struct Node { int data; struct Node* left; struct Node* right; }; // 创建一个新的节点 struct Node* newNode(int data) { struct Node* node = (struct Node*)malloc(sizeof(struct Node)); node->data = data; node->left = NULL; node->right = NULL; return node; } // 插入节点到二排序 struct Node* insert(struct Node* node, int data) { // 如果为空,则创建一个新节点并返回 if (node == NULL) { return newNode(data); } // 否则,递归地向下移动,直到找到一个合适的位置插入新节点 if (data < node->data) { node->left = insert(node->left, data); } else if (data > node->data) { node->right = insert(node->right, data); } // 返回插入后的根节点 return node; } // 中序遍历二排序 void inorderTraversal(struct Node* node) { if (node != NULL) { inorderTraversal(node->left); printf("%d ", node->data); inorderTraversal(node->right); } } // 测试二排序 int main() { struct Node* root = NULL; root = insert(root, 50); insert(root, 30); insert(root, 20); insert(root, 40); insert(root, 70); insert(root, 60); insert(root, 80); // 输出排序后的节点 printf("排序后的节点:\n"); inorderTraversal(root); printf("\n"); return 0; } ``` 这个程序创建了一个二排序,并插入了一些节点,最后输出了排序后的节点。你可以根据需要进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值