• 算法导论第十四章:数据结构的扩张


        在应用工程中,需要在现有的数据结构上有所创新,但很少需要创造出全新的数据结构。通常情况下,只要向标准的数据结构中增加一些信息即可。可以对数据结构编入新的造作,以支持所需的应用。但是,数据结构的扩张并不总是轻而易举的,附加的信息需要能为该数据结构的常规操作所更新和维护。这一章讨论通过扩展红黑树构造的数据结构。

    动态顺序统计

       第9章介绍了顺序统计的概念,在一个无序的集合中,任意的顺序统计量都可以在O(n)时间内找到。在这一节里,将介绍如何修改红黑树的结构,使得任意的顺序统计量都可以在O(lgn)时间内确定。

    一棵顺序统计量树T通过简单地在红黑树的每个结点存入附加信息而成。在一个结点x内,除了原有的域,还包括size[x],这个域包含以结点x为根的子树的节点数:
    Size[x] = size[left[x]] + size[right[x]] +1

    检索具有给点排序的元素算法如下,只要调用OS-SELECT(root[T],i):
    OS-SELECT(x, i)
    1     r = size[left[x]]+1
    2     if i = = r
    3     then return r
    4     Else if i<r
    5     Then return OS-SELECT(left[x],i)
    6     Else return OS-SELECT(right[x],i-r)

    确定一个元素的秩:
    OS-RANK(T, x)
    1     r = size[left[x]]+1
    2     y = x
    3    while y != root[T]
    4    do if y==right[p[y]]
    5    then r = r+size[left[p[y]]]+1
    6    y = p[y]
    7    return r

    对子树规模的维护:
    给点每个结点的size域后,OS-SLELECT和OS-RANK能迅速地计算出所需的顺序统计信息。然而,除非能够用红黑树上基本的修改操作对这些size域加以有效的维护,否则,就达不到期望的目的。
    插入结点:在寻找插入位置的过程中,所经路径上的结点size域都需加1
    旋转:如果插入结点后,需要旋转某些结点,可以验证,可以在常数时间内更新相关结点的size域。

    如何扩张数据结构

    对一种数据结构进行扩张,一般分为四个步骤
    1 选择基础数据结构
    2 确定选取什么信息作为关键字,选取什么信息作为附加字段,这些选择取决于设计目的
    3 验证可在数据结构的常规操作中来维护新加的信息,一般来说如果某个信息只直接依赖于其子节点的信息的话,维护某个节点该信息只需要常数时间。
    4 设计新的操作

    以上节的顺序统计树为例,我们不是在结点中存储顺序统计量,而是存储子树的节点数,这是因为前者很难维护。而有了后者我们也可以在较快时间lgn内得出顺序统计量。

    区间树:

    一个闭区间是一个实数的有序对[t1,t2],其中t1<=t2。区间可以很方便第表示占用连续时间的事件。我们可以把一个区间[t1,t2]表示成一个对象i,其各个域为low[i]=t1,high[i]=t2。两个区间i和j满足一下三种关系之一:
    1 重叠
    2 i在j左边,即high[i]<low[j]
    3 i在j右边,即high[j]<low[i]

    我们需要维护一个动态区间集合,并能迅速找到与某个已知区间重叠的集合元素。


    先按上节所述的方法来构造区间树:
    1 基础数据结构
        选择红黑树,其中每个结点x包含区间域int[x],关键字为区间的低端点low[int[x]]。这样对树进行中序遍历就可以按低端点的次序输出区间。
    2 附加信息
        每个结点除了区间信息之外,还包含一个值max[x],即以x为根的子树所有区间的端点的最大值。
    3 对信息的维护
        验证对max域的维护能在常规的插入、删除操作中完成:
        max[x] = max( high[int[x]], max[left[x]], max[right[x]]),这样更新max域只需要常数时间。
    4 新的操作
    INTERVAL-SEARCH(T, i)
    1.    x  root[T]
    2.    while x!=nil[T] and i dose not overlap int[x]
    3.    do if left[x] != nil[T] and max[left[x]]>=low[i]
    4.    then x left[x]
    5.    else x right[x]
    6.    return x


    上述算法的关键点在于第3-5行的选择,在结点x与i不重叠前提下,如果x存在左树,且左子树的最大端点大于i的低点,则往左子树搜寻:这个选择是正确的,应为如果在这种条件下左子树中不存在和i重叠的结点,右子树种也不会存在。因为max[left[x]]>=low[i],左子树中必然存在某结点y,high[y]>=low[i],如果y与i不重叠,则有low[y]>high[i],则x右子树的所有结点的低端都大于high[i]。

  • 相关阅读:
    点评cat系列-服务器开发环境部署
    [FreeRTOS].FreeRTOS CortexM3 M4中断优先级设置总结
    [FreeRTOS]FreeRTOS使用
    [Ethernet].以太网总线详解
    [USB].USB总线详解
    [CAN].CAN总线详解
    [LIN].LIN总线详解
    [SDIO].SDIO总线详解
    [eMMC]eMMC读写性能测试
    [通信]Linux User层和Kernel层常用的通信方式
  • 原文地址:https://www.cnblogs.com/longhuihu/p/10423364.html
Copyright © 2020-2023  润新知