堆的实现-用数组表示的完全二叉树

堆时一种具有优先级的队列,取出元素的顺序按照元素的优先级
堆若用数组和链表,二者的插入时间复杂度为O(1),删除时间复杂度为O(N)
若用有序数组或有序链表,插入操作所需时间均为O(N),删除操作所需时间复杂度为O(1)
更为理想的堆实现方式为:用数组表示的完全二叉树.
另外将该完全二叉树调整为任何父结点都比左子树和右子树的元素大(最大堆)
我们来看以下这样实现的好处:
插入操作:
直接在数组元素的后面插入即可,插入后再逐层比较该结点与父结点的大小并将其调 整为最大堆—时间复杂度O(logN).
删除操作:
删除根结点,并取出元素的最后一个元素补充到根结点,然后逐层比较该元素与子结点的大小,依然调整为最大堆。时间复杂度O(logN)
当数据量较大时用二叉树实现的堆的效率就能得到充分体现
二者的实现代码请参照代码push()和pop()

另外,如何建一个堆,在实际应用中,一个堆中事先应该有一定数量的元素。因此,一个堆的初始化利用一个数组来初始化,首先将数组中的元素用完全二叉树的形式实现,然后再从最后一个元素的父结点开始逐个向上将子树调整为最大堆,最后便将该完全二叉树表示成了一个最大堆,方法与删除略有类似。这样就建了一个具有一定元素的初始堆。

heap.h文件
#ifndef HEAP_H
#define HEAP_H
#include<iostream>
#include<new>
using namespace std;
template<typename T>
class MaxHeap{
private:
    T *heap;
    int heapSize;
    int heapCapacity;
public:
    MaxHeap(int heapcap=20) 
    {
        heapSize = 0;
        heapCapacity = heapcap;
        heap=new T[heapCapacity+1];
    }
    ~MaxHeap(){delete [] heap;}
    int size(){return heapSize;}
    int capacity(){return heapCapacity;}
    void push(T element)
    {

        if(heapSize==heapCapacity)
        {
            cout << "堆满!" << endl;
        }
        else
        {
            int currentNode = ++heapSize;
            while(currentNode!=1&&heap[currentNode/2]<element)
            {
                heap[currentNode]=heap[currentNode/2];
                currentNode /= 2;;
            }
            heap[currentNode]=element;
        }
    }
    void pop()
    {
        if(heapSize==0)
        {
            cout << "已空" << endl;
        }
        else
        {
            T lastelement = heap[heapSize--];
            int currentNode = 1;
            int child = 2;
            while(child <= heapSize)
            {
                if(child<heapSize && heap[child] < heap[child+1])
                    child++;
                if(lastelement >= heap[child])
                    break;
                heap[currentNode]=heap[child];
                currentNode = child;
                child *= 2;
            }
            heap[currentNode]= lastelement;
        }
    }

    /*
        利用一个给定的数组表示一个完全二叉树,然后将此完全二叉树调整为最大堆
        注意:数组表示的完全二叉树(根结点下标从1开始)的左孩子=2*父结点,父结点=孩子/2
             完全二叉树的根结点的下标从1开始
    */
    void initHeap(T *array, int len)
    {
        heapSize=len;
        for(int i=1;i<=heapSize;i++)
            heap[i]=array[i];

        //将一个数组对应的完全二叉树转化成最大堆树
        for(int root=heapSize/2;root>=1;root--)
        {
            T rootelement = heap[root];
            int child = 2*root;
            while(child <= heapSize)
            {
                if(child<heapSize && heap[child] < heap[child+1])//heap[child]为兄弟中的较大者
                    child++;
                if(rootelement>=heap[child])//已经为最大堆
                    break;
                heap[child/2]=heap[child];//将最大的儿子移到根结点
                child *= 2;     //将原根结点继续与下层的比较
            }
            heap[child/2] = rootelement;
        }
    }

    void print()
    {
        for(int i=1; i<=heapSize;++i)
            cout << heap[i] << " ";
        cout << endl;
    }
};
#endif

main.cpp 测试文件

#include"heap.h"
#include<iostream>
#include<new>
using namespace std;
int main()
{
    int arry[11]={0,20,12,35,15,10,80,30,17,2,1};
    for(int i=1;i<11;i++)
        cout << arry[i] << " ";
    cout << endl;
    MaxHeap<int> myHeap;
    myHeap.initHeap(arry,10);
    myHeap.print();
    cout << myHeap.size() << " " << myHeap.capacity() << endl;

    myHeap.push(5);
    myHeap.push(60);
    myHeap.push(31);
    myHeap.push(100);
    myHeap.push(40);
    myHeap.push(14);
    myHeap.print();
    cout << myHeap.size() << " " << myHeap.capacity() << endl;
    myHeap.pop();
    myHeap.pop();
    myHeap.print();
    cout << myHeap.size() << " " << myHeap.capacity() << endl;
}






猜你喜欢

转载自blog.csdn.net/Gouhailiang/article/details/53084912