C++实现优先队列——最小堆,d路堆及配对堆

来源:互联网 发布:淘宝助理报告错误 编辑:程序博客网 时间:2024/05/17 02:27

优先队列实现,此处的优先队列是用于Huffman树实现的(具体参考上一篇文章)。所以用于比较的都是huffman树的node的频率,希望读者见谅。

最小堆(二叉):

template <typename T>class MinHeap{public:MinHeap(int cap );~MinHeap();public:bool insert(pTree val);bool remove(pTree data);void print();int size;T getTop();bool createMinHeap(pTree a[], int length);private:int capacity;T * heap;private:void filterUp(int index);void filterDown(int begin, int end);};template <typename T>MinHeap<T>::MinHeap(int cap ):capacity(cap), size(0), heap(nullptr){heap = new pTree[capacity];};template<typename T>MinHeap<T>::~MinHeap(){delete[]heap;};template <typename T>void MinHeap<T>::print(){for (int i = 0; i < size; i++)cout << heap[i]->freq << " ";};template <typename T>T MinHeap<T>::getTop()//返回最小值{if (size != 0)return heap[0];};template <typename T>bool MinHeap<T>::insert(pTree val)//插入函数{if (size == capacity)return false;heap[size] = val;filterUp(size);size++;return true;};template <typename T>void MinHeap<T>::filterUp(int index)//由上至下进行调整{pTree value = heap[index];while (index > 0){int indexParent = (index-1) / 2;if (value->freq >= heap[indexParent]->freq)break;else{heap[index] = heap[indexParent];index = indexParent;}}heap[index] = value;};template<typename T>bool MinHeap<T>::createMinHeap(pTree a[], int length){if (length > capacity)return false;for (int i = 0; i < length; i++){insert(a[i]);}return true;};template<typename T>bool MinHeap<T>::remove(pTree data)//删除元素{if (size == 0)return false;int index;for (index = 0; index < size; index++){if (heap[index]== data)break;}if (index == size)return false;heap[index] = heap[size - 1];size--;filterDown(index, size);return true;};template<typename T>void MinHeap<T>::filterDown(int current, int end)//由下至上进行调整{int child = current * 2 + 1;pTree value = heap[current];while (child <= end){if (child < end && heap[child]->freq > heap[child + 1]->freq)child++;if (value->freq<heap[child]->freq)break;else{heap[current] = heap[child];current = child;child = child * 2 + 1;}}heap[current] = value;};



配对堆:

