浅谈杂交数据结构之分块 deque 原理及实现
FlowerAccepted · · 科技·工程
前言
@_KagamineRin : 会慢得跟屎一样,最关键的是我要封装 || @AKPC : 用数组手写双端队列 || @_KagamineRin : vector 在首尾添加很慢,deque 随机访问很慢,那能不能把这两个 STL 结合起来??
其实可以的,鸽们,可以的!我有个好办法!
可以整体用重载 [] 的 std::list 维护约
我所说的这个数据结构,平均可以做到
但是若当前块长 deque 拍了重建不然性能查询性能大大影响。重建和初始化复杂度均为
这里用定长数组(为了方便,还是 std::vector 但是 reserve 过的)
虽然 std::deque 也使用了类似的思路但是本质并不相同,各有千秋。这边内存是 std::deque 的
但是这边思路确实我独立想到的啊!wssb?
“寂”术细节
小前言
设 deque 大小
下标
首先,因为块
为了兼容一些特殊用途,这个杂交数据结构是 因为本蒟蒻太菜所以无法一发确定,所以经过大量调试发现原下标
因为有些用,所以把上述两式封装函数。反正可以开强制内联。
于是就可以重载 [] 运算符咯!
建立空分块 deque
将 vector。
从 std::vector 导入
建立长度为 deque,然后一个一个替换为目标数据即可。
精力有限,后面的不想写了,请大家看代码理解。
原型代码
轻量版实现,功能很少,没有边界判断,谨防溢出,没有迭代器。适合较纯粹场景。
注意到本项目数据越大插入修改的优势就越大,但是替代大量单点查询没得准的。(n 根 n 还是有点大)
也就是一个小糖思路,主要是优化了 deque 的十六倍空间。 :::info[点击打开]
#ifndef blkarr_h
#define blkarr_h
#include <vector>
#include <cmath>
#include <list>
using namespace std;
#define ila inline __attribute__((always_inline))
template<typename Tp>
class __list : public std::list<Tp> {
public:
using list<Tp>::list;
ila Tp& operator[](size_t index) {
auto it = this->begin();
advance(it, index);
return *it;
}
};
template <typename Tp>
struct Blkarr {
int BL, BN, len, n, pre;
long long mln;
__list<vector<Tp>> a;
ila int __getb(int i) const {
return (i + pre) / BL;
}
ila int __getidx(int i) const {
return (i + pre) % BL;
}
ila Tp& operator [](int i) {
return a[__getb(i)][__getidx(i)];
}
ila const Tp& operator [](int i) const {
return a[__getb(i)][__getidx(i)];
}
ila void push_back(Tp x) {
if (__getb(len) == BN) {
a.push_back(vector<Tp>(BL));
BN ++;
len ++;
a.back()[0] = x;
if (len >= mln) {
rebuild();
}
} else {
a.back()[__getidx(len)] = x;
len ++;
}
}
ila void push_front(Tp x) {
if (!pre) {
a.push_front(vector<Tp>(BL));
pre = BL - 1;
a.front()[pre] = x;
BN ++;
len ++;
if (len >= mln) {
rebuild();
}
} else {
pre --;
a.front()[pre] = x;
len ++;
}
}
ila void pop_back() {
if (!__getidx(len)) {
a.pop_back();
BN --;
len --;
if (len <= BL) {
rebuild();
}
} else {
len --;
}
}
ila void pop_front() {
if (pre + 1 == BL) {
a.pop_front();
BN --;
len --;
pre = 0;
if (len <= BL) {
rebuild();
}
} else {
pre ++;
len --;
}
}
ila void reclear(int l) {
a.clear();
n = len = l;
BL = sqrt(n) + 1;
BN = ceil(1.0 * len / BL);
mln = n << (int)(sqrt(BL));
pre = 0;
for (int i = 0; i < BN; i ++) {
a.push_back(vector<Tp>(BL));
}
}
ila void operator = (vector<Tp> v) {
reclear((int)v.size());
auto cb = a.begin();
int cbi = 0, cbs = 0, cbe = BL - pre - 1;
for (int i = 0; i < len; i++) {
if (i > cbe) {
cb ++;
cbi ++;
cbs = cbe + 1;
cbe = cbs + BL - 1;
}
int pib = i - cbs;
(*cb)[pib] = v[i];
}
}
ila void rebuild() {
vector<Tp> v;
v.resize(len);
auto cb = a.begin();
int cbi = 0, cbs = 0, cbe = BL - pre - 1;
for (int i = 0; i < len; i++) {
if (i > cbe) {
cb ++;
cbi ++;
cbs = cbe + 1;
cbe = cbs + BL - 1;
}
int pib = i - cbs;
v[i] = (*cb)[pib];
}
*this = v;
}
ila Blkarr() {
BL = 1;
BN = len = n = pre = 0;
}
ila Blkarr(int l) {
reclear(l);
}
ila Blkarr(const vector<Tp>& v) {
*this = v;
}
};
#undef ila
#endif
:::