📜  弱堆(1)

📅  最后修改于: 2023-12-03 15:09:50.162000             🧑  作者: Mango

弱堆

弱堆是一种堆(heap)的实现方式,它不同于传统的堆实现,具有一些独特的特点。

概述

弱堆最初由Robert E. Tarjan于1985年提出,它是一种可以在 $O(1)$ 时间内完成删除操作的堆实现。它采用了将二叉堆中的节点替换成一个部分有序树的方式,从而可以保证在删除操作时只需要改变常数个节点的值。

除此之外,弱堆还提供了特殊的操作—— decrease-key,使得同时支持删除和修改操作成为可能。

特点
  • 弱堆支持 $O(\log n)$ 的插入操作
  • 弱堆支持 $O(\log n)$ 的查找最小值操作
  • 弱堆支持 $O(1)$ 的删除操作
  • 弱堆支持 $O(1)$ 的 decrease-key 操作
原理

在弱堆中,每个节点都对应着不同级数的多项式。级数最小的多项式对应的节点为根节点,而级数最大的多项式对应的节点为叶子节点。

为了方便删除操作,弱堆中的节点存储着最小值,而其余子节点中存储着与该节点之差最小的值。在删除节点时,只需要将其右子节点的值赋给该节点,并删除右子节点即可。

在 decrease-key 操作中,弱堆将待修改节点的值与其父节点的值进行比较。如果待修改节点的值大于其父节点的值,就将该节点从该父节点中分离出来,并合并于根节点的右子节点中。最后,将根节点的值设置为待修改节点的值,并将其左子节点和右子节点合并即可。

代码实现

以下是一个简单的弱堆的C++实现。

template<typename T>
class WeakHeap {
public:
    WeakHeap() : root(nullptr) {}
    ~WeakHeap() {
        if (root) {
            delete root;
        }
    }
    bool empty() const {
        return root == nullptr;
    }
    const T& top() const {
        assert(!empty());
        return root->value;
    }
    template<typename... Args>
    void push(Args&&... args) {
        WeakHeap<T>* node = new WeakHeap<T>(std::forward<Args>(args)...);
        root = merge(root, node);
    }
    void pop() {
        assert(!empty());
        root = merge(root->left, root->right);
    }
    void decrease_key(T key) {
        assert(!empty());
        if (key < root->value) {
            std::swap(key, root->value);
        }
        if (root->right) {
            root->right->add_constant(key - root->value);
            root->right->parent = nullptr;
        }
        if (root->left) {
            root->left->add_constant(key - root->value);
            root->left->parent = nullptr;
        }
        delete root;
        root = merge(root->left, root->right);
    }
private:
    WeakHeap(T key) : value(key), left(nullptr), right(nullptr), parent(nullptr) {}
    WeakHeap(const WeakHeap& other) : value(other.value), left(nullptr), right(nullptr), parent(nullptr) {}
    WeakHeap& operator=(const WeakHeap&) = delete;
    void add_constant(int c) {
        value += c;
        constant += c;
    }
    static WeakHeap<T>* merge(WeakHeap<T>* a, WeakHeap<T>* b) {
        if (!a) {
            return b;
        }
        if (!b) {
            return a;
        }
        if (a->value > b->value) {
            std::swap(a, b);
        }
        if (rand() & 1) {
            std::swap(a->left, a->right);
        }
        a->right = merge(a->right, b);
        if (a->right) {
            a->right->parent = a;
        }
        if (!a->left || a->left->level < a->right->level) {
            std::swap(a->left, a->right);
        }
        a->level = a->right->level + 1;
        return a;
    }
    T value;
    int level;
    int constant;
    WeakHeap* left;
    WeakHeap* right;
    WeakHeap* parent;
};