简介

VEB树的基础理论在算法导论第三版第20章有详细介绍,这里不再赘述。

VEB树的优势

VEB树支持插入、删除、搜索、最大值、最小值、前驱、后继等操作。
这些操作的时间复杂度都是O(lglgu),u为关键字的全域。

接口定义


/*** Van emde boas树* 下面时间复杂度中 u表示树的容量** @author: zyp* @since: 2022/1/18 下午5:46*/
public interface IVEBTree {int size();/*** u: 可能存储的最大值* O(lglgu)*/boolean contains(int value);/*** 最小值* O(1)*/Integer minmum();/*** 最大值* O(1)*/Integer maxmum();/*** 后继节点* O(lglgu)*/Integer successor(int x);/*** 前驱节点* O(lglgu)*/Integer predecessor(int x);/*** 插入* O(lglgu)*/boolean insert(int value);/*** 删除* O(lglgu)*/boolean delete(int value);void clear();
}

Java实现


import java.util.Arrays;/*** ProtoVEB原型树** @author: zyp* @since: 2022/1/18 下午5:46*/
public class VEBTree implements IVEBTree {private ProtoVEBNode root;public VEBTree(int capacity) {if (capacity < 16) {capacity = 16;}root = new ProtoVEBNode(getOffset(capacity));}//    插入VEB树, 如果元素存在, 则忽略@Overridepublic boolean insert(int value) {ensureCapacity(value + 1);return root.insert(value);}//    是否包含指定元素@Overridepublic boolean contains(int value) {return root.contains(value);}@Overridepublic int size() {return root == null ? 0 : root.size;}//    最小值@Overridepublic Integer minmum() {if (root.size == 0) {return null;}return root.min;}//    最大值@Overridepublic Integer maxmum() {if (root.size == 0) {return null;}return root.max;}//    x的后继节点@Overridepublic Integer successor(int x) {if (root == null) {return null;}return root.successor(x);}//    x的前驱结点@Overridepublic Integer predecessor(int x) {if (root == null) {return null;}return root.predecessor(x);}//    删除指定元素, 如果树种包含该元素, 则返回true@Overridepublic boolean delete(int value) {if (value >= root.capacity) {return false;}return root.delete(value);}@Overridepublic void clear() {root = new ProtoVEBNode(16);}//    扩展容量private void ensureCapacity(int capacity) {int offset = getOffset(capacity);while (root.offset < offset) {ProtoVEBNode newRoot = new ProtoVEBNode(root.offset << 1);newRoot.size = root.size;if (root.size > 0) {newRoot.min = root.min;newRoot.max = root.max;root.delete(root.min);newRoot.getOrCreateSummary().insert(0);}newRoot.getOrCreateClusters(0)[0] = root;root = newRoot;}}/*** 2^n < capacity <= 2^(n+1)* 计算n*/private static int getOffset(int capacity) {if (capacity <= 2) {return 0;}if (capacity <= 4) {return 1;}int offset = 1;while (((1 << offset) << offset) < capacity) {offset <<= 1;if (offset == 16) {return offset;}}return offset;}private static class ProtoVEBNode {private int offset;private int capacity; // 容量 为2的整数次幂 capacity== (1<<offset)<<offsetprivate ProtoVEBNode summary; // 统计clusters中的bitprivate ProtoVEBNode[] clusters; // clusters.length == 1<<offsetprivate int min;private int max;private int size;private ProtoVEBNode() {}public ProtoVEBNode(int offset) {this.offset = offset;if (offset == 16) {this.capacity = Integer.MAX_VALUE;} else {this.capacity = (1 << offset) << offset;}}private ProtoVEBNode(int offset, int capacity) {this.offset = offset;this.capacity = capacity;}@Overridepublic String toString() {return String.format("offset=%s,capacity=%s,size=%s,min=%s,max=%s", offset, capacity, size, min, max);}public Integer predecessor(int x) {if (offset == 0) {if (size == 0) {return null;}if (min < x) {return 0;}return null;}if (size == 0 || x <= min) {return null;}if (x > max) {return max;}if (size == 1) {return null;} else if (size == 2) {return min;}int high = high(x);ProtoVEBNode cluster = getCluster(high);if (cluster != null) {Integer predecessor = cluster.predecessor(low(x));if (predecessor != null) {return index(high, predecessor);}}if (summary == null) {return min;}Integer predecessor = summary.predecessor(high);if (predecessor == null) {return min;}cluster = clusters[predecessor];if (cluster == null) {return min;}return index(predecessor, cluster.max);}public Integer successor(int x) {if (offset == 0) {if (size == 0) {return null;}if (max > x) {return 1;}return null;}if (size == 0 || x >= max) {return null;}if (x < min) {return min;}if (size == 1) {return null;} else if (size == 2) {return max;}int high = high(x);ProtoVEBNode cluster = clusters[high];if (cluster != null) {Integer successor = cluster.successor(low(x));if (successor != null) {return index(high, successor);}}if (summary == null) {return max;}Integer successor = summary.successor(high);if (successor == null) {return max;}cluster = clusters[successor];if (cluster == null) {return max;}return index(successor, cluster.min);}//        因子是2的整数次幂时, 可以用位运算快速计算除法/乘法/取余public int low(int value) {
//            value % (1 << offset)int segSize = 1 << offset;return value & (segSize - 1);}public int high(int value) {
//            value / (1 << offset)int segSize = 1 << offset;return (value & (-segSize)) >> offset;}public int index(int x, int y) {
//            x * (1<<offset) + yreturn (x << offset) + y;}public ProtoVEBNode getOrCreateSummary() {if (summary == null) {summary = createSubNode();}return summary;}private ProtoVEBNode createSubNode() {if (offset == 1) {return new ProtoVEBNode(0, 2);} else {return new ProtoVEBNode(offset >> 1);}}private ProtoVEBNode[] getOrCreateClusters(int capacity) {if (clusters == null) {clusters = new ProtoVEBNode[Math.max(16, capacity)];} else {if (clusters.length < capacity) {
//                    扩容int len = clusters.length;while (len < capacity) {len <<= 1;}clusters = Arrays.copyOf(clusters, len);}}return clusters;}public ProtoVEBNode getCluster(int idx) {if (clusters == null || idx >= clusters.length) {return null;}return clusters[idx];}public ProtoVEBNode getOrCreateCluster(int idx) {ProtoVEBNode[] clusters = getOrCreateClusters(idx + 1);ProtoVEBNode cluster = clusters[idx];if (cluster == null) {cluster = createSubNode();clusters[idx] = cluster;}return cluster;}private boolean insertBase(int x) {if (size == 0) {min = max = x;size++;return true;} else if (size == 1) {if (min == x) {return false;}if (x < min) {min = x;} else {max = x;}size++;return true;} else {return false;}}public boolean insert(int value) {if (offset == 0) {return insertBase(value);}if (size == 0) {min = max = value;size++;return true;} else {if (value == min || value == max) {return false;}int insert;if (value < min) {insert = min;min = value;} else if (value > max) {max = value;insert = value;} else {insert = value;}int high = high(insert);boolean ok = getOrCreateCluster(high).insert(low(insert));if (ok) {getOrCreateSummary().insert(high);size++;}return ok;}}private boolean deleteBase(int x) {if (size == 0) {return false;}if (size == 1) {if (min == x) {size--;return true;}} else {if (0 == x) {min = max = 1;} else {min = max = 0;}size--;return true;}return false;}public boolean delete(int value) {if (offset == 0) {return deleteBase(value);}if (size == 0 || value < min || value > max) {return false;}if (size == 1) {if (min == value) {size--;return true;} else {return false;}}if (min == value) {int successor = successor(min);delete0(successor);min = successor;return true;} else if (max == value) {int predecessor = predecessor(max);delete0(value);max = predecessor;return true;} else {return delete0(value);}}private boolean delete0(int x) {int high = high(x);ProtoVEBNode cluster = clusters[high];boolean ok = cluster != null && cluster.delete(low(x));if (ok) {size--;if (cluster.size == 0) {summary.delete(high);}}return ok;}public boolean contains(int value) {if (size == 0 || value < min || value > max) {return false;}if (min == value || max == value) {return true;}if (offset == 0) {return false;}if (size < 3) {return false;}int high = high(value);if (clusters != null && high < clusters.length) {ProtoVEBNode cluster = clusters[high];if (cluster != null) {return cluster.contains(low(value));}}return false;}}
}

