Skip to content

Binomial Queue

没啥讲的,直接上代码

代码

class node{
public:
    int key;
    int id;
    int rank;
    node* left_child;
    node* next_sibling;    
    node(){key = 0, id = 0, rank = 0, left_child = NULL, next_sibling = NULL;}
    node(int key, int id) : key(key), id(id) {rank = 0, next_sibling = NULL, left_child = NULL;}
    friend class BinTree;
};    
bool LEQ(node* X, node* Y){
    return X->key == Y->key ? X->id < Y->id : X->key < Y->key;
}
class BinTree{
public:
    node* root;    
    friend class BinQueue;
    BinTree(){root = NULL;}
    void dfs(node* u){
        if(!u) return;
        cerr<<u->key<<" ";
        if(u->left_child) dfs(u->left_child);
        if(u->next_sibling) dfs(u->next_sibling);
    }
    void traverse(){
        dfs(root);
    }
};

class BinQueue{
public:
    static const int LOGN = 20;
    int size;
    int MinId;
    BinTree* Min;
    BinTree* Trees[LOGN];
    BinQueue(){
        size = 0, MinId = -1, Min = NULL;
        for(int i = 0; i < LOGN; ++i) Trees[i] = NULL;
    }
    void Traverse(){
        for(int i = 0; i < LOGN; ++i){
            if(Trees[i]) Trees[i]->traverse();
        }
    }
};
BinTree* CombineTrees(BinTree* X, BinTree* Y){
    if(LEQ(Y->root, X->root)) swap(X, Y);
    Y->root->next_sibling = X->root->left_child;
    X->root->left_child = Y->root;
    ++X->root->rank;
    return X;
}

BinQueue* Merge(BinQueue* X, BinQueue* Y){
    BinTree* S;
    BinTree* T;
    BinTree* Carry = NULL;
    BinTree* Min = NULL;
    int MinId = -1;
    X->size += Y->size;
    for(int i = 0; i < X->LOGN; ++i){
        S = X->Trees[i], T = Y->Trees[i];
        switch(4*!!Carry + 2*!!T + !!S){
            case 0:
            case 1: break;
            case 2:
                X->Trees[i] = T; Y->Trees[i] = NULL; break;
            case 3:
                Carry = CombineTrees(S, T);
                X->Trees[i] = Y->Trees[i] = NULL;
                break;
            case 4:
                X->Trees[i] = Carry; Carry = NULL; break;
            case 5:
                Carry = CombineTrees(S, Carry); X->Trees[i] = NULL; break;
            case 6:
            case 7:
                Carry = CombineTrees(T, Carry); Y->Trees[i] = NULL; break;
        }
        //change Min if necessary
        if(!Min || X->Trees[i] && LEQ(X->Trees[i]->root, Min->root)) 
            Min = X->Trees[i], MinId = i;
    }
    X->Min = Min, X->MinId = MinId;
    delete(Y);
    return X;
}
BinTree* MakeTree(node* root){
    BinTree* H = new BinTree();
    H->root = root;
    H->root->next_sibling = NULL;
    return H;
}
int FindMin(BinQueue* H){
    return H->Min->root->key;
}
void InsertKey(BinQueue* H, int key, int id){
    assert(H != NULL);
    BinQueue* X = new BinQueue();
    node* x = new node(key, id);
    X->Trees[0] = MakeTree(x);
    X->size = 1;
    H = Merge(H, X);
}
int DeleteMin(BinQueue* H){
    BinQueue* DeleteQueue = new BinQueue();
    assert(H != NULL);
    int ret = FindMin(H);
    node* x = H->Min->root->left_child;
    while(x != NULL){
        int i = x->rank;
        node* w = x;
        node* next = x->next_sibling;
        DeleteQueue->Trees[i] = MakeTree(w);
        DeleteQueue->size += (1 << DeleteQueue->Trees[i]->root->rank);
        x = next;
    }
    H->Trees[H->MinId] = NULL;
    H->size -= (1 << H->Min->root->rank);
    delete(H->Min);
    H->Min = NULL, H->MinId = -1;
    H = Merge(H, DeleteQueue);
    return ret;
}

模板类

