《算法导论》实验七:区间树上的重叠区间查找算法(C++)——控制台树型显示

一、题目描述

区间树(interval tree)是一种对动态集合进行维护的扩张红黑树,因此可在实验二红黑树的基础上进行扩张。为此,本实验(实验三)在实验二的基础上对红黑树的节点增加新的附加信息,并设计新的操作。从而熟悉并实现区间树上的重叠区间查找算法,分析该算法的性能。
具体问题测试用例:尝试构造一个区间树。可依次插入下列区间:[41,49] [38,44] [31,35] [12,20] [19,25] [8,10]
查找重叠区间:“find [37,40]”、“find[9,30]”、“find [26,29]”

二、算法分析与设计

(一)基本概念:
区间:一个事件占用的时间;
闭区间:实数的有序对[low,high],使low≤high
区间的对象表示:[low,high]可以用对象interval表示,有两个属性:
low[interval]=t1 //起点或低点;
high[interval]=t2 //终点或高点。
区间的重叠:interval∩interval’≠∅⇔(low[interval]≤high[interval’]) and (low[interval’]≤high[interval])

(二)数据结构:本质上是将红黑树扩充,方法如下:
Step 1:基本结构:
以红黑树为基础,对∀x∈T,x包含区间interval[x]的信息(低点和高点),key=low[interval [x]]。
Step 2:附加信息:
max[x]=max(high[interval [x]], max[left[x]], max[right[x]])
Step 3:维护附加信息(有效性):
在新节点的插入时进行Step2的计算,此外要注意在左旋和右旋时也要对max值进行维护,这是与基本红黑树的左右旋很大不同的地方。
Step 4:开发新操作:查找与给定区间重叠的区间节点x。

(三)查找算法IntervalSearch(T, i)基本思想:
step 1:x ←root[T]; //从根开始查找
step 2:若x≠nil[T]且i与int[x]不重叠
if x的左子树非空且左子树中最大高点≥low[i] then
x ←left[x];//到x的左子树中继续查找
else
x ←right[x];//左子树必查不到,到右子树查
step 3:返回x //x=nil or i和x重叠
由于区间树是红黑树的简单扩重,因此区间树相关操作的实现如左旋、右旋、插入,插入调整等与红黑树基本相同,这些在实验二有详细的描述,此处就不再赘述。但要在左旋和右旋的操作中维护max域的取值。

(四)查找具有最小低端点的重叠区间算法IntervalSearchMin()的基本思想:
采用递归思想,递归先从左子树找;递归到整个树的最左端,从第一个区间开始匹配,如果x与interval重叠,就不需要往下找了;若左子树找不到,则在右子树上找。

三、实验结果与分析

(一)首先,初始化区间树,依次插入下列区间:[41,49] [38,44] [31,35] [12,20] [19,25] [8,10],在树状显示的代码中稍作修改,再在控制台中树形显示区间树,如下图-1所示:
这里写图片描述
图-1 初始化区间树并树形显示

(二)情况一:查找重叠区间[37,40]:“find [37,40]”
输出结果:最先找到的重叠区间和具有最小低端点的重叠区间相同,均为[38,44]。如下图-2所示:
这里写图片描述
图-2 查找重叠区间[37,40]:“find [37,40]”

(三)情况二:查找重叠区间[9,30]:“find [9,30]”
输出结果:因为此时存在多个重叠区间,所以最先找到的重叠区间和具有最小低端点的重叠区间不同,最先找到的重叠区间为[19,25];具有最小低端点的重叠区间为[8,10]。如下图-3所示:
这里写图片描述
图-3 查找重叠区间[9,30]:“find [9,30]”

(四)情况三:查找重叠区间[26,29]:“find [26,29]”
输出结果:因为没有与区间[26,29]重叠的区间,所以显示“Output:无重叠区间”。如下图-4所示:
这里写图片描述
图-4 查找重叠区间[26,29]:“find [26,29]”

四、实验总结

1、区间树是红黑树的扩张,大部分操作跟红黑树相同或相似,但在对附加信息max进行维护时,左旋和右旋的过程中要对max单独进行更新维护。
2、通过测试证明查找算法是正确有效的。
3、用递归的思想可实现查找具有最小低端点的重叠区间。
4、对于任意一个具有n个结点的区间树,我们最多需要循环logn+2次,(即从根节点查找到叶子结点),每次循环都是常数时间,故在最坏情况下时间复杂度为O(log n)。在一个比较差的搜索中,假设每次我们寻找的区间都是叶子结点,在这个情况下的时间复杂度为Ω(log n)。所以区间树上的重叠区间查找算法的时间复杂度为Ɵ(log n)


五、源代码(C++)

/* 
区间树(interval tree)是一种对动态集合进行维护的扩张红黑树,因此可在实验二红黑树的基础上进行扩张。
*/  

#include <iostream>
#include <deque>
#include <iomanip>
#include <sstream>
#define SENTINEL -100000    //哨兵,作为nil结点的key,方便树状输出时临界点判断
using namespace std;


enum Color{RED=0,BLACK=1};  //定义枚举类型,即红黑树结点颜色类型,0表示红色,1表示黑色

typedef struct Interval     //定义一个表示区间范围的结构体
{
    int low;                //区间的低端点(low endpoint)
    int high;               //区间的高端点(high endpoint)
}Interval;

typedef struct Node        //声明红黑树结点
{
    Color color;           //红黑树结点的颜色类型,
    struct Node *parent;   //父节点
    struct Node *left;     //左孩子
    struct Node *right;    //右孩子
    Interval interval;     //区间
    int max;               //附加信息,记录以该节点为根的子树中所有区间端点的最大值
}Node;

typedef struct RBTree      //定义一个红黑树
{
    Node *root;            //根节点
    Node *nil;             //哨兵结点,避免讨论结点的边界情况
}RBTree;

//选择显示
void Display()             
{
    cout<<"************************************************************************\n";
    cout<<"****           请选择您要的红黑树操作!!                           ****\n";
    cout<<"****   I:插入区间    D:区间树当前状态   S:查找区间    E:退出    ****\n";
    cout<<"****   Insert         Display             Search         Exit       ****\n";
    cout<<"************************************************************************\n";
}

//求三个参数中的最大值
int GetMax(int high,int leftMax,int rightMax)     
{
    int temp=(leftMax>rightMax)?leftMax:rightMax;
    return (high>temp)?high:temp;
}

//左旋,结点x原来的右子树y旋转成x的父母
void LeftRotate(RBTree * rbTree,Node *x)
{
    if(x->right!=rbTree->nil)
    {
        Node *y=x->right;
        x->right=y->left;
        if(y->left!=rbTree->nil)
        {
            y->left->parent=x;
        }
        y->parent=x->parent;
        if(x->parent==rbTree->nil)    //空树,将y设为根
        {
            rbTree->root=y;
        }
        else if(x==x->parent->left)   //x为左子树,将y放在x父节点的左子树
        {
            x->parent->left=y;
        }
        else
        {
            x->parent->right=
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值