算法导论读书笔记(16)

算法导论读书笔记(16)

目录

  • 动态顺序统计
    • 检索具有给定排序的元素

    • 确定一个元素的秩

  • 区间树
    • 步骤1:基础数据结构

    • 步骤2:附加信息

    • 步骤3:维护信息

    • 步骤4:设计新操作

动态顺序统计

之前介绍过 顺序统计
的概念。在一个无序的集合中,任意的顺序统计量都可以在 O ( n )时间内找到。而这里我们将介绍如何在
O ( lg n )时间内确定任意的顺序统计量。

下图显示的是一种支持快速顺序统计量操作的数据结构。一棵 顺序统计树 T
通过在红黑树的每个结点中存入附加信息而成。在一个结点 x 内,增加域 x.size 。该域包含以结点
x 为根的子树的(内部)结点数(包括 x 本身),即子树的大小。设 T.nil.size
为0,则有

x.size = x.left.size +
x.right.size + 1

检索具有给定排序的元素

过程 OS-SELECT(x, i) 返回一个指向以 x 为根的子树中包含第 i
小关键字的结点的指针。为找出顺序统计树 T 中的第 i 小关键字,调用过程
OS-SELECT(T.root, i)

OS-SELECT(x, i)
1 r = x.left.size + 1
2 if i == r
3 return x
4 elseif i < r
5 return OS-SELECT(x.left, i)
6 else
7 return OS-SELECT(x.right, i)

对含 n 个元素的动态集合, OS-SELECT 的运行时间为 O ( lg
n )。

确定一个元素的秩

给定指向一顺序统计树 T 中结点 x 的指针,过程 OS-RANK 返回在对
T 进行中序遍历后得到的线性序中 x 的位置。

OS-RANK(T, x)
1 r = x.left.size + 1
2 y = x
3 while y != T.root
4 if y == y.p.right
5 r = r + y.p.left.size + 1
6 y = y.p
7 return r

x 的秩可以视为在对树的中序遍历中,排在 x 之前的结点个数再加1( x
本身)。在最坏情况下,对含 n 个结点的顺序统计树, OS-RANK 的运行时间为 O
( lg n )。

区间树

在算法设计过程中,经常需要对基本的数据结构进行扩张,以便支持一些新功能。而对一种数据结构的扩张过程通常可以分为四个步骤:

  1. 选择基础数据结构

  2. 确定要在基础数据结构中添加哪些信息

  3. 验证可用基础数据结构上的基本修改操作来维护这些新添加的信息

  4. 设计新的操作

以上只是给出了一个一般模式,设计顺序统计树时,我们就依照了这些步骤。

