【Data Structure】堆与优先队列

来源:互联网 发布:国外免费wifi软件 编辑:程序博客网 时间:2024/05/29 17:26

本文介绍一下重要的数据结构:堆,并以C++实现了整数最小堆。

堆是一种完全二叉树,特点是其根大于/小于其儿子,并且这个特性是递归定义的。这样的数据结构用于实现logN复杂度下进行一次最值得查询。



上图显示了一个最小堆。由于堆是完全二叉树,所以底层的数据结构用数组就可以了(当然C++里用vector更好)。那么,我们应该使堆具有哪些操作呢?首先我们应该可以实现对元素的插入。假设我们已经有一个堆,如何插入一个元素且保持对的性质呢?

首先我们写一个Heap类,底层用一个vector保存数据,把data[0]设为哨兵,这样有利于下标的操作。加入的时候,先把数据扔到数组尾部,然后再逐步往上(沿着父节点)直到调整到合适的位置。


上图实现了14的插入,具体代码如下:

void push(int temp)    {        data.push_back(temp);        int cur=data.size()-1;        while(cur!=1)        {            int father=cur/2;            if(data[cur]<data[father])            {                int t=data[cur];                data[cur]=data[father];                data[father]=t;            }            cur=father;        }    }
下面我们考虑如何删除并输出最小值。显而易见,最小值就是data[1]。此时,我们把最尾部的数甩到根上,再逐步往下移动到合适位置。



由上图,我们此时应该对31进行percolate down,具体实现(包括pop)如下:

    void pop()    {        cout<<data[1]<<endl;        data[1]=data[data.size()-1];        data.pop_back();        percolateDown(1);    }    void percolateDown(int hole)    {        int child;        int tmp=data[hole];        for(;hole*2<data.size();hole=child)//中间判断是不是叶子,最后更新hole(当然也可以写在循环中)        {            child=hole*2;//left child            if(child!=data.size()-1&&data[child+1]<data[child])//if there is a right child and less then the left one                child++;            if(data[child]<tmp)//less than child,then swap                data[hole]=data[child];            else                break;        }        data[hole]=tmp;//补上hole,此时hole显然已经变了    }

最后,我们还要想办法实现把乱序数组初始化为堆。其实我们只要对数组的前一半用percolate down就好了。

另外,优先队列其实就是堆的一种外包装,pop操作弹出的事最值,这是利用堆来实现的,下面是heap类的完整代码(省去了析构函数),实际上就可以当做优先队列来用了。

class Heap{private:    vector<int> data;public:    Heap(){data.push_back(-1);}    Heap(const vector<int>& item)    {        data.push_back(-1);        for(int i=0;i<item.size();i++)            data.push_back(item[i]);    }    void push(int temp)    {        data.push_back(temp);        int cur=data.size()-1;        while(cur!=1)        {            int father=cur/2;            if(data[cur]<data[father])            {                int t=data[cur];                data[cur]=data[father];                data[father]=t;            }            cur=father;        }    }    void pop()    {        cout<<data[1]<<endl;        data[1]=data[data.size()-1];        data.pop_back();        percolateDown(1);    }    void percolateDown(int hole)    {        int child;        int tmp=data[hole];        for(;hole*2<data.size();hole=child)//中间判断是不是叶子,最后更新hole(当然也可以写在循环中)        {            child=hole*2;//left child            if(child!=data.size()-1&&data[child+1]<data[child])//if there is a right child and less then the left one                child++;            if(data[child]<tmp)//less than child,then swap                data[hole]=data[child];            else                break;        }        data[hole]=tmp;//补上hole,此时hole显然已经变了    }    bool empty()    {        return !(data.size()-1);    }    void print()    {        for(int i=1;i<data.size();i++)            cout<<data[i]<<' ';        cout<<endl;    }    void build_heap()    {        for(int i=(data.size()-1)/2;i>=1;i--)        {            percolateDown(i);        }    }};


0 0
原创粉丝点击