Van Emde Boas Trees
## 介绍 ##
van Emde Boas trees 支持所有优先级优先级队列的操作,并且巧妙的是它对于SEARCH, INSERT,DELETE,MINIMUM,MAXMUN,SUCCESSOR,和PREDECESSOR这些操作的支持都在最坏复 杂度O(lglgn)之内。不过有些限制的是,所有的Kye值都必须在 0…n−1之间,且不能有重复值。换言之,他的算法复杂度不由数据的规模 有多 大而决定,而由key值的取值范围而决定。
算导上这一章的讲述方式我非常喜欢,循序渐进,从最基础最简单的一个结构开始,最终 演化成Van Emde Boas trees,这样的方式更能让人捕捉到发明人思路发展的一个演变过 程,毫无疑问,这一章得多记点笔记。
## 基础方法 ##
这部分会有三种方法来存储动态集合,尽管它们没有一个能达到O(lglgu), 但是通过这三种方法却能让我们得到理解Van Emde Boas trees的真知灼见
## Direct Address ##
Direct Addressing提供一种最简单的方法来存储一组数据。Direct Addressing直接用 一个大小为u的位数组A[0..u−1]来存储这组属于集合{0,1,2,…,u−1}的数。如果这组数中有x,那么A[x]的值存1, 否则存0。
这种简单粗暴的方法,显然不能达到预期。对于INSERT、DELETE、MEMBER这些操作复杂 度在O(1)内。而对于MINIMUM、MAXMIMUM、SUCCESSOR、PREDECESSOR这些操作 每一个都要θ(u)。我们不妨对Direct Addressing进行改进一下。几个 θ(u)的操作皆因必须对数组进行迭代才能得到结果的缘故。那么如果我 们在Direct Addressing之上建立一棵二叉树想必有所改善。
## Superimposing a binary tree structure ##
二叉树中的结点存储着0或1,当两个孩子中有一个为1时它为1,只有当两个孩子都为0 的时候它才为0。
在Direct Addressing中花费θ(u)的操作,依赖于这棵二叉树现在都有了 一个更低的上限O(lgu)。但这个上限还并不理想,不然我们不如使用一棵 红黑树,好歹人家还是O(lgn)的上限。如果把这棵树的高度降低,说不定 是一个突破口,姑且试试。
## Superimposing a tree of constant height ##
要降低树的高度,我们可以直接通过增加树的度数来实现,将二叉树将变为多叉树。假 设全域的大小是u=22k,其中k是一个整数,那么u√ 也是一个整数。
和在位数组上建立一棵二叉树不同,现在我们在位数组上建立一棵度数为u√ 的树,如下图(a)。这棵树的高度是2。树中的每个结点存储了各子树的逻辑与结果。
如下图(b)所示,可以将那些结点看作是一个数组summary[0..u√−1],当 且仅当A[iu√..(i+1)u√−1]含1,summary[i]才为1。
我们把A中的u√位的子数组称为簇,对于一个给定值x, 位A[x]存在于第⌊x/u√⌋个簇中。现在INSERT将在 O(1)内完成——对于插入一个x,分别将A[x]和⌊x/u√⌋设为1。对于MINIMUM、MAXIMUM、SUCCESSOR、PREDECESSOR和 DELETE这些操作将花费O(u√)。具体操作不做赘述。
比起Superimposing a binary tree,现在的结构似乎反而更糟了,前者最差劲的操作 也只要lgu,现在都要u√了,但是透过这个结构带来了一点 新的想法,如果我们把数组summary也变作一个Superimposinga tree of constant height怎么样,一路递归下去情况会如何?
## A recursive structure ##
前面用u√度数的树给了我们一个启示,假如我们能够把问题的规模以开平 方的规模缩小的话,会有一个什么效果?假设我们能做到以开平方的规模递归减小一个 数据结构的规模,而且每个操作在每一级递归上只产生一次新的递归调用,那么 对于一 个大小为u的数据结构的操作有: [ T(u) = T(\sqrt{u}) + O(1) ] 令m=lgu, 有u=2m。那么可以有: [ T(2^m) = T(2^{m/2}) + O(1)] 设S(m)=T(2m),可得新方程: [ S(m) = S(m/2) + O(1)] 可以得出S(m)=O(lgm),回到T(u)上来,那么 T(u)=T(2m)=S(m)=O(lgm)=O(lglgu)。
这个假设说明如果我们能够以递归方式以开平方的规模来缩小数据的规模大小,并在每 一级递归上花费O(1)的时间的话,我们这个假设的数据结构的操作的复杂度将 是O(lglgu)。
围绕方程 T(u)=T(u√+O(1)),我们来设计一个递归的数据结构,以开 平方的规模来减小每一次递归的大小。当然,我们可能不能一步达到让所有的操作都达 到O(lglgu),但是我们还是可以先设计出一个原型。自u起,我们 用一个u√=u1/2项的数据结构来持有u1/4项的,以 u1/4项的递归持有u1/8项的,以u1/8项的递归持有 … u=22k,如此,u1/2,u1/4,u1/8,…都为整数。
对于一个全域为{0,1,2,…u−1}的van Emde Boas数据结构为原 型,我们简称为proto-vEB(u)。它遵循以下这些规则:
如果u=2,那么已是基础大小,那么它包含两个标志位A[0…1]
否则,u=22k, 且整数k≥1, 所以u≥4, 这时,proto-vEB(u)包含两个属性:
一个名为summary指向proto-vEB(u√)的指针。
一个u√大的指针数组cluster[0…1],其中每一个指 针指向一个proto-vEB(u√)。
如果cluster的第i个指针所指向的的集合含有元素,那么i也存在于summary所指向 的集合中,否则i也不存在于summary中。
对于一个u=16的集合{2,3,4,5,7,14,15}情况就是 下面这样的:
在proto-VEB(u)中,一个给定值x,那么他应该储存在proto-VEB(u)中cluster的 第⌊x/u√⌋个指针指向的proto-VEB(u√) 的第xmodu√个值。鉴于此,在分析各项操作之前,先定义几个有用 的工具函数: [ high(x) = \lfloor{x} / \sqrt{u} \rfloor ] [ low(x) = x \mod \sqrt{u} ] [ index(x, y) = x\sqrt{u} + y ]
## 判断一个值是否存在 ##
PROTO-VEB-MEMBER(V, x)if V.u == 2return V.A[x]elsereturn PROTO-VEB-MEMBER(V.cluster[high(x)], low(x))
## 找最小值 ##
从summary中得到最小值i,那么最小值必定存在于cluster[i]所表示的集合中, 在从cluster[i]表示的集合中得到最小值,结合i值可以得到全局的最小值。伪 码:
PROTO-VEB-MINIMUMN(V)if V.u == 2if V.A[0] == 1return 0else if V.A[1] == 1return 1elsereturn NILelsemin-cluster = PROTO-VEB-MINIMUM(V.summary)if min-cluster == NILreturn NILelseoffset = PROTO-VEB-MINIMUN(V.cluster[min-cluster])return index(min-cluster, offset)
复杂度 [ T(u) = 2T(\sqrt u) + O(1)] 设u=2m [ T(2^m) = 2T(2^{m/2}) + O(1)] 设S(m)=T(2m),得: [S(m) = 2S(m/2) + O(1)] [T(u) = S(m) = \theta(m) = \theta(lg u)]
## 找X的后继 ##
1.从x所在的子集中找后继
2.找不到的话,先从summary中得到下一个子集的索引,从下一个子集中找最小值。
3.转换成全局的值。
PROTO-VEB-SUCCESSOR(V, x)if V.u == 2if x == 0 and V.A[1] == 1return 1else return NILelseoffset = PROTO-VEB-SUCCESSOR(V.cluster[high(x)], low(x))if(offset != NIL)retuen index(high(x), offset)elsesucc-cluster = PROTO-VEB-SUCCESSOR(V.summary, high(x))if succ-cluster != NILoffset = PROTO-VEB-MINIMUM(V.cluster[succ-cluster])return index(succ-cluster, offset)elsereturn NIL
复杂度: [ T(u) = 2T(\sqrt u) + \theta(\lg{\sqrt u})] [ = 2T(\sqrt u) + \theta(\lg u)] 用与前文类似的方法可以化得T(u)=θ(lgulglgu)
## 插入元素 ##
一路向下递归插入,并将summary相应设为1即可。
PROTO-VEB-INSERT(V, x)if V.u == 2V.A[x] = 1elsePROTO-VEB-INSERT(V.summary, high(x))PROTO-VEB-INSERT(V.cluster[high(x)], low(x))
VEB-EMPTY-TREE-INSERT(V, x)V.min = xV.max = x
VEB-TREE-INSERT(V, x)if V.min == NILVEB-EMPTY-TREE-INSERT(v, x)else if x < V.minexchange x with V.minif V.u > 2if VEB-TREE-MINIMUN(V.cluster[high(x)]) == NILVEB-TREE-INSERT(V.summary, high(x))VEB-EMPTY-TREE-INSERT(V.cluster[high(x)], low(x))elseVEB-TREE-INSERT(V.cluster[high(x)], low(x))if x > V.max V.max = x
复杂度和PROTO-VEB-MINIMUN一样 [ T(u) = 2T(\sqrt u) + O(1)] 即 θ(lgu)
## 删除元素##
相对于插入,删除要麻烦一点,因为不能直接从summary中删除元素。要确保相对应的 cluser所代表的子集不包含任何元素才能在smmary中置0。探查一个proto-VEB是否只 包含一个元素,以目前的结构可以有几种方式,但没有一种快于 θ(lgu) 的方式。也就是说PROTO-VEB-DELETE注定要超过 θ(lgu)。这儿先别急 着实现proto-VEB的删除操作,先来回顾一下,所有的基本操作我们都已经分析过一遍 了。拿最大值、最小值很慢,拿前驱、后继很慢,插入删除也要比预期的慢,似乎除 了MEMBER操作,所有的操作都很慢,但是仔细分析发现,找前驱慢是因为取最小值太 慢了,找后继慢是因为取最大值太慢了。插入慢是因为要额外对summary执行一次插入, 删除慢是因为对这个结构的判空慢,实际上插入和删除慢是因为同一个问题,没法快 速知道一个proto-VEB的尺寸和极限值。归根结底,这些操作慢的症结在于,没法快速 知道最大值最小值,因为知道最大值最小值以后,尺寸便能在θ(1)之内得 到了。既然如此,我们不如直接将最大值,最小值直接记录在proto-VEB的结构中。 Van Emde Boas Trees的最终模型就得到了,给proto-VEB添加记录最大值和最小值的 两个属性。
The van Emde Boas tree
先约定,将van Emde Boas tree简称为vEb。
在给proto-VEB加上min和max两个属性之前,还得有一个问题要解决,proto-VEB 要求 u=22k,这个要求显然有点太过苛刻了,现在我们把这个范围放宽到 u=2k。放宽要面对的第一个问题就是u√不一定是整数了,解决的 办法便是,我们的规模不再要求以开平方的规模来缩小了,而是以接近开平方的规模缩 小,简言之,原来将proto-VEB(u)分解为u√个proto-VEB(u√), 现在则是将vEB(u)分解成⌈(lgu)/2⌉个 vEB(⌊(lgu)/2⌋)。直观起见,将 ⌈(lgu)/2⌉用u√↑表示,将 ⌊(lgu)/2⌋以u√↓表示, u=u√↑⋅u√↓.
相较于proto-VEB结构上有以下两个变化:
增加min和max两个属性
对于u=2的VEB来说,不需要数组A[0..1]了,因为min和max足以来 记录两个值。
对于u>2的VEB来说,min不储存在任何一个cluster中,但是max值要, 为什么这么做,可以让在空集合中插入元素和删除集合中唯一元素的操作都为 O(1)。
重新定义一下几个方法: [high(x) = \lfloor x / \sqrt[\downarrow] u \rfloor] [low(x) = x \mod \sqrt[\downarrow] u] [index(x, y) = x \sqrt[\uparrow] u + y]
VEB-TREE-DELETE(V, x)if V.min == V.maxV.min == NILV.max == NILelse if V.u == 2if x == 0V.min = 1elseV.min = 0V.max = V.minelse if x == V.minfirst-cluster = VEB-TREE-MINIMUN(V.summary)x = index(first-cluster, VEB-TREE-MINIMUN(V.cluster[first-cluster]))V.min = xVEB-TREE-DELETE(V.cluster[high(X)], low(x))if VEB-TREE-MINIMUN(V.cluster[high(x)]) == NILVEB-TREE-DELETE(V.summary, high(x))if x == V.maxsummary-max = vEB-TREE-MAXIMUN(V.summary)if summary-max == NILV.max = V.minelseV.max = index(summary-max, vEB-TREE-MAXMIMUN(V.cluster[summary-max]))
Van Emde Boas Trees相关推荐
- van Emde Boas Trees(vEB树)(Introduction to Algorithms, 算法导论,CLRS)学习笔记
van Emde Boas Trees 1. Predecessor search/ordered sets predecessor: return the nearest left neighbor ...
- 【adoo】Van Emde Boas trees
各种姿势补充中--转自http://www.roading.org/algorithm/introductiontoalgorithm/Van_Emde_Boas_trees.html van Emd ...
- 《算法导论3rd第二十章》van Emde Boas树
前言 前面介绍的二叉堆,红黑树以及斐波那契堆,其重要的操作都要O(lgn).当特定条件下,能否够规避Ω(lglgn)下界的限制?在本章中,我们将看到:van Emde Boas树支持优先队列操作及一些 ...
- 6.6 van Emde Boas树
我将按四个步骤来逐一引入到van Emde Boas树.从位图到索引位图,再到van Emde Boas原型,最后到van Emde Boas树. 位图与索引位图 在java中有这个一个类,叫 ...
- BZOJ 3685: 普通van Emde Boas树( 线段树 )
建颗权值线段树就行了...连离散化都不用... 没加读入优化就TLE, 加了就A掉了...而且还快了接近1/4.... ---------------------------------------- ...
- 算法导论读书笔记(20)van Emde Boas树
第五部分 高级数据结构 第20章 van Emde Boas树 van Emde Boas树支持优先队列操作以及一些其他操作,每个操作最坏情况运行时间为O(lglgn).而这种数据结构限制关键字必须为 ...
- van Emde Boas 树 数据结构说解
van Emde Boas 树的定义 直观上看,vEB 树保存了一个有序的集合,并支持以 O(lglgn) 的时间复杂度在 vEB 树上进行最小最大值查询.单值存在性查询.单值前驱后继查询.单值插入维 ...
- 算法导论-van Emde Boas树
van Emde Boas树 van Emde Boas树中文名不知道,所以暂且叫它v树吧.v树是一种数据结构,和二叉树.红黑树类似.一种数据结构被创建出来,肯定有其特别的优点,v树的优点就是实现数据 ...
- 详解Van emde boas tree
详解Van Emde Boas Tree 在这篇文章中, 我将带大家走进Van Emde Boas tree这种数据结构 Motivation 在读这篇文章之前, 相信大家都已经很了解二叉搜索树了, ...
最新文章
- 第八届全国大学生智能汽车竞赛获奖名单
- x86虚拟机NXVM_Centos6.5 x86_64系统安装kvm虚拟机—基础篇
- 【我的Android进阶之旅】Android自定义Lint实践
- 【FFMPEG中PTS与DTS统一转换为毫秒】
- c语言连接mysql_聊聊数据库MySQL、SqlServer、Oracle的区别,哪个更适合你?
- CentOS7 内核参数优化
- SparkStreaming项目(实时统计每个品类被点击的次数)
- 语音识别相关书籍抖音十大先看哪一本最好
- 3至六年级计算机知识,小学三至六年级下册信息技术教学计划范文
- AV-TEST最新Windows 10平台最佳杀毒软件测试结果
- MC34063中文资料及应用实例(转)
- UVa 124 Following Orders
- 正样本/反(负)样本/易区分样本/难区分样本
- 【SQL2008】select TOP (100) PERCENT***********ORDER BY **********
- java 苹果cms 萌果_苹果cms打包app
- ubuntu - sudo file 编辑报错 sudo: no valid sudoers sources found, quitting
- 2019年上半年云桌面排名前五企业
- 【渝粤教育】国家开放大学2018年秋季 2408T中国当代文学 参考试题
- final修饰的变量
- 杭电考研计算机专业课_2019杭电计算机考研初试科目、参考书目、报录比汇总...
热门文章
- php+js+背景特效,基于canvas+html5炫酷星空背景动画特效
- 从一颗MCU芯片开始,降低抗干扰成本——MCU抗干扰实验系列专题(11)
- c语言基于easyx库的 飞机大战游戏(鼠标控制飞机移动,武器升级,boss发射散弹,boss血条等功能)
- 2022司钻(钻井)考试题及答案
- android 华为底部虚拟键盘隐藏,Android隐藏手机底部虚拟按键的方法
- python中好用的库(一)
- MacOS 卡在Finished,saving caches
- 柠檬浏览器 for linux,柠檬浏览器官方下载
- 随机梯度下降与动量详解
- UE4学习日记15(怪兽)