class PairNode{    public:        pTree element;        PairNode *leftChild;        PairNode *nextSibling;        PairNode *prev;        PairNode(pTree element)        {            this->element = element;            leftChild = NULL;            nextSibling = NULL;            prev = NULL;        }};class PairingHeap{    private:        PairNode *root;        void reclaimMemory(PairNode *t);        void compareAndLink(PairNode * &first, PairNode *second);        PairNode *combineSiblings(PairNode *firstSibling);        PairNode *clone(PairNode *t);    public:        PairingHeap();        PairingHeap(PairingHeap &rhs);        ~PairingHeap();        bool isEmpty();        bool isFull();        pTree &findMin();        PairNode *Insert(pTree &x);        void deleteMin();        void deleteMin(pTree &minItem);        void makeEmpty();        void decreaseKey(PairNode *p, pTree &newVal );        PairingHeap &operator=(PairingHeap &rhs);};PairingHeap::PairingHeap(){    root = NULL;}PairingHeap::PairingHeap(PairingHeap & rhs){    root = NULL;    *this = rhs;}/* * Destroy the leftist heap. */PairingHeap::~PairingHeap(){    makeEmpty();}/* * Insert item x into the priority queue, maintaining heap order. * Return a pointer to the node containing the new item. */PairNode *PairingHeap::Insert(pTree &x){    PairNode *newNode = new PairNode(x);    if (root == NULL)        root = newNode;    else        compareAndLink(root, newNode);    return newNode;}/* * Find the smallest item in the priority queue. * Return the smallest item, or throw Underflow if empty. */pTree &PairingHeap::findMin(){    return root->element;}/* * Remove the smallest item from the priority queue. * Throws Underflow if empty. */void PairingHeap::deleteMin(){    PairNode *oldRoot = root;    if (root->leftChild == NULL)        root = NULL;    else        root = combineSiblings(root->leftChild);    delete oldRoot;}/* * Remove the smallest item from the priority queue. * Pass back the smallest item, or throw Underflow if empty. */void PairingHeap::deleteMin(pTree &minItem){    if (isEmpty())    {        cout<<"The Heap is Empty"<<endl;        return;    }    minItem = findMin();    deleteMin();    cout<<"Minimum Element: "<<minItem<<" deleted"<<endl;}/* * Test if the priority queue is logically empty. * Returns true if empty, false otherwise. */bool PairingHeap::isEmpty(){    return root == NULL;}/* * Test if the priority queue is logically full. * Returns false in this implementation. */bool PairingHeap::isFull(){    return false;}/* * Make the priority queue logically empty. */void PairingHeap::makeEmpty(){    reclaimMemory(root);    root = NULL;}/* * Deep copy.*/PairingHeap &PairingHeap::operator=(PairingHeap & rhs){    if (this != &rhs)    {        makeEmpty( );        root = clone(rhs.root);    }    return *this;}/* * Internal method to make the tree empty. */void PairingHeap::reclaimMemory(PairNode * t){    if (t != NULL)    {        reclaimMemory(t->leftChild);        reclaimMemory(t->nextSibling);        delete t;    }}/* * Change the value of the item stored in the pairing heap. * Does nothing if newVal is larger than currently stored value. * p points to a node returned by insert. * newVal is the new value, which must be smaller *    than the currently stored value. */void PairingHeap::decreaseKey(PairNode *p, pTree &newVal){    if (p->element->freq < newVal->freq)        return;    p->element = newVal;    if (p != root)    {        if (p->nextSibling != NULL)            p->nextSibling->prev = p->prev;        if (p->prev->leftChild == p)            p->prev->leftChild = p->nextSibling;        else            p->prev->nextSibling = p->nextSibling;            p->nextSibling = NULL;            compareAndLink(root, p);    }}/* * Internal method that is the basic operation to maintain order. * Links first and second together to satisfy heap order. * first is root of tree 1, which may not be NULL. *    first->nextSibling MUST be NULL on entry. * second is root of tree 2, which may be NULL. * first becomes the result of the tree merge. */void PairingHeap::compareAndLink(PairNode * &first, PairNode *second){    if (second == NULL)        return;    if (second->element->freq < first->element->freq)    {        second->prev = first->prev;        first->prev = second;        first->nextSibling = second->leftChild;        if (first->nextSibling != NULL)            first->nextSibling->prev = first;        second->leftChild = first;        first = second;    }    else    {        second->prev = first;        first->nextSibling = second->nextSibling;        if (first->nextSibling != NULL)            first->nextSibling->prev = first;        second->nextSibling = first->leftChild;        if (second->nextSibling != NULL)            second->nextSibling->prev = second;        first->leftChild = second;    }}/* * Internal method that implements two-pass merging. * firstSibling the root of the conglomerate; *     assumed not NULL. */PairNode *PairingHeap::combineSiblings(PairNode *firstSibling){    if (firstSibling->nextSibling == NULL)        return firstSibling;    static vector<PairNode *> treeArray(5);    int numSiblings = 0;    for (; firstSibling != NULL; numSiblings++)    {        if (numSiblings == treeArray.size())            treeArray.resize(numSiblings * 2);        treeArray[numSiblings] = firstSibling;        firstSibling->prev->nextSibling = NULL;        firstSibling = firstSibling->nextSibling;    }    if (numSiblings == treeArray.size())        treeArray.resize(numSiblings + 1);    treeArray[numSiblings] = NULL;    int i = 0;    for (; i + 1 < numSiblings; i += 2)        compareAndLink(treeArray[i], treeArray[i + 1]);    int j = i - 2;    if (j == numSiblings - 3)        compareAndLink (treeArray[j], treeArray[j + 2]);    for (; j >= 2; j -= 2)        compareAndLink(treeArray[j - 2], treeArray[j] );    return treeArray[0];}/* * Internal method to clone subtree. */PairNode *PairingHeap::clone(PairNode * t){    if (t == NULL)        return NULL;    else    {        PairNode *p = new PairNode(t->element);        if ((p->leftChild = clone( t->leftChild)) != NULL)            p->leftChild->prev = p;        if ((p->nextSibling = clone( t->nextSibling)) != NULL)            p->nextSibling->prev = p;        return p;    }}