在这里,我们要扩展红黑树以支持由区间构成的动态集合上的操作(假设区间都是闭区间)。一个 闭区间
是一个实数的有序对[ t1, t2 ],其中 t1 <=
t2 。我们可以把一个区间[ t1, t2 ]表示成一个对象,其各个域为
i.low = t1 (低端点), i.high = t2
(高端点)。任意两个区间 ii‘ 都满足 区间三分法 ,即:

  • ii‘ 重叠( i.low <= i‘.high
    ,且 i‘.low <= i.high

  • ii‘ 左边( i.high < i‘.low

  • ii‘ 右边( i‘.high < i.low

区间树是一种对动态集合进行维护的红黑树,该集合中的每个元素 x 都包含一个区间 x.int
。区间树支持下列操作:

  • INTERVAL-INSERT(t, X) :将包含区间域 int 的元素
    x 插入到区间树 T 中。

  • INTERVAL-DELETE(T, x) :从区间树 T 中删除元素 x

  • INTERVAL-SEARCH(T, i) :返回一个指向区间树 T 中元素
    x 的指针,使 x.inti 重叠;否则返回 T.nil

下面就按之前提到的四个步骤,来分析和设计区间树上的各种操作。

步骤1:基础数据结构

基础数据结构为红黑树,其中每个结点 x 包含一个区间域 x.intx
的关键字为区间的低端点 x.int.low

步骤2:附加信息

每个结点还要包含一个值 x.max ,即以 x 为根的子树中所有区间的端点的最大值。

步骤3:维护信息

必须验证对含 n 个结点的区间树的插入和删除能在 O ( lg n
)时间内完成。给定区间 x.intx 的子结点的 max 值,可以确定
x.max = max ( x.int.high ,
x.left.max , x.right.max )。

步骤4:设计新操作

唯一需要的新操作是 INTERVAL-SEARCH

INTERVAL-SEARCH(T, i)
1 x = T.root
2 while x != T.nil and i does not overlap x.int
3 if x.left != T.nil and x.left.max >= i.low
4 x = x.left
5 else
6 x = x.right
7 return x

算法导论读书笔记(16),布布扣,bubuko.com

时间: 2024-10-13 18:43:29

算法导论读书笔记(16)的相关文章

算法导论读书笔记(13)

算法导论读书笔记(13) 目录 红黑树 旋转 插入 情况1 : z 的叔父结点 y 是红色的 情况2 : z 的叔父结点 y 是黑色的,而且 z 是右孩子 情况3 : z 的叔父结点 y 是黑色的,而且 z 是左孩子 删除 情况1 : x 的兄弟 w 是红色的 情况2 : x 的兄弟 w 是黑色的,且 w 的两个孩子都是黑色的 情况3 : x 的兄弟 w 是黑色的, w 的左孩子是红色的,右孩子是黑色的 情况4 : x 的兄弟 w 是黑色的,且 w 的右孩子是红色的 红黑树 红黑树 是一种二叉查

算法导论读书笔记(18)

算法导论读书笔记(18) 目录 最长公共子序列 步骤1:描述最长公共子序列的特征 步骤2:一个递归解 步骤3:计算LCS的长度 步骤4:构造LCS LCS问题的简单Java实现 最长公共子序列 某给定序列的子序列,就是将给定序列中零个或多个元素去掉后得到的结果.其形式化定义如下:给定一个序列 X = < x1 , x2 , - , xm >,另一个序列 Z = < z1 , z2 , - , zk >,如果 Z 满足如下条件则称 Z 为 X 的 子序列 (subsequence),

算法导论读书笔记之钢条切割问题

算法导论读书笔记之钢条切割问题 巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo) 给定一段长度为n英寸的钢条和一个价格表 pi (i=1,2, -,n),求切割钢条的方案,使得销售收益rn最大.注意,如果长度为n英寸的钢条价格pn足够大,最优解可能就是完全不需要切割. 若钢条的长度为i,则钢条的价格为Pi,如何对给定长度的钢条进行切割能得到最大收益? 长度i   1   2    3   4     5      6     7     8  

算法导论读书笔记(15) - 红黑树的具体实现

算法导论读书笔记(15) - 红黑树的具体实现 目录 红黑树的简单Java实现 红黑树的简单Java实现 /** * 红黑树 * * 部分代码参考自TreeMap源码 */ public class RedBlackTree<T> { protected TreeNode<T> root = null; private final Comparator<? super T> comparator; private int size = 0; private static

算法导论读书笔记(17)

算法导论读书笔记(17) 目录 动态规划概述 钢条切割 自顶向下的递归实现 使用动态规划解决钢条切割问题 子问题图 重构解 钢条切割问题的简单Java实现 动态规划概述 和分治法一样, 动态规划 (dynamic programming)是通过组合子问题的解而解决整个问题的.分治法是将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原问题的解.与此不同,动态规划适用于子问题并不独立的情况,即各子问题包含公共的子子问题.在这种情况下,分治法会重复地求解公共的子子问题.而动态

算法导论读书笔记(14) - 二叉查找树的具体实现

算法导论读书笔记(14) - 二叉查找树的具体实现 目录 二叉查找树的简单Java实现 二叉查找树的简单Java实现 /** * 二叉查找树 * 部分代码参考自TreeMap的源码 */ public class BinarySearchTree<T> { protected TreeNode<T> root = null; private final Comparator<? super T> comparator; private int size = 0; pub

算法导论读书笔记-第十四章-数据结构的扩张

算法导论第14章 数据结构的扩张 一些工程应用需要的只是标准数据结构, 但也有许多其他的应用需要对现有数据结构进行少许的创新和改造, 但是只在很少情况下需要创造出全新类型的数据结构, 更经常的是通过存储额外信息的方法来扩张一种标准的数据结构, 然后对这种数据结构编写新的操作来支持所需要的应用. 但是对数据结构的扩张并不总是简单直接的, 因为新的信息必须要能被该数据结构上的常规操作更新和维护. 14.1 动态顺序统计 顺序统计树(order-static tree) : 在红黑树的基础上, 在每个

平摊分析 --- 算法导论读书笔记

我们经常会说一个算法快不快,这个可以由实验得出,也可以通过分析复杂度得出.实验需要大量不同的输入才更全面准确,否则片面地看某个输入下的表现,是比较偏颇的.分析复杂度(通常分析最坏,因为平均涉及输入的概率分布,依靠假设或者实验和经验)有时候并不是一个简单的事,简单的情况是遍历 for(int i = 0; i != n; i++) 的这种情况,显然是O(n)的复杂度.但是一些复杂的情况就比较难办了,举例来说: a.   栈操作:  除了PUSH,POP,添加一个操作叫MULTIPOP. MULTI

字符串匹配问题 ---- 算法导论读书笔记

字符串匹配是一个很常见的问题,可以扩展为模式的识别,解决字符串问题的思想被广泛地应用.介绍四种解决该问题的办法,包括:最朴素的遍历法,Rabin-Karp算法,自动机机匹配,Knuth-Morris-Pratt算法即耳熟能详的KMP. 在一开始,先对时间复杂度做出一个总扩(从大到小):[1]朴素法:O( (n-m+1)m ):[2]Rabin-Karp:预处理:O(m),匹配:最坏O( (n-m+1)m ),但是平均和实际中比这个好得多:[3]自动机:预处理O(m|Σ|),匹配O(n):[4]K