二叉查找树与平衡树简介

在信息奥赛中,我们常常会遇到序列中的元素查找问题。有时候二分查找就能满足需要,但是当题目附加插入与删除操作时,二分查找便显得不那么灵活。这时候,我们就要用到二叉查找树(又称二叉排序树)来进行查找。

一、二叉查找树

二叉查找树的主要特征为:

对于每一个节点:

(1)若其左子树不空,则其左子树上所有结点的值均小于该结点的值;

(2)若其右子树不空,则其右子树上所有结点的值均大于该结点的值;

(有时可变为小于等于或大于等于,根据实际情况而定,本文忽略此种情况)

由于以上特点,二叉查找树的中序遍历是有序的。我们根据其特性对于二叉查找树进行操作。

1、查找节点

由于以上特征,二叉查找树的查找操作与二分查找十分相似。从根节点开始:

(1)若该节点值等于所查的值,查找成功。

(2)若该节点值小于所查的值,递归查找左子树。

(3)若该节点值大于所查的值,递归查找右子树。

(4)在(2)(3)环节中,若子树为空,则查找失败。

2、插入节点

二叉查找树的插入节点操作在查找节点的操作上进行。

(1)将节点的值带入“查找节点”操作,直至遇到情况(4)。

(2)将该节点填入空子树的位置。

下面附上插入操作的代码。

struct node
{
    int ch[2];//ch[0]为左子树,ch[1]为右子树
    int val;//节点值
}t[maxn];//定义二叉查找树节点
int cnt;
void insert(int num,int h)//插入值、当前节点
{
    if((num>t[h].val&&!t[h].ch[1])||(num<t[h].val&&!t[h].ch[0]))//查找的子树为空
    {
        t[++cnt].val=num;
        t[h].ch[num>t[h].val]=cnt;//简化写法
    }//新建节点
    else insert(num,t[h].ch[num>t[h].val]);//继续查找
}

3、删除节点

二叉查找树的删除操作较为复杂,在信息奥赛中也没有必要使用此种写法,常用平衡树的删除操作代替。具体内容详见后文。

由上我们可以看见,二叉查找树在查找方面兼具速度与灵活性。在理想情况下,查找与插入一个值的时间复杂度为O(log2n),与二分查找相当。

二、平衡树

在上文中提到,二叉查找树的“理想情况”可以达到O(log2n),那么实际情况呢?在比赛中,有时候出题者会故意生成一些数据,如1、2、3、5、7、9……的递增序列,在这种情况下,二叉查找树的发挥十分不理想,特别是当序列单调递增或递减时,其与链表没有区别,时间复杂度回到了O(n),效率极低,这是我们都不愿意看到的。而平衡树,就是对二叉查找树进行调整,使其保持性质的情况下,降低层数,提高时间效率,在多数情况下能使时间复杂度保持在接近O(log2n)级别的一种数据结构。

平衡树的常见种类有treap、splay、SBT、AVL、红黑树等,由于后两种编程难度较大,在信息奥赛中一般只需掌握前三种。关于详细介绍会在后面的博客中提到。

平衡树不仅可以解决二叉查找树的时间效率问题,根据它们自身的特性,它们不仅拥有诸如分裂、合并等一般二叉查找树几乎无法完成的功能,而且还可以超越二叉查找树的范畴,进行序列维护等强大的操作。相信这种数据结构会对解题带来十分巨大的帮助。

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/xffyjq/article/details/52204405
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