template<typename T> class BinTree;
template<typename T> class BinQueue;
template<typename T> class BinNode{
public:
    T key;
    int rank; // rank of node, if rank is k, then size of subtree of this node is 2^k
    BinNode<T>* left_child;
    BinNode<T>* next_sibling;    
    BinNode<T>* parent;
    BinNode<T>(){key = 0, rank = 0, left_child = NULL, next_sibling = NULL;}
    BinNode<T>(T key) : key(key) {rank = 0, next_sibling = NULL, left_child = NULL;}
    friend class BinTree<T>;
};    
template<typename T> class BinTree{
public:
    BinNode<T>* root; 
    friend class BinQueue<T>;
    BinTree<T>(){root = NULL;}
};
template<typename T> class BinQueue{
public:
    static const int LOGN = 20;
    int size;
    int MinId;
    BinTree<T>* Min; // Min pointer
    BinTree<T>* Trees[LOGN]; // forest
    BinQueue<T>(){
        size = 0, MinId = -1, Min = NULL;
        for(int i = 0; i < LOGN; ++i) Trees[i] = NULL;
    }
    bool empty(){
        return size == 0;
    }
    void MakeBinQueue(){
        size = 0, MinId = -1, Min = NULL;
        for(int i = 0; i < LOGN; ++i) Trees[i] = NULL;
    }
};
template<typename T> BinQueue<T>* Merge(BinQueue<T>* X, BinQueue<T>* Y);
template<typename T> BinTree<T>* MakeTree(BinNode<T>* root);
template<typename T> void InsertKey(BinQueue<T>* H, T key);
template<typename T> BinNode<T>* DeleteMin(BinQueue<T>* H);
template<typename T> void DecreaseKey(BinQueue<T>* H, BinNode<T>* x, T k);
template<typename T> BinNode<T>* FindMin(BinQueue<T>* H);

template<typename T> bool LEQ(BinNode<T>* X, BinNode<T>* Y){
    return X->key < Y->key;
}

template<typename T> BinTree<T>* CombineTrees(BinTree<T>* X, BinTree<T>* Y){ // combine two trees
    if(LEQ(Y->root, X->root)) swap(X, Y);
    Y->root->next_sibling = X->root->left_child;
    X->root->left_child = Y->root;
    Y->root->parent = X->root;
    ++X->root->rank;
    delete(Y); // delete is necessary, otherwise space is not O(n)
    return X;
}

template<typename T> BinQueue<T>* Merge(BinQueue<T>* X, BinQueue<T>* Y){ // merge two queues
    BinTree<T>* S;
    BinTree<T>* M;
    BinTree<T>* Carry = NULL;
    BinTree<T>* Min = NULL;
    int MinId = -1;
    X->size += Y->size;

    for(int i = 0; i < X->LOGN; ++i){
        S = X->Trees[i], M = Y->Trees[i];
        switch(4*!!Carry + 2*!!M + !!S){
            case 0:
            case 1: break;
            case 2:
                X->Trees[i] = M; Y->Trees[i] = NULL; break;
            case 3:
                Carry = CombineTrees(S, M);
                X->Trees[i] = Y->Trees[i] = NULL;
                break;
            case 4:
                X->Trees[i] = Carry; Carry = NULL; break;
            case 5:
                Carry = CombineTrees(S, Carry); X->Trees[i] = Y->Trees[i] = NULL; break;
            case 6:
            case 7:
                Carry = CombineTrees(M, Carry); Y->Trees[i] = NULL; break;
        }
        //change Min if necessary

        if(!Min || X->Trees[i] && LEQ(X->Trees[i]->root, Min->root)) Min = X->Trees[i], MinId = i;
    }
    X->Min = Min, X->MinId = MinId;
    delete(Y);
    return X;
}
template<typename T> BinTree<T>* MakeTree(BinNode<T>* root){ // make a new tree containing a node
    BinTree<T>* H = new BinTree<T>();
    H->root = root;
    H->root->next_sibling = H->root->parent = NULL;
    return H;
}
template<typename T> BinNode<T>* FindMin(BinQueue<T>* H){
    return H->Min->root;
}
template<typename T> void InsertKey(BinQueue<T>* H, T key){
    assert(H != NULL);
    BinQueue<T>* X = new BinQueue<T>(); 
    BinNode<T>* x = new BinNode<T>(key); 
    X->Trees[0] = MakeTree(x); 
    X->size = 1; 
    H = Merge(H, X); 
}
template<typename T> BinNode<T>* DeleteMin(BinQueue<T>* H){
    BinQueue<T>* DeleteQueue = new BinQueue<T>();
    assert(H != NULL);
    BinNode<T>* ret = FindMin(H);
    BinNode<T>* x = H->Min->root->left_child;
    while(x != NULL){ // create a new queue containing subtrees of Min tree
        int i = x->rank;
        BinNode<T>* w = x;
        BinNode<T>* next = x->next_sibling;
        DeleteQueue->Trees[i] = MakeTree(w);
        DeleteQueue->size += (1 << DeleteQueue->Trees[i]->root->rank);
        x = next;
    }
    H->Trees[H->MinId] = NULL;
    H->size -= (1 << H->Min->root->rank); // delete Min tree from original queue
    delete(H->Min);
    H->Min = NULL, H->MinId = -1;
    H = Merge(H, DeleteQueue);
    return ret;
}
template<typename T> void DecreaseKey(BinQueue<T>* H, BinNode<T>* x, T k){
    assert(k <= x->key);
    x->key = k;
    while(x->parent != NULL && LEQ(x, x->parent)){ // campare x with parent y
        swap(x->key, x->parent->key);
        x = x->parent;
    }
    if(x->parent == NULL /*root*/ && LEQ(x, H->Min->root)) H->Min->root = x;
}

与 Fibonacci Heap 复杂度对比

还是 Fibonacci Heap 更快一些