d路堆:

class DaryHeap{    private:        int d;        int currentSize;        int size;        pTree *array;    public:        /*         * Constructor         */        DaryHeap(int capacity, int numKids)        {            currentSize = 1;            d = numKids;            size = capacity + 1+1;            array=new pTree[capacity + 1+1];        }        /*         * Constructor , filling up heap with a given array         */        /*         * Function to check if heap is empty         */        bool isEmpty()        {            return currentSize == 1;        }        /*         * Check if heap is full         */        bool isFull()        {            return currentSize == size;        }        /*         * Clear heap         */        void makeEmpty( )        {            currentSize = 1;        }        /*         * Function to  get index parent of i         */        int parent(int i)        {            return (i - 1) / d+1;        }        /*         * Function to get index of k th child of i         */        int kthChild(int i, int k)        {            return d * i + k+1;        }        /*         * Function to inset element         */        void Insert(pTree x)        {            if (isFull())            {                cout<<"Array Out of Bounds"<<endl;                return;            }            int hole = currentSize;            currentSize++;            array[hole] = x;            percolateUp(hole);        }        /*         * Function to find least element         */        pTree findMin()        {            if (isEmpty())            {                cout<<"Array Underflow"<<endl;                return 0;            }            return array[1];        }        /*         * Function to delete element at an index         */        pTree Delete(int hole)        {            if (isEmpty())            {                cout<<"Array Underflow"<<endl;                return 0;            }            pTree keyItem = array[hole];            array[hole] = array[currentSize - 1];            currentSize--;            percolateDown( hole );            return keyItem;        }        /*         * Function to build heap         */        void buildHeap()        {            for (int i = currentSize - 1 ; i >=1; i--)                percolateDown(i);        }        /*         * Function percolateDown         */        void percolateDown(int hole)        {            int child;            pTree tmp = array[hole];            for ( ; kthChild(hole, 1) < currentSize; hole = child)            {                child = smallestChild( hole );                if (array[child]->freq < tmp->freq)                    array[hole] = array[child];                else                    break;            }            array[hole] = tmp;        }        /*         * Function to get smallest child from all valid indices         */        int smallestChild(int hole)        {            int bestChildYet = kthChild(hole, 1);            int k = 2;            int candidateChild = kthChild(hole, k);            while ((k <= d) && (candidateChild < currentSize))            {                if (array[candidateChild]->freq < array[bestChildYet]->freq)                    bestChildYet = candidateChild;                k++;                candidateChild = kthChild(hole, k);            }            return bestChildYet;        }        /*         * Function percolateUp         */        void percolateUp(int hole)        {            pTree tmp = array[hole];            for (; hole > 1 && tmp->freq < array[parent(hole)]->freq; hole = parent(hole))                array[hole] = array[ parent(hole) ];            array[hole] = tmp;        }};


在这里面,速度最慢的是配对堆,因为配对堆调整的算法需要进行一系列合并,相当于重建了一个堆。

这里是应用3种优先队列进行10次构建1000000个数据的huffman树所需的时间,总体而言,d路堆和最小堆的时间其实相差并不会特别多,因为都是在数组上进行操作。

这次的体会是,静态数组的速度远比动态数据结构要快很多,虽然会造成空间的浪费,但是时间相当客观


0 0
原创粉丝点击