双端堆/间隔堆(IntervalHeap)

简介:

一般堆结构(大根堆/小根堆)能够以O(logn)水平动态维护集合的最值(最大/最小),间隔堆结构类似一般堆结构,是一棵满二叉树,能够以O(logn)水平动态维护集合的最大值和最小值,空间复杂度O(n)。

核心思想:
  1. 堆的每个结点维护两个值(下文称为左值和右值),保证左值小于右值

  1. 所有结点的左值相当于一个小根堆,保证每个结点的值小于其父结点的值;右值同理

  1. 进行HeapDown(向下堆化)操作时,必须保证当前结点的左值小于右值

  1. 压入新值时:

  1. 如果有邻值,则需要先与邻值进行比较,再进行HeapUp(向上堆化)操作

  1. 如果没有,则需要先确定自己所在的堆,再进行HeapUp操作

  1. 其他所有操作与一般堆结构同理,细节参考源码

源代码:
#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';
    }
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IN0vation

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值