排序二叉树

排序二叉树

排序二叉树是一种如下定义的树:
(1)根结点的值比它的左子树上的任意一个结点的值都要大。
(2)根结点的值比它的左子树上的任意一个结点的值都要小。
(3)根的左子树和右子树也满足上述性质。
排序二叉树的先序遍历可以得到数据的升序序列。

1、排序二叉树的构造(插入)

构造排序二叉树的过程相对简单.
1 .从根结点开始,判断当前节点是否为空,若为空则执行插入操作。若非空则转第2步。
2.若根结点的值大于(小于)需要插入的值,递归根结点的左(右)孩子,转第1步。

代码实现c++

void insert_data(node *&head ,int value)
{
    if (head == NULL)
    {
        node *tree = new node;
        tree->data = value;
        head = tree;
    }
    else
    {
        if(value < head->data)insert_data(head->left, value);
        else insert_data(head->right, value);
    }
}

2、排序二叉树的删除

排序二叉树的删除相比麻烦,因为有多种情况要考虑。
(1)最简单的情况:需要删除的结点时叶子结点(没有任何孩子),则直接删除
(2)需要删除的结点有一个孩子,那么让其父结点对应的指针指向被删除结点的孩子即可。
(3)需要删除的结点有两个孩子,那么可以如下操作:在两个孩子中选择一个作为父结点,将另一个孩子放到它的子树中。

代码实现 c++

注:
(1)笔者使用了循环的方法来查找对应元素,没有使用递归。
(2)根节点和非根节点分开讨论了,所以代码有点长。
(3)关于前面的选择,笔者通过判断左孩子的右深度和右孩子的左深度,选取深度小的为新的父结点。将深度大的拼接至深度小的结点的子树中。

//该结构体用来返回深度的值和最深处的结点
struct node_and_depth
{
    struct node *a=NULL;
    int depth=0;
};
//获得结点的右深度
void letf_big_depth(node *d,node_and_depth *r)
{
    if (d == NULL)return;
    else
    {
        r->depth++;
        r->a = d;
        letf_big_depth(d->right, r);
    }
}
//获取结点的左深度
void right_small_depth(node *d,node_and_depth *r)
{
    if (d == NULL)return;
    else
    {
        r->depth++;
        r->a = d;
        right_small_depth(d->left, r);
    }
}

上面的代码如果不考虑选择的问题,可以无视。

注意,因为懒~~所以所有情况都使用return语句作为退出口(没有使用递归),可能讲究代码规范的人会很恼火。。。

struct node* delete_data(node *head,int value)//按值删除结点
{
    node *p = head;
    
    if (head==NULL)
    {
        cout<<"error :tree is empty"<<endl;
        return head;
    }
    
    node * father = NULL;//指向当前结点的父节点
    
    while (head->data != value)//通过循环找到对应节点
    {
        father = head;
        if (head->data > value)head = head->left;
        else head = head->right;
        
        if(head == NULL)
        {
            cout<<"the value is not exist "<<endl;
            return p;
        }
    }
    
    if (father == NULL)//删除的是根节点
    {
        if (head->left != NULL && head->right !=NULL)//删除的结点同时有左孩子和右孩子
        {
            struct node_and_depth *lr = new node_and_depth;
            struct node_and_depth *rr = new node_and_depth;
            letf_big_depth(head->left,lr);
            right_small_depth(head->right,rr);
            if (lr->depth >= rr->depth)//左子树深,故将左子树插入右子树的左孩子上
            {
                rr->a->left = head->left;
                p = head->right;
                delete head;
            }
            else
            {
                lr->a->right = head->right;
                p = head->left;
                delete head;
            }
            return p;
        }
        else
        {   if (head->left == NULL && head->right == NULL)
            {
                delete head;
                return NULL;
            }
            else
            {
                if (head->left != NULL)
                {
                    node *temp = head->left;
                    delete head;
                    return temp;
                }
                else
                {
                    node *temp = head->right;
                    delete head;
                    return temp;
                }
            }
        }
        
    }
    
    
    
    if (head->left == NULL && head->right == NULL)//删除的是叶子结点
    {
        if (father->left->data == head->data)//确定该节点是父节点的左孩子还是右孩子
        {
            father->left = NULL;
            delete head;
        }
        else
        {
            father->right = NULL;
            delete head;
        }
        return p;
    }
    
    
    
    if (head->left != NULL && head->right !=NULL)//删除的结点同时有左孩子和右孩子
    {
        struct node_and_depth *lr = new node_and_depth;
        struct node_and_depth *rr = new node_and_depth;
        letf_big_depth(head->left,lr);
        right_small_depth(head->right,rr);
        if (father->left == head)//确定该节点是父节点的左孩子还是右孩子
        {
            if (lr->depth >= rr->depth)//左子树深,故将左子树插入右子树的左孩子上
            {
                father->left = head->right;
                rr->a->left = head->left;
                delete head;
            }
            else
            {
                father->left = head->left;
                lr->a->right = head->right;
                delete head;
            }
        }
        else
        {
            if (lr->depth >= rr->depth)//左子树深,故将左子树插入右子树的左孩子上
            {
                father->right = head->right;
                rr->a->left = head->left;
                delete head;
            }
            else
            {
                father->right = head->left;
                lr->a->right = head->right;
                delete head;
            }
        }
        return p;
    }
    
    
    //下面是只有一个孩子的
    if (father->left->data == head->data)//确定该节点是父节点的左孩子还是右孩子
    {
        if (head->left != NULL)
        {
            father->left = head->left;
            delete head;
        }
        else
        {
            father->left = head->right;
            delete head;
        }
    }
    else
    {
        if (head->left != NULL)
        {
            father->right = head->left;
            delete head;
        }
        else
        {
            father->right = head->right;
            delete head;
        }
    }
    return p;
}

如有错误,欢迎指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值