简介:
一般堆结构(大根堆/小根堆)能够以O(logn)水平动态维护集合的最值(最大/最小),间隔堆结构类似一般堆结构,是一棵满二叉树,能够以O(logn)水平动态维护集合的最大值和最小值,空间复杂度O(n)。
核心思想:
堆的每个结点维护两个值(下文称为左值和右值),保证左值小于右值
所有结点的左值相当于一个小根堆,保证每个结点的值小于其父结点的值;右值同理
进行HeapDown(向下堆化)操作时,必须保证当前结点的左值小于右值
压入新值时:
如果有邻值,则需要先与邻值进行比较,再进行HeapUp(向上堆化)操作
如果没有,则需要先确定自己所在的堆,再进行HeapUp操作
其他所有操作与一般堆结构同理,细节参考源码
源代码:
#pragma once
#include <utility>
#include <exception>
#include <algorithm>
#include <cstdlib>
#include <type_traits>
#include <thread>
#define L first
#define R second
#define BIG 8172
// 间隔树结构
// _Ty 元素类型
// LessTag 比较器标志(若采用大于比较器则置false)
// _Cmpr 比较器(默认采用小于比较器)
template<typename _Ty, bool LessTag = true, typename _Cmpr = std::less<_Ty>>
class IntervalHeap {
protected:
// 实际使用的比较器
struct Cmpr
{
// 封装用户传递的比较器,保证采用小于比较准则
bool operator() (const _Ty& v1, const _Ty& v2) const {
return LessTag ? _cpr(v1, v2) : !_cpr(v1, v2);
}
_Cmpr _cpr;
};
// 资源申请函数
// 申请失败报异常但不进行初始化操作
// cap: 容器容量(以元素大小为单位)
// 返回资源指针
inline void* New(size_t cap) {
if (!cap) return nullptr;
void* p = malloc(sizeof(_Ty) * cap);
if (!p) throw std::bad_alloc();
return p;
}
// 释放资源
inline void Free() {
if (this->src) {
_Ty* p = (_Ty*)this->src;
if (std::is_class_v<_Ty>) {
if (this->size > BIG) {
// 多线程优化
std::thread t([p](size_t n) { for (size_t i = 0; i < n >> 1; i++) p[i].~_Ty(); }, this->size);
for (size_t i = this->size >> 1; i < this->size; i++) p[i].~_Ty();
t.join();
}
else for (size_t i = 0; i < this->size; i++) p[i].~_Ty();
}
free(this->src);
this->src = nullptr;
this->size = 0;
this->capacity = 0;
}
}
// 快速换值,直接交换二进制流
inline void Swap(void* p, void* q, size_t bits) {
if (bits < 128u) {
static char rev[128]{};
memcpy(rev, p, bits);
memcpy(p, q, bits);
memcpy(q, rev, bits);
}
else {
void* buf = malloc(sizeof(_Ty));
if (!buf) throw std::bad_alloc();
memcpy(buf, p, bits);
memcpy(p, q, bits);
memcpy(q, buf, bits);
free(buf);
}
}
// 删除某一元素
// off: 第几个元素(从1开始)
inline void Del(size_t off) {
if (std::is_class_v<_Ty>) ((_Ty*)this->src)[off - 1].~_Ty();
--this->size;
}
// 数据拷贝
// 源数据地址,元素个数
// 目标地址,元素最大容量
inline void Memcpy(void* src, size_t cnt, void* dst, size_t cap) {
// 基本类型直接拷贝
// 自定类型逐个构造
if (std::is_class_v<_Ty>) {
_Ty* p = (_Ty*)src;
_Ty* q = (_Ty*)dst;
size_t n = std::min(cnt, cap);
if (n > BIG) {
// 多线程优化
std::thread t([p, q, n] { for (size_t i = 0; i < n >> 1; i++) new(&q[i]) _Ty(p[i]); });
for (size_t i = n >> 1; i < n; i++) new(&q[i]) _Ty(p[i]);
t.join();
}
else for (size_t i = 0; i < n; i++) new(&q[i]) _Ty(p[i]);
}
else memcpy_s(dst, sizeof(_Ty) * cap, src, sizeof(_Ty) * cnt);
}
// 扩容函数(每次扩容2倍)
void Expand() {
// 分配资源
size_t cap = this->capacity ? this->capacity << 1 : 2;
if (cap <= 0) throw std::exception("fail to expand");
this->Reserve(cap);
}
// 向下堆化
// x: 结点下标
// minHeap: true调整小堆,false调整大堆
void HeapDown(size_t x, bool minHeap) {
std::pair<_Ty, _Ty>* p = (std::pair<_Ty, _Ty>*) this->src;
// 左右孩子下标
size_t l = (x << 1) + 1, r = l + 1;
// 目标值的下标
size_t tar;
// 结点个数
size_t cnt;
// 小堆调整
if (minHeap) {
cnt = (this->size >> 1) + this->size % 2;
// 结点内部调整
// 如果元素个数为奇数则尾结点不用调整
if ((x < cnt - 1 || this->size % 2 == 0) && this->cpr(p[x].R, p[x].L)) this->Swap(&p[x].L, &p[x].R, sizeof(_Ty));
while (true) {
if (l >= cnt) return;
tar = r >= cnt || this->cpr(p[l].L, p[r].L) ? l : r;
if (this->cpr(p[x].L, p[tar].L)) return;
this->Swap(&p[tar].L, &p[x].L, sizeof(_Ty));
x = tar;
// 结点内部调整
if ((x < cnt - 1 || this->size % 2 == 0) && this->cpr(p[x].R, p[x].L)) this->Swap(&p[x].L, &p[x].R, sizeof(_Ty));
l = (x << 1) + 1, r = l + 1;
}
}
// 大堆调整
else {
// 如果元素个数为奇数则最后一个结点不用处理
cnt = this->size >> 1;
// 结点内部调整
if (this->cpr(p[x].R, p[x].L)) this->Swap(&p[x].L, &p[x].R, sizeof(_Ty));
while (true) {
if (l >= cnt) return;
tar = r >= cnt || this->cpr(p[r].R, p[l].R) ? l : r;
if (this->cpr(p[tar].R, p[x].R)) return;
this->Swap(&p[x].R, &p[tar].R, sizeof(_Ty));
x = tar;
// 结点内部调整
if (this->cpr(p[x].R, p[x].L)) this->Swap(&p[x].L, &p[x].R, sizeof(_Ty));
l = (x << 1) + 1, r = l + 1;
}
}
}
// 向上堆化
// x: 结点下标
// minHeap: true调整小堆,false调整大堆
void HeapUp(size_t x, bool minHeap) {
std::pair<_Ty, _Ty>* p = (std::pair<_Ty, _Ty>*) this->src;
// fa 父结点
size_t fa = (x - 1) >> 1;
while (x) {
// 小堆调整
if (minHeap) {
if (this->cpr(p[x].L, p[fa].L)) {
this->Swap(&p[x].L, &p[fa].L, sizeof(_Ty));
x = fa;
}
else return;
}
// 大堆调整
else {
if (this->cpr(p[fa].R, p[x].R)) {
this->Swap(&p[fa].R, &p[x].R, sizeof(_Ty));
x = fa;
}
else return;
}
fa = (x - 1) >> 1;
}
}
public:
// 默认构造
IntervalHeap() :src(nullptr), size(0), capacity(0) {}
// 浅拷贝(小心使用,注意析构问题)
IntervalHeap(const IntervalHeap& cp, bool ShallowCopy) :src(cp.src), size(cp.size), capacity(cp.capacity) {}
// 拷贝构造(深拷贝)
IntervalHeap(const IntervalHeap& cp) : src(this->New(cp.capacity)), size(cp.size), capacity(cp.capacity) {
if (!this->src) return;
// 数据拷贝
this->Memcpy(cp.src, cp.size, this->src, this->capacity);
}
// 移动构造
IntervalHeap(IntervalHeap&& mv) noexcept :src(mv.src), size(mv.size), capacity(mv.capacity) {
mv.src = nullptr;
mv.size = 0;
mv.capacity = 0;
}
// 批构造
// 第一个参数传源数据地址
// 第二个参数传元素个数
template<typename T>
IntervalHeap(T* _src, size_t cnt) :src(this->New(cnt)), size(cnt), capacity(cnt) {
if (!this->src) return;
// 数据拷贝
this->Memcpy(_src, cnt, this->src, this->capacity);
// 堆化
std::pair<T, T>* p = (std::pair<T, T>*)this->src;
cnt = (cnt >> 1) - 1;
if (cnt < 0) return;
while (1) {
this->HeapDown(cnt, false);
this->HeapDown(cnt, true);
if (!cnt) return;
--cnt;
}
}
// 列表初始化
template<typename T>
IntervalHeap(const std::initializer_list<T>& lst) :IntervalHeap<T>(lst.begin(), lst.size()) {}
// 赋值(深拷贝)
IntervalHeap& operator= (const IntervalHeap& cp) {
// 释放旧资源
this->Free();
// 申请新资源
this->size = cp.size;
this->capacity = cp.capacity;
this->src = this->New(cp.capacity);
if (!src) return *this;
// 数据拷贝
this->Memcpy(cp.src, cp.size, this->src, this->capacity);
return *this;
}
// 赋值(移动赋值)
IntervalHeap& operator= (IntervalHeap&& mv) noexcept {
this->src = mv.src;
this->size = mv.size;
this->capacity = mv.capacity;
mv.src = nullptr;
mv.size = 0;
mv.capacity = 0;
return *this;
}
// 析构函数
~IntervalHeap() { this->Free(); }
// 压入元素
void Push(const _Ty& val) { this->Emplace(val); }
// 直接构造
template<typename... Args>
void Emplace(Args&&... args) {
// 容量不足则扩容
if (this->size == this->capacity) this->Expand();
new((char*)this->src + sizeof(_Ty) * this->size) _Ty(args...);
// 新元素所在结点下标
size_t x = this->size >> 1;
// 堆中本来有奇数个元素时
// 新元素压入尾结点
// 此时需要先进行内部调整,再向上堆化
if (this->size % 2) {
_Ty* p = (_Ty*)this->src;
if (this->cpr(p[this->size], p[this->size - 1])) {
this->Swap(&p[this->size], &p[this->size - 1], sizeof(_Ty));
this->HeapUp(x, true);
}
else this->HeapUp(x, false);
}
// 堆中本来由偶数个元素时
// 新建尾结点
// 根据父结点的值选择堆,再向上堆化
else if (this->size > 1) {
std::pair<_Ty, _Ty>* p = (std::pair<_Ty, _Ty>*)this->src;
size_t fa = (x - 1) >> 1;
if (this->cpr(p[x].L, p[fa].L)) this->HeapUp(x, true);
else if (this->cpr(p[fa].R, p[x].L)) {
this->Swap(&p[fa].R, &p[x].L, sizeof(_Ty));
this->HeapUp(fa, false);
}
}
++this->size;
}
// 删除最大值
void PopMax() {
if (!this->size) throw std::exception("none element");
if (this->size == 1) this->Del(1);
else if (this->size == 2) this->Del(2);
else {
_Ty* p = (_Ty*)this->src;
this->Swap(&p[1], &p[this->size - 1], sizeof(_Ty));
this->Del(this->size);
this->HeapDown(0, false);
}
}
// 删除最小值
void PopMin() {
if (!this->size) throw std::exception("none element");
if (this->size == 1) this->Del(1);
else {
_Ty* p = (_Ty*)this->src;
this->Swap(&p[0], &p[this->size - 1], sizeof(_Ty));
this->Del(this->size);
this->HeapDown(0, true);
}
}
// 返回最大值
_Ty Max()const {
if (!this->size) throw std::exception("none element");
_Ty* p = (_Ty*)this->src;
return this->size == 1 ? p[0] : p[1];
}
// 返回最小值
_Ty Min()const {
if (!this->size) throw std::exception("none element");
return ((_Ty*)this->src)[0];
}
// 判断函数是否为空
inline bool Empty()const {
return this->size;
}
// 返回元素个数
inline size_t Size()const { return this->size; }
// 返回容器容量
inline size_t Capacity()const { return this->size; }
// 设置容器容量
// 返回0 正常
// 返回-1 元素被截断
int Reserve(size_t cap) {
// 申请资源
void* buf = this->New(cap);
// 拷贝源数据
if (this->src) {
// 拷贝数据
memcpy_s(buf, cap * sizeof(_Ty), this->src, this->size * sizeof(_Ty));
// 释放旧资源
free(this->src);
}
this->src = buf;
this->capacity = cap;
if (cap < this->size) {
this->size = cap;
return -1;
}
return 0;
}
// 返回源数据地址
_Ty* Data() {
return (_Ty*)this->src;
}
// 清空元素,不释放资源
void Clear() { this->Free(); }
protected:
// 源数据地址
// 每个结点是一对数据,左小右大
void* src;
// 元素个数
size_t size;
// 容量大小
size_t capacity;
// 比较器
Cmpr cpr;
};
测试代码:
#include <random>
#include <time.h>
#include <queue>
#include <exception>
#include <cstdlib>
#include <iostream>
#include "IntervalHeap.h"
// 随机数生成器
std::default_random_engine e(std::time(nullptr));
std::uniform_int_distribution<int> irand(-100, 100);
// 一个简单的自定义类型
class Node
{
public:
Node() :v(irand(e)) {}
Node& operator= (const Node& cp) {
v = cp.v;
return *this;
}
bool operator!= (const Node& cpr)const {
return this->v != cpr.v;
}
int v;
std::string str;
};
// 自定义类型的大于比较器
struct Cmpr
{
bool operator() (const Node& v1, const Node& v2)const {
return v1.v > v2.v;
}
};
// 计时类
class Timer {
public:
std::chrono::time_point<std::chrono::steady_clock> start;
Timer() :start(std::chrono::steady_clock::now()) {}
~Timer() {
auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - this->start);
printf("%0.9lf\n", duration.count());
}
};
const int n = 1e6;
// 正确性测试
// 基本类型测试
void f1() {
int* buf = new int[n];
while (1) {
for (int i = 0; i < n; i++) buf[i] = irand(e);
IntervalHeap<int> test(buf, n);
std::vector<int> vec(buf, buf + n);
std::sort(vec.begin(), vec.end());
int hh = 0, tt = n - 1;
while (test.Size()) {
if (irand(e) % 2) {
buf[hh++] = test.Min();
test.PopMin();
}
else {
buf[tt--] = test.Max();
test.PopMax();
}
}
for (int i = 0; i < n; i++) {
if (vec[i] != buf[i]) {
puts("wrong");
return;
}
}
puts("right");
}
delete[] buf;
}
// 自定义类型测试
void f2() {
Node* buf = new Node[n];
while (1) {
IntervalHeap<Node, false, Cmpr> test(buf, n);
std::vector<Node> vec(buf, buf + n);
std::sort(vec.begin(), vec.end(), Cmpr());
int hh = 0, tt = n - 1;
while (test.Size()) {
int v = irand(e);
if (v % 2) {
buf[tt--] = test.Min();
test.PopMin();
}
else {
buf[hh++] = test.Max();
test.PopMax();
}
}
for (int i = 0; i < n; i++) {
if (vec[i] != buf[i]) {
puts("wrong");
return;
}
}
puts("right");
}
delete[] buf;
}
// 性能测试
// 预分配内存
void f3() {
{
Timer clk;
IntervalHeap<Node, false, Cmpr> test;
test.Reserve(n);
for (int i = 0; i < n; i++) test.Emplace();
}
{
Timer clk;
IntervalHeap<Node, false, Cmpr> test;
for (int i = 0; i < n; i++) test.Emplace();
}
}
// 与STL比较
void f4() {
{
Timer clk;
IntervalHeap<Node, false, Cmpr> test;
test.Reserve(n);
for (int i = 1; i < n; i++) test.Emplace();
while (test.Size()) test.PopMax();
}
{
Timer clk;
std::priority_queue<Node, std::vector<Node>, Cmpr> test;
for (int i = 1; i < n; i++) test.emplace();
while (test.size()) test.pop();
}
}
int main() {
try {
}
catch (std::exception error) {
std::cerr << error.what() << '\n';
}
}