测试

分为正确性测试和性能测试

性能测试结果

TreeMap insert 15045 ms
ProtoVEB insert 11844 ms
TreeMap minimum 142 ms
ProtoVEB minimum 19 ms
TreeMap predecessor 14349 ms
ProtoVEB predecessor 7248 ms
TreeMap contains 13375 ms
ProtoVEB contains 2223 ms
TreeMap delete 14465 ms
ProtoVEB delete 6767 ms


import org.junit.Test;import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom;/*** @author: zyp* @since: 2022/1/20 下午6:50*/
public class SortedTreeTest {ThreadLocalRandom random = ThreadLocalRandom.current();//    VEB树正确性测试@Testpublic void testProtoVEB() {long start = System.currentTimeMillis();TreeHolder holder = new TreeHolder();int keyRange = 10000;int loopTimes = 10000000;
//        测试插入for (int i = 1; i <= loopTimes; i++) {int key = random.nextInt(keyRange);holder.insert(key);key = random.nextInt(keyRange);holder.delete(key);}long end = System.currentTimeMillis();System.out.println(String.format("cost %s ms", end - start));}//    VEB树性能测试@Testpublic void testProtoVEBTime() {long start;Integer zero = 0;int size = 10000000;int[] nums = new int[size];Integer[] numWrappers = new Integer[size];for (int i = 0; i < size; i++) {int v = random.nextInt(0, 100000000);nums[i] = v;numWrappers[i] = v;}TreeMap<Integer, Integer> map = new TreeMap<>();
//        ========================start = System.currentTimeMillis();for (Integer num : numWrappers) {map.put(num, zero);}System.out.println(String.format("TreeMap insert %s ms", System.currentTimeMillis() - start));VEBTree tree1 = new VEBTree(16);start = System.currentTimeMillis();for (int num : nums) {tree1.insert(num);}System.out.println(String.format("ProtoVEB insert %s ms", System.currentTimeMillis() - start));
//        ========================start = System.currentTimeMillis();for (int i = 0; i < size; i++) {map.firstKey();}System.out.println(String.format("TreeMap minimum %s ms", System.currentTimeMillis() - start));start = System.currentTimeMillis();for (int i = 0; i < size; i++) {tree1.minmum();}System.out.println(String.format("ProtoVEB minimum %s ms", System.currentTimeMillis() - start));//        ========================start = System.currentTimeMillis();for (int i = 0; i < size; i++) {map.lowerKey(nums[i]);}System.out.println(String.format("TreeMap predecessor %s ms", System.currentTimeMillis() - start));start = System.currentTimeMillis();for (int i = 0; i < size; i++) {tree1.predecessor(nums[i]);}System.out.println(String.format("ProtoVEB predecessor %s ms", System.currentTimeMillis() - start));//        ========================start = System.currentTimeMillis();for (Integer num : numWrappers) {map.containsKey(num);}System.out.println(String.format("TreeMap contains %s ms", System.currentTimeMillis() - start));start = System.currentTimeMillis();for (int num : nums) {tree1.contains(num);}System.out.println(String.format("ProtoVEB contains %s ms", System.currentTimeMillis() - start));
//        ========================start = System.currentTimeMillis();for (Integer num : numWrappers) {map.remove(num);}System.out.println(String.format("TreeMap delete %s ms", System.currentTimeMillis() - start));start = System.currentTimeMillis();for (int num : nums) {tree1.delete(num);}System.out.println(String.format("ProtoVEB delete %s ms", System.currentTimeMillis() - start));
//        ========================}private static class TreeHolder {private TreeMap<Integer, Integer> map = new TreeMap<>();private VEBTree tree1 = new VEBTree(16);private VEBTree tree2 = new VEBTree(16);public void delete(int key) {boolean remove = map.remove(key) != null;boolean delete;try {delete = tree1.delete(key);} catch (Throwable x) {tree2.delete(key);throw new RuntimeException(x);}if (!Objects.equals(remove, delete)) {tree2.delete(key);throw new RuntimeException("delete 错误");}try {if (tree1.contains(key)) {tree2.delete(key);throw new RuntimeException("delete 错误");}} catch (Throwable x) {tree2.delete(key);tree2.contains(key);throw new RuntimeException(x);}if (map.size() != tree1.size()) {tree2.delete(key);throw new RuntimeException("delete 错误");}tree2.delete(key);}public void insert(int key) {boolean ok = map.put(key, key) == null;boolean ok1;try {ok1 = tree1.insert(key);} catch (Throwable x) {tree2.insert(key);throw new RuntimeException(x);}if (!Objects.equals(ok, ok1)) {tree2.insert(key);throw new RuntimeException("insert 错误");}if (map.firstKey().intValue() != tree1.minmum().intValue()) {tree2.insert(key);tree2.minmum();throw new RuntimeException("minmum 错误");}if (map.lastKey().intValue() != tree1.maxmum().intValue()) {tree2.insert(key);tree2.maxmum();throw new RuntimeException("minmum 错误");}if (!tree1.contains(key)) {tree2.insert(key);tree2.contains(key);throw new RuntimeException("contains 错误");}Integer lowerKey = map.lowerKey(key);Integer predecessor;try {predecessor = tree1.predecessor(key);} catch (Throwable x) {tree2.insert(key);tree2.predecessor(key);throw new RuntimeException("predecessor 错误");}if (!Objects.equals(lowerKey, predecessor)) {tree2.insert(key);tree2.predecessor(key);throw new RuntimeException("predecessor 错误");}Integer higherKey = map.higherKey(key);Integer successor;try {successor = tree1.successor(key);} catch (Throwable x) {tree2.insert(key);tree2.successor(key);throw new RuntimeException("predecessor 错误");}if (!Objects.equals(higherKey, successor)) {tree2.insert(key);tree2.successor(key);throw new RuntimeException("successor 错误");}tree2.insert(key);}}
}

Van emde boas树Java实现相关推荐

  1. 6.6 van Emde Boas树

      我将按四个步骤来逐一引入到van Emde Boas树.从位图到索引位图,再到van Emde Boas原型,最后到van Emde Boas树. 位图与索引位图   在java中有这个一个类,叫 ...

  2. BZOJ 3685: 普通van Emde Boas树( 线段树 )

    建颗权值线段树就行了...连离散化都不用... 没加读入优化就TLE, 加了就A掉了...而且还快了接近1/4.... ---------------------------------------- ...

  3. 算法导论读书笔记(20)van Emde Boas树

    第五部分 高级数据结构 第20章 van Emde Boas树 van Emde Boas树支持优先队列操作以及一些其他操作,每个操作最坏情况运行时间为O(lglgn).而这种数据结构限制关键字必须为 ...

  4. van Emde Boas 树 数据结构说解

    van Emde Boas 树的定义 直观上看,vEB 树保存了一个有序的集合,并支持以 O(lglgn) 的时间复杂度在 vEB 树上进行最小最大值查询.单值存在性查询.单值前驱后继查询.单值插入维 ...

  5. 算法导论-van Emde Boas树

    van Emde Boas树 van Emde Boas树中文名不知道,所以暂且叫它v树吧.v树是一种数据结构,和二叉树.红黑树类似.一种数据结构被创建出来,肯定有其特别的优点,v树的优点就是实现数据 ...

  6. 《算法导论3rd第二十章》van Emde Boas树

    前言 前面介绍的二叉堆,红黑树以及斐波那契堆,其重要的操作都要O(lgn).当特定条件下,能否够规避Ω(lglgn)下界的限制?在本章中,我们将看到:van Emde Boas树支持优先队列操作及一些 ...

  7. 【算法学习笔记】van Emde Boas树

    参考算法导论第20章 van Emde Boas树 文章目录 1. 基本方法 1.1 直接寻址 1.2 叠加的二叉树结构 `Superimposing a binary tree structure` ...

  8. 原型 van Emde Boas 树

    (对于一些简单的数据结构,我就不写在博客上了,然而这个van Emde Boas 树是真的有问题..) 首先,先介绍在本章中n与u的用法: n:集合中当前元素的个数: u:元素可能的取值范围: 同时, ...

  9. van Emde Boas树

    van Emde Boas树支持优先队列操作以及一些其他操作,每个操作最坏运行时间为O(lg lgn),这种数据结构限制关键字必须为0~n-1的整数且无重复.     目前参数n有两个不同的用法:一个 ...

最新文章

  1. rust(13)-闭包作为参数 trait泛型
  2. javascript面向对象包装类Class的类库解析
  3. 网络层网络层服务及其 IP 地址
  4. ie6 ie7下使用clear不能将浮动的元素换行问题
  5. 深入掌握JMS(三):MessageListener
  6. Struts2文件上传超出配置大小的解决办法
  7. 用ExpandableListView实现好友分组
  8. 解决办法:Cannot find the class file for org.apache.http.client.ClientProtocolException
  9. 搭建Web和FTP站点
  10. Use YSlow to know why your web Slow
  11. 基于单片机的公交车系统
  12. 酷派Y60-C1刷官方ROM
  13. windows server 2016 安装有线网卡驱动
  14. “焊”卫锂电 | 昂视锂电池密封钉视觉检测应用详解
  15. linux下编写脚本文件 .sh
  16. 【CODETOOL】文件比较Beyond Compare使用介绍
  17. Android studio2.3版本 用小米手机无法调试,用模拟器正常调试。Application Installation Failed
  18. Pandas数据视图 — groupby 和 pivot
  19. java趣味编程心形_求源代码!(迪卡尔心形图案)
  20. unity物理碰撞检测和触发器碰撞检测的区别

热门文章

  1. 【Android基础】StatusBar重新认识
  2. Android 12系统源码_SystemUI(二)系统状态栏StatusBar的创建流程
  3. 启动SALOME时出现SyntaxError: (unicode error) utf-8 codec can‘t decode byte的解决办法
  4. LINUX集群技术构建ANSYS分布式高性能计算平台
  5. UI设计的市场行情如何?你真的看懂了吗?
  6. 2021年安全员-A证最新解析及安全员-A证考试试卷
  7. 他是马化腾的偶像,拒绝过马云的应聘!如今劝年轻人躺平......
  8. 从真实空间到傅立叶空间
  9. 期初暂估导入报表查看
  10. 移动端App测试实用指南(下)