From 1a14907c567f22c6fdf5a7b4f23b7b2677a94b89 Mon Sep 17 00:00:00 2001 From: huangsimin Date: Wed, 28 Aug 2019 19:22:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Readme=20=E4=B8=8E=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=B5=8B=E8=AF=95=E6=8F=8F=E8=BF=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Readme.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ run.sh | 1 + src/main.cpp | 4 +++ 3 files changed, 90 insertions(+) create mode 100644 Readme.md diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..6a827ba --- /dev/null +++ b/Readme.md @@ -0,0 +1,85 @@ +# 优先队列的一些理解与测试 + +## 优先队列(PriorityQueue) + +最经典的就是Heap的应用, 效率也相当高, 当时操作仅限Put Pop. 无法实现Rank, Index等操作, 很多时候结构使用局限性较大. 甚至会出现一些每次需要Index, Rank的时候, 先Copy一个数组, Sort(排序一次), 通过数组Index. 数据量非常小的情景下, 实则怎么操作都没什么大问题. 量巨大的时候, 效率异常低下. 所以以下是我曾经为了优先队列的一些研究. + +--- + +* SkipList + +> 跳表是一个随机化的数据结构,可以被看做二叉树的一个变种,它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,目前在Redis和LeveIDB中都有用到。 +它采用随机技术决定链表中哪些节点应增加向前指针以及在该节点中应增加多少个指针。跳表结构的头节点需有足够的指针域,以满足可能构造最大级数的需要,而尾节点不需要指针域。 +采用这种随机技术,跳表中的搜索、插入、删除操作的时间均为O(logn),然而,最坏情况下时间复杂性却变成O(n)。相比之下,在一个有序数组或链表中进行插入/删除操作的时间为O(n),最坏情况下为O(n)。 + +* 这里更正以下, 我个人认为跳表的效率远不如红黑树,AVL, 而且有大量测试都验证不如. 如果有异议可以纠正我错误. + +--- + +* Size Balance Tree + +> 简称[SBT](https://wenku.baidu.com/view/364afa42a8956bec0975e3b1.html) 可以从链接山查看具体介绍, 拥有与跳表一样的Rank, Select(Index), 等属性, 在并行上处理不如跳表, 平衡树put,remove的操作都涉及范围内的旋转与调整, 需要锁树, 但是链表, 可以只锁相邻节点. 达到高效的并行处理. + +* 通过各种语言和测试, 并不像论文所述, 并不优于AVL 和 RBTree. 感觉有夸大的嫌疑. 如果有异议可以纠正我错误. + +--- + +* Vague Balance Tree + +> 简称[VBT] 这个树是我根据宽度平衡的一些构想并实现, 我在这个树结构的时候完全不知道SBT的存在(知道我不会写了). 通过大量的结果测试写出课根据一个平衡因子作旋转, 具体以后再写. 实测性能不输RBTree(红黑), AVLTree, SBT SkipList并且有 SBT等同的属性. 在一些特殊倾斜的数据集会略输. + +--- + +``` bash +rm -f bin/main +g++ -std=c++17 -Wall -Wextra -g -O2 -Wno-unused-parameter -Wno-unused-function -Iinclude -Llib src/sbt.h src/vbtree.h src/main.cpp -o bin/main +基于5000000数据量的测试 +vec.dat 加载... + +case: 1 +792 ns/op +end RBTree Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 1_1 +747 ns/op +end RBTree Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 2 +688 ns/op +end VBTree Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 2_1 +706 ns/op +end VBTree Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 3 +1029 ns/op +end SBT Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 3_1 +675 ns/op +end SBT Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 4 +1455 ns/op +end SkipList Case Benchmark +基于5000000数据量的测试 +vec.dat 加载... + +case: 4_1 +1451 ns/op +end SkipList Case Benchmark +``` + diff --git a/run.sh b/run.sh index f88a578..f886a13 100644 --- a/run.sh +++ b/run.sh @@ -1,3 +1,4 @@ +#! /bin/bash make clean all ./bin/main 1 ./bin/main 1_1 diff --git a/src/main.cpp b/src/main.cpp index 193c4a3..a256280 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,9 +28,11 @@ vector vec; map funcmap ; void init() { + cout << "基于" << N << "数据量的测试" << endl; const char *fpath = "./vec.dat"; std::ifstream inf(fpath); if (!inf.is_open()) { + cout << "vec.dat不存在, 初始化生成随机数据" << endl; std::ofstream openfile(fpath, ios::binary | ios::trunc); default_random_engine e; std::uniform_int_distribution<> dist{0, 1000000000}; @@ -42,6 +44,8 @@ void init() { openfile.close(); inf.open(fpath); } + + cout << "vec.dat 加载..." << endl; for(;!inf.eof();) { int v; inf >> v;