算法导论10.顺序统计树与区间树习题

摘要:
顺序统计树和间隔树都是红黑树的扩展:其他功能可以通过向节点添加字段来完成。如果该字段可以在$O$时间内保持,则不会影响红黑树本身的运行效率的逐步提高。间隔树间隔树是红黑树的另一个扩展。每个元素表示一个动态间隔。红黑树使用的键值是间隔树的间隔左端的值。

顺序统计树和区间树都是对红黑树的扩张:通过在节点添加字段完成其他的功能,如果该字段可以在 $O(1)$ 时间内维护,就能够不影响红黑树本身操作效率渐进量级。

顺序统计树

顺序统计树是红黑树的扩展:在红黑树的每个节点额外维护一个域size,记录以该节点为根的子树中的总结点个数。顺序统计数具有这样的功能:在 $O(\lg n)$ 时间内找到树中所有元素的第 $i$ 个顺序量。以下是一棵顺序统计树:

算法导论10.顺序统计树与区间树习题第1张

练习14.1-4 写出一个递归过程OS-KEY-RANK(T,k)使得顺序统计树T和某个关键字k为输入,输出k的秩(排序)。

思路:简单的递归:

  • 如果关键字等于根节点,返回根节点左子树的size再加上1(这是根节点的秩);
  • 如果关键字小于根节点,返回该关键字在根节点左子树中的秩;
  • 如果关键字大于根节点,返回该关键字在根节点右子树中的秩加上左子树的size加上1。
OS-KEY-RANK(r,k)if r = nil
        return 0
    if k < key[r]
        return OS-KEY-RANK(left[r],k)
    if k > key[r]
        return OS-KEY-RANK(right[r],k)+size[left[r]]+1
    if k = key[r]
        return size[left[r]]+1

练习14.1-5 给定含有 $n$ 个元素的顺序统计树中的一个元素 $x$ 和一个自然数 $i$,如何在 $O(\lg n)$ 的时间内找到元素 $x$ 的第 $i$ 个后继?

思路:就是中序遍历,但由于每个节点有size域,所以当子树里不可能符合条件时,可以直接跳过:

  • 如果 $i=0$ 后继,直接返回 $x$ 本身;
  • 如果 $x$ 右子树size大于等于 $i$ ,说明需要找的元素在右子树中,就采取OS-SELECT(题目中没有,正文中)方法找出右子树中第 $i$ 顺序量。
  • 否则需要找的元素不在右子树中,就去找最近的祖先节点,且节点x必须在祖先节点的左子树中。对该祖先节点递归调用本方法,但是参数 $i$ 必须减去 $x$ 的右子树的size。这样理解:中序遍历中,会先遍历 $x$ 的右子树,再回到祖先节点上。
  • 如果找不到左祖先节点,说明 $i$ 太大了,树中不存在这样的后继。
OS-SUCCESSOR(x,i)
    if i = 0
        return x
    if size[right[x]] < i
        t = size[right[x]]
        while s = father[x]
        if left[s] = x
            return OS-SUCCESSOR(s,i-t)
        if s = nil
            return nil
        x = s
    if size[right[x]] >= i
        return OS-SELECT(right[x],i)

练习14.1-7 说明如何在 $O(n\lg n)$ 时间代价内,利用顺序统计树对大小为 $n$ 的数组中的逆序对计数。 

思路:按照原数组的顺序,依次插入元素,构建顺序统计树。每次插入完成一个元素 $x$ 后,通过size域计算出该元素的顺序统计量 $i$(如练习14.1-4),进而得到在这棵顺序统计树中,比 $x$ 大的节点有多少个:这部分比 $x$ 大的节点实际上就与 $x$ 构成了逆序对,因为他们在 $x$ 之前插入了顺序统计树,说明在原数组中他们排在 $x$ 的前面。每插入一个元素之后就将该数目累加起来,最后求得逆序对的数目。

练习14.1-8 一个圆上有 $n$ 条弦,每条弦都是按照端点来定义的。给出一个能在 $O(n\lg n)$ 时间内确定圆内相交弦的对数。

思路:如果将圆从某个点剪断,并拉成直线,,圆上的所有县都变成了互相平行的线段,那么相交的弦的特点是:有重叠区域。每条弦有2个顶点,左端点和右端点,为每条弦创建一个代号,然后开始遍历2n个点:

  • 如果是左端点,那么就将该端点对应的弦的代号,以左端点的位置为关键字,插入到顺序统计树中;
  • 如果右端点,那么就将该端点对应的弦的代号从顺序统计树中删除。

在每条弦被删除之前,立刻统计一下树中现存的,关键字大于该弦的元素(如练习14.1-4)个数,这就是与待删除节点相交的弦的个数,因为这些弦:关键字值大于待删除的弦,说明其左端点在待删除弦的左端点右侧;在待删除弦马上就要被删除的时候,让然还没被删除,说明其右端点在待删除节点的右侧。所有而且仅有这样的弦与待删除的弦相交。

区间树

区间树是红黑树的另一种扩展,每个元素表示一个动态区间。红黑树用到的关键字值是区间树的区间左端点值。以下是一个区间树及其所表示的区间:

算法导论10.顺序统计树与区间树习题第2张

区间树的节点还扩展了一个域max,就是以该节点为根的子树的所有区间元素的右端点的最大值。该域很容易在 $O(1)$ 时间内维护:那就是左子结点的max、右子结点的max和自身区间的右端点三者的最大值。

区间树提供一些与区间有关的操作,比如判断一个区间有没有与区间树中的任何一个区间元素有交集,判断一个点是否落在区间树中的任意一个区间元素中。

练习14.3-6 说明如何维护一个支持操作MIN-GAP的动态数集Q,该操作能够给出Q中所有元素距离最近的两个。

思路:扩展红黑树,,将Q中的元素值作为关键字,在红黑树的每个节点上维护如下三个域:

  • min-gap表示子树中所有元素,每两个元素中的最小距离;
  • min表示树中所有元素最小值;
  • max表示树中所有元素最大值。

问题的重点在min-gap域的维护上。min-gap应当这样维护:它应当是一下几个值得最小值:

  • 左节点的min-gap域
  • 右节点的min-gap域
  • 左节点max域与本节点值的差
  • 右节点min域与本节点值的差

练习14.3-7 VLSL数据库将一块集成电路表示为一个矩形,每个矩形的两边分别平行于x轴和y轴。给出一个算法,在 $O(n\lg n)$ 确定n个矩形中是否有两个有重叠区域。

思路:将n块矩形的左边界,右边界值排序为具有2n个元素的数组X,类似练习14.1-8,开始遍历X:

  • 如果遍历到的元素x为某个矩形的左边界,那么将该矩形的上下边界作为一个区间插入到区间树中;
  • 如果遍历到的元素x为某个矩形的右边界,那么将该矩形的上下边界区间从区间树中删除。

在删除区间之前,判断一下在区间树中是否有其他元素和待删除的区间有重叠区域。如果有,则找出了重叠区域。数组X已排序,并且插入和删除顺序保证了两个矩形在x轴上有重叠,而区间树保证了两个矩形在y轴上有重叠,因此两个矩阵有重叠区域。

思考题14-1 有一组区间,如何尽可能快地找到最大重叠点:即与该点有重叠区域的区间的数目最多。

思路:直观上,最大重叠点一定可以是端点,因为最大重叠点和非最大重叠点的分界,一定是某个区间具有端点造成的。这样考虑:

  1. 将所有端点组织成红黑树,增加一个域p,左节点为1,右节点为-1。
  2. 然后在节点中再维护一个域s,表示以该节点为根的子树中所有元素的p的和。某个节点的重叠数就是该节点左节点的s域:因为s表示,在这个节点上,已经开始(+1)但没有结束的(-1)的区间的个数。s域的维护也很简单,就是左子树的s加上右子树的s再加上自身的p。
  3. 最大重叠数也维护在节点中,为域m,表示以该节点为根的子树中所有元素的最大重叠数。m的维护是:m为左节点的最大重叠数、右节点的最大重叠数和自己的最大重叠数三者的最大值。

思考题14-2 Josephus环。假设n个人排成一圈,给定一个正整数m<n,从某人开始报数,遇到第m个人就让其出圈,并进行下去直到所有人出圈,给出一个算法来获得这n个人出圈的顺序。

  1. 如果m是个常数,那么在$O(n)$内。
    用环形链表也好,因为$m=O(1)$,所以直接遍历每个元素,每m次删除一个元素,获得出圈序列的一个值。
  2. 如果m不是常数,那么在$O(n\lg n)$内。
    顺序统计树最重要的意义是,可以在$O(\lg n)$时间内访问第$i$顺序量(注意$i$不是常数)。第1问中,实际上遍历了mn次,但m是常数,所以效率还是$O(n)$。而在这里,m不是常数,因此可以将所有元素组织成顺序统计树,每次访问并删除一个节点的耗费是$O(\lg n)$,总耗费就是$O(n\lg n)$。

免责声明:文章转载自《算法导论10.顺序统计树与区间树习题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇DeWeb进阶 :控件开发 --- 2 改造成DeWeb控件【计算机网络】应用层下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

将excel中的数据转为json格式

---恢复内容开始--- 用来总结工作中碰导一些错误,可以让自己在碰到相同错误的时候不至于重新走一遍。。。。        昨天导入数据的时候,碰到了一个问题是将一个大数组里面的每一个元素中的一些不要的去提出掉,本身这些元素每一个本身也是数组,然后我去遍历大数组,又去遍历小数组,然后要赋值的条件就懵了,因为是双重循环,所以后面洗澡想起来可以用一个函数去跑内...

回溯法 | 旅行商问题(TSP问题)

学习链接: 回溯法解旅行商问题(TSP)、贪心算法:旅行商问题(TSP) 今天早上做了无数个梦,然后被紧紧地吸附在床上。挣扎一番后爬起来,已经是9点了。然后我开始研究旅行商问题。 在一个无向图中找到一个可以遍历所有节点的一个最短回路。理论上说可以用全排列列出所有解的下标,然后一个一个试,时间复杂度o(n!)。但是可以用回溯法,用【约束函数】(constr...

for循环删除数组中的元素crash问题

转载请注明出处!!! 如以下代码: NSMutableArray *array = [NSMutableArray arrayWithObjects:@"2",@"3",@"4",@"9",@"4",@"12",@"22",@"4",@"4",@"5",@"6",@"1", nil]; for (NSString *str in array)...

凸包算法

包含点s集合中所有点的最小凸多边形的名字叫凸包 Graham扫描算法: 1.从y轴最低点作为起始点p0 2.从p0开始极坐标扫描,依次遍历图中所有的点,按极坐标角度大小,逆时针方向遍历 3.如果新遍历的点能产生一个左旋转,则将该点添加到凸包中,否则舍去 实现流程 1.彩色图像转灰度图像 2.灰度图像转二值图像 3.通过发现轮廓得到候选点 4.计算凸包 5...

一个可以选择目录生成doc目录内容的小工具(二)-os库目录遍历

回到一目录遍历是一个经典话题,花些功夫也很值得。(好在之前了解过)实现目录遍历的方式有三种,递归、栈、队列。递归一般是函数自己调用自己,一直到满足退出的条件。栈和队列就是数据结构,栈stack是后进先出,队列queue是先进先出。很好理解。(在python里没有这两种数据对象,实现上就是个list,看你怎么捣鼓。一般目录遍历使用递归就可以,简单快捷。感觉堆...

麻省理工公开课《算法导论》学习笔记:第一讲

主题:简介课程,渐近概念的大局观,插入排序和归并排序,递归式函数时间分析(递归树方法) 教材:《算法导论》 收获:很感动地看到算法分析那个log(n)是为什么出现了,更深层还要听第二讲,若不是因为要准备SAS,恨不得马上看。 内容: 1 何为算法分析? 计算机程序运行性能和存储空间的理论分析,叫算法分析。也就是关注2点:1 性能,就是程序跑得快不快; 2...