二叉排序树C语言实现一

一、定义:

  二叉排序树(二叉搜索树、二叉查找树)或者是空树,或者满足以下性质:`

(1)若它的左子树非空,则左子树上所有记录的值均小于根记录的值;

(2)若它的右子树非空,则右子树上所有记录的值均大于根记录的值;

(3)左、右子树本身又各是一颗二叉排序树。

    ——该定义源于《数据结构》李春葆

示例:

                 

二、数据结构:

使用一个链表数据结构来表示,节点定义如下:

typedef struct STnode
{
    int key;//数据信息
    struct STnode *left;//指向左孩子
    struct STnode *right;//指向右孩子
    struct STnode *p;//指向父节点
} STnode;

三、插入操作:

二叉搜索树插入操作比较简单,将欲插入节点my_node从根节点开始比较,用cur_node表示当前被比较的节点,如果my_node.key > cur_node.key,则比较其右孩子,否则比较其左孩子,以此类推,直到找到叶节点为止,将my_node插入(大于所找到的叶节点则作为右孩子插入,小于则作为左孩子插入)。注意:插入操作一定是在叶节点上进的


示例:插入关键字为9的节点,先和根节点比较(9>6),故与其右孩子节点比较(9>7),继续与其右孩子节点比较(9>8),由于该节点为叶节点,且9>8,则将节点作为右孩子插入。


代码:

//将节点my_node插入到二叉搜索树tree
STnode* STree_Insert(STnode *tree, STnode *my_node)
{
    STnode *parent_node;//指向my_node的父节点
    STnode *cur_node;//指向当前被比较的节点
    
    //树为空
    if(tree==NULL)
        tree=my_node;
        
    //树不为空    
    else
    {
        parent_node=NULL;
        cur_node=tree;
        while(cur_node!=NULL) //while循环寻找my_node的父节点
        {
            parent_node=cur_node;
            if(my_node->key < cur_node->key)
                cur_node=cur_node->left;
            else
                cur_node=cur_node->right;
        }
        my_node->p=parent_node;
        if(my_node->key < parent_node->key)//插入到左子树
            parent_node->left=my_node;
        else                               //插入到右子树  
            parent_node->right=my_node;
    }
    return tree;
}


四、查找节点

思想比较简单,直接上代码:

//在tree里查找节点my_node
STnode *STree_Find(STnode *tree, int my_key)
{
    STnode *cur_node=tree;
    
    if(tree==NULL)
        return NULL;
    else
    {
        while(cur_node->key != my_key)
        {
            if(my_key < cur_node->key)
                cur_node=cur_node->left;
            else
                cur_node=cur_node->right;
        }
        return cur_node;
    }
}

五、返回最小关键字节点

根据二叉排序树的性质可知,关键字最小的节点一定是整棵树中最左边的节点所以只需从根节点开始一直寻找left指

针,直到找到NULL为止。

代码:

//返回最小关键字所在节点
STnode *STree_Min(STnode *tree)
{
    STnode *cur_node=tree;
    
    while(cur_node->left)
    {
        cur_node=cur_node->left;
    }
    return cur_node;
}

六、返回最大关键字所在节点

根据二叉排序树的性质可知,关键字最大的节点一定是整棵树中最右边的节点所以只需从根节点开始一直寻找right

指针,直到找到NULL为止。

代码:

//返回最大关键字所在节点
STnode *STree_Max(STnode *tree)
{
    STnode *cur_node=tree;
    
    while(cur_node->right)
    {
        cur_node=cur_node->right;
    }
    return cur_node;
}

七、查找节点后继(中序)

中序序列为:左子树、根、右子树,则一个节点若存在中序后继,则该后继必然位于该节点右边。

下图所示二叉排序树的中序为:2、3、4、6、7、13、15、17、18、20


——该图源于《算法导论》


如上所述,节点的后继一定位于节点右边,分两种情况:

1、该节点右孩子不为空:其后继必然是右子树上的最左节点(如节点6,后继为节点9);

2、该节点右孩子为NULL且该节点为其父节点的左孩子:后继为其父节点(如节点2,后继为节点3);

3、该节点右孩子为NULL且该节点为其父节点的右孩子:后继必为该节点所在“子树”根节点T的父节点,该根节点T

必为其父节点的左孩子,否则继续往上寻找(如节点13,满足该子树根节点为其父节点左孩子的子树根节点为6,

该节点为其父节点15的左孩子,故该节点后继为15)

代码:

STnode *STree_Successor(STnode *my_node)
{
    STnode *cur_node;
    STnode *successor;
    if(my_node->right)//右孩子不为空
        return STree_Min(my_node->right);
    else              //右孩子为空
    {
        if(my_node==my_node->p->left)//该节点为父节点左孩子
            return my_node->p;
        else//该节点为父节点右孩子
        {
            cur_node=my_node;
            successor=cur_node->p;
            while(successor!=NULL && cur_node!=successor->left)
            {
                cur_node=cur_node->p;
                successor=cur_node->p;
            }
            return successor;
        }
    }
}

八、查找节点前驱(中序)

查找节点前驱的算法和查找节点后继的算法对称,也分为三种情况,分析分发一样,直接上代码。

代码:

STnode *STree_Predecessor(STnode *my_node)
{
    STnode *cur_node;
    STnode *predecessor;
    if(my_node->left)//左孩子不为空
        return STree_Max(my_node->left);
    else              //左孩子为空
    {
        if(my_node==my_node->p->right)//该节点为父节点右孩子
            return my_node->p;
        else//该节点为父节点左孩子
        {
            cur_node=my_node;
            predecessor=cur_node->p;
            while(predecessor!=NULL && cur_node!=predecessor->right)
            {
                cur_node=cur_node->p;
                predecessor=cur_node->p;
            }
            return predecessor;
        }
    }
}

七、删除节点

删除节点操作是二叉排序树所有操作中最复杂最难理解的操作,在下一篇博文

(链接地址http://blog.csdn.net/xiaowang627/article/details/51336272 )中对其进行详细的图文描述

同时对所有函数进行测试。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值