现在的位置: 首页 > 综合 > 正文

堆的构建

2014年07月10日 ⁄ 综合 ⁄ 共 3680字 ⁄ 字号 评论关闭

       堆,又可以称为优先级队列,这种数据结构插入和删除操作需要o(lgn)的时间复杂度,但是却能在o(1)的时间复杂度内取出最大值或最小值。

      堆有最大堆和最小堆,最大堆中任意节点的关键码大于或等于它的左、右子女的关键码,相反,最小堆中任意节点的关键码小于或等于它的左、右子女的关键码。

      如果堆的索引从0开始,则有如下关系式:

             (1)左子女:2*i+1

             (2)右子女:2*i+2

             (3)父亲节点:向下取整((i-1)/2)   

【注】这是索引,给定一个数组长度,应该先通过len-1得到最后一个元素的索引,在通过第三条的公式开始调整。


堆的调整

(1)向下调整(删除堆顶元素)

/*copyright@ CNV && lsj*/
/*最小堆*/

#include<iostream>
#include<algorithm>
using namespace std;

#define LEFT(i) (((i)<<1)+1)
#define RIGHT(i) (((i)<<1)+2)
#define CHILD(i) (((i)-1)>>1)
typedef int RecType;

/*从上往下调整 ---删除堆顶元素的调整*/
void SiftDown(RecType minHeap[],int low,int high)
{
     int i = low;
     int j = LEFT(i);
     int base = minHeap[i];
     while(j<=high){
	    //与小的比较,必须是j<high没有等号
	    if(j<high && minHeap[j+1]<minHeap[j])j++;
	    if(minHeap[j]>=base)break;
	    else{
    	        //上移
	         minHeap[i] = minHeap[j];
   	         i = j;
 	         j = LEFT(i);
	    }
     }
     minHeap[i] = base;
};

(2)向上调整(插入元素,插入堆尾部)

/*从下往上调整 ---往堆中插入元素的调整*/
void SiftUp(RecType minHeap[],int high)
{
     int j = high;
     int i = CHILD(j);
     int base = minHeap[j];
     while(i>0){
	     if(minHeap[i]<=base)break;
	     else{
 	        //下移
	        minHeap[j] = minHeap[i];
   	        j = i;
	        i = CHILD(j);
	     }
     }
    minHeap[j] = base;
};

(3)堆排序

//逆序--》从大到小
void HeapSort(RecType arr[],int len)
{
    int lastIndex = len -1;//由长度转换为索引
    int beginIndex = (lastIndex-1)>>1;
    //下面构建了一个堆,o(nlogn)
    while(beginIndex>=0){
	    SiftDown(arr,beginIndex,len-1);
	    --beginIndex;
    }

    //排序
    for(int i=len-1;i>=0;i--){
	    swap(arr[0],arr[i]);
	    SiftDown(arr,0,i-1);
    }
};

STL中的堆(面试的时候用得着

(1)利用make_heap构建堆(STL源码剖析P181)

      STL提供堆结构,但却是幕后工作者,heap可以分为max_heap和min_heap。记住几个重要的接口:make_heap、push_heap、pop_heap、sort_heap。

     这几个接口输入参数是这样的:

template<class RandomAccessIterator,Class Compare>

inline void make_heap(RandomAccessIterator first,RandomAccessIterator last, Compare comp);

    

注:通过给上面各函数传入不同的仿函数,分别构造最大堆还是最小堆

#include<iostream>
#include<algorithm>
#include<vector>
#include<functional>
using namespace std;
int main()
{
    int arr[]={0,1,2,3,4,8,9,3,5};
    vector<int>ivec(arr,arr+9);
    //greater<int> comp;//最小堆
    less<int> comp;//最大堆
    make_heap(ivec.begin(),ivec.end(),comp);
    
    //9 5 8 3 4 0 2 3 1
    for(int i=0;i<ivec.size();++i){
	cout<<ivec[i]<<" ";
    }
    cout<<endl;


    ivec.push_back(7);
    push_heap(ivec.begin(),ivec.end(),comp);
    //9 7 8 3 5 0 2 3 1 4
    for(int i=0;i<ivec.size();++i){
	cout<<ivec[i]<<" ";
    }
    cout<<endl;


    pop_heap(ivec.begin(),ivec.end(),comp);
    cout<<ivec.back()<<endl;//9
    ivec.pop_back();
    
    sort_heap(ivec.begin(),ivec.end(),comp);
    //9 7 8 3 5 0 2 3 1 4
    for(int i=0;i<ivec.size();++i){
	cout<<ivec[i]<<" ";
    }

    system("pause");
    return 0;
}

(2)利用priority_queue构建堆(STL源码剖析P183,其实利用了上面的接口)

       STL中提供了一种priority_queue,缺省情况下利用max_heap完成。STL中的priority_queue往往不被归类为容器,而是被归类为容器迭代器。

STL中的声明priority_queue声明如下:

template<class T,class Sequence = vector<T>,class Compare=less<typename Sequence::value_type>>

class priority_queue{

      ....

}

从上面的定义看出,STL的priority_queue采用vector实现,且Compare比较函数为仿函数less,我们可以传入greater,构造最小堆。

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int main()
{
    int arr[]={0,1,2,3,4,5,8,9,3,5};
    priority_queue<int> ipq(arr,arr+9);
    cout<<"size="<<ipq.size()<<endl;
    while(!ipq.empty()){
	cout<<ipq.top()<<" ";
	ipq.pop();
    }
    system("pause");
}

换一个仿函数就能构造最小堆:

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int main()
{
    int arr[]={0,1,2,3,4,5,8,9,3,5};
    priority_queue<int,vector<int>,greater<int>> ipq(arr,arr+9);
    cout<<"size="<<ipq.size()<<endl;
    while(!ipq.empty()){
	cout<<ipq.top()<<" ";
	ipq.pop();
    }
   system("pause");
   return 0;
}

(3)利用set(或者multiset)构建堆(剑指offer P169页)

#include<iostream>
#include<algorithm>
#include<functional>
#include<set>
using namespace std;

typedef greater<int> Greater;//最大堆
typedef less<int> Less;//最小堆
typedef multiset<int,Less> MaxHeap;
typedef multiset<int,Less>::iterator Iterator;


int main()
{
    int arr[]={0,1,2,3,4,8,9,3,5};

    MaxHeap heap;
    for(int i=0;i<9;i++){
	    heap.insert(arr[i]);
    }
    for(Iterator it = heap.begin();it!=heap.end();++it){
	    cout<<*it<<" ";
    }
    cout<<endl;

    heap.erase(heap.begin());
    heap.insert(10);
    for(Iterator it = heap.begin();it!=heap.end();++it){
	    cout<<*it<<" ";
    }
    system("pause");
    return 0;
}






抱歉!评论已关闭.