C++实现斐波那契堆

227 阅读2分钟

斐波那契堆的实现相对复杂,涉及到许多细节。以下是一个简单的C++实现,包含了插入、合并、删除最小元素和减小关键字等基本操作:

#include <iostream>
#include <vector>
#include <cmath>
#include <limits>

// 定义斐波那契堆节点
class FibonacciHeapNode {
public:
    int key; // 节点值
    int degree; // 节点度数
    bool marked; // 是否被标记
    FibonacciHeapNode* parent; // 父节点
    FibonacciHeapNode* child; // 第一个子节点
    FibonacciHeapNode* left; // 左兄弟节点
    FibonacciHeapNode* right; // 右兄弟节点

    // 构造函数
    FibonacciHeapNode(int k) : key(k), degree(0), marked(false), parent(nullptr), child(nullptr), left(this), right(this) {}
};

// 定义斐波那契堆
class FibonacciHeap {
private:
    FibonacciHeapNode* minNode; // 最小节点
    int numNodes; // 节点数目

public:
    // 构造函数
    FibonacciHeap() : minNode(nullptr), numNodes(0) {}

    // 插入操作
    void insert(int key) {
        FibonacciHeapNode* newNode = new FibonacciHeapNode(key);
        if (!minNode) {
            minNode = newNode;
        } else {
            newNode->left = minNode->left;
            newNode->right = minNode;
            minNode->left->right = newNode;
            minNode->left = newNode;
            if (key < minNode->key) minNode = newNode;
        }
        numNodes++;
    }

    // 合并操作
    void merge(FibonacciHeap* other) {
        if (!other || !other->minNode) return;
        if (!minNode) {
            minNode = other->minNode;
        } else {
            FibonacciHeapNode* thisRight = minNode->right;
            FibonacciHeapNode* otherLeft = other->minNode->left;
            minNode->right = other->minNode;
            other->minNode->left = minNode;
            thisRight->left = otherLeft;
            otherLeft->right = thisRight;
            if (other->minNode->key < minNode->key) minNode = other->minNode;
        }
        numNodes += other->numNodes;
        other->minNode = nullptr;
        other->numNodes = 0;
    }

    // 删除最小元素操作
    int removeMin() {
        if (!minNode) return std::numeric_limits<int>::max();
        FibonacciHeapNode* min = minNode;
        if (minNode->child) {
            FibonacciHeapNode* child = minNode->child;
            do {
                FibonacciHeapNode* nextChild = child->right;
                minNode->left->right = child;
                child->right = minNode;
                minNode->left = child;
                child->parent = nullptr;
                child = nextChild;
            } while (child != minNode->child);
        }
        minNode->left->right = minNode->right;
        minNode->right->left = minNode->left;
        if (minNode == minNode->right) {
            minNode = nullptr;
        } else {
            minNode = minNode->right;
            consolidate();
        }
        numNodes--;
        int minKey = min->key;
        delete min;
        return minKey;
    }

    // 减小关键字操作
    void decreaseKey(FibonacciHeapNode* node, int newKey) {
        if (!node || newKey >= node->key) return;
        node->key = newKey;
        FibonacciHeapNode* parent = node->parent;
        if (parent && node->key < parent->key) {
            cut(node, parent);
            cascadingCut(parent);
        }
        if (node->key < minNode->key) minNode = node;
    }

    // 删除节点操作
    void deleteNode(FibonacciHeapNode* node) {
        decreaseKey(node, std::numeric_limits<int>::min());
        removeMin();
    }

private:
    // 合并具有相同度数的树
    void consolidate() {
        int maxDegree = std::ceil(std::log2(numNodes)) + 1;
        std::vector<FibonacciHeapNode*> degreeTable(maxDegree, nullptr);
        FibonacciHeapNode* curr = minNode;
        do {
            FibonacciHeapNode* next = curr->right;
            int degree = curr->degree;
            while (degreeTable[degree]) {
                FibonacciHeapNode* other = degreeTable[degree];
                if (curr->key > other->key) std::swap(curr, other);
                link(other, curr);
                degreeTable[degree] = nullptr;
                degree++;
            }
            degreeTable[degree] = curr;
            curr = next;
        } while (curr != minNode);

        minNode = nullptr;
        for (int i = 0; i < maxDegree; ++i) {
            if (degreeTable[i]) {
                if (!minNode) {
                    minNode = degreeTable[i];
                } else {
                    degreeTable[i]->left->right = degreeTable[i]->right;
                    degreeTable[i]->right->left = degreeTable[i]->left;
                    degreeTable[i]->left = minNode->left;
                    degreeTable[i]->right = minNode;
                    minNode->left->right = degreeTable[i];
                    minNode->left = degreeTable[i];
                    if (degreeTable[i]->key < minNode->key) minNode = degreeTable[i];
                }
            }
        }
    }

    // 将other合并到root中
    void link(FibonacciHeapNode* other, FibonacciHeapNode* root) {
        other->left->right = other->right;
        other->right->left = other->left;
        other->parent = root;
        if (!root->child) {
            root->child = other;
            other->left = other->right = other;
        } else {
            other->left = root->child->left;
            other->right = root->child;
            root->child->left->right = other;
            root->child->left = other;
        }
        root->degree++;
        other->marked = false;
    }

    // 剪切节点node和其父节点的链接,并将node添加到根列表中
    void cut(FibonacciHeapNode* node, FibonacciHeapNode* parent) {
        if (!parent->child) return;
        if (node->right == node) {
            parent->child = nullptr;
        } else {
            node->left->right = node->right;
            node->right->left = node->left;
            if (parent->child == node) parent->child = node->right;
        }
        parent->degree--;
        node->left = minNode->left;
        node->right = minNode;
        minNode->left->right = node;
        minNode->left = node;
        node->parent = nullptr;
        node->marked = false;
    }

    // 级联剪切,直到遇到未被标记的节点或根节点
    void cascadingCut(FibonacciHeapNode* node) {
        FibonacciHeapNode* parent = node->parent;
        if (parent) {
            if (!node->marked) {
                node->marked = true;
            } else {
                cut(node, parent);
                cascadingCut(parent);
            }
        }
    }
};

int main() {
    FibonacciHeap heap;
    heap.insert(5);
    heap.insert(10);
    heap.insert(3);

    std::cout << "Min element: " << heap.removeMin() << std::endl;

    return 0;
}