维护堆的性质
MAX-HEAPIFY是用于维护最大堆性质的重要过程。输入为待维护的数组,与待维护的节点i。时间复杂度为O(lgn),即树的高度h
MAX_HEAPIFY(A,i)
l=LEFT(i)
r=RIGHT(i)
if l<=A.heapSize and A[l]>A[i]
largest=l
else largest=i
if r<=A.heapSize and A[r]>A[largest]
largest=r
if largest!=i
exchange A[i] with A[largest]
MAX-HEAPIFY(A,largest)
建堆
利用自底向上的方法利用过程MAX-HEAPIFY把一个大小为n=A.lenght的数组转换为最大堆。因为数组中A([n/2]+1..n)中的元素都是叶子节点。每个叶子节点可看成只含有一个元素的堆。因此建堆过程BUILD-MAX-HEAP过程只需调用n/2次 MAX-HEAPIFY即可。
BUILD-MAX-HEAP(A)
A.heap-size=A.length
for i=[A.length/2] downto 1
MAX-HEAPIFY(A,i)
一个c++的最大堆类
#include <iostream>
#include <vector>
using namespace std;
class UnderflowException{ };
template<typename Comparable>
class BinaryHeap
{
public:
explicit BinaryHeap(int capacity=100)
:array(capacity+1),currentSize(0){}
explicit BinaryHeap(const vector<Comparable> &items)
:array(items.size()+10),currentSize(items.size()){
for(int i=0;i<items.size();++i)
//为方便操作,堆从下标1开始存储
array[i+1]=items[i];
buildMaxHeap();
}
bool isEmpty()const{
return currentSize==0;
}
int currSize()const{
return currentSize;
}
void print(){
for(int i=1;i<=currentSize;++i){
cout<<array[i]<<" ";
}
cout<<endl;
}
Comparable& findMax() const{
if (isEmpty())
throw UnderflowException();
return array[1];
}
//Increase the value in position i to key
int increaseKey(int i,const Comparable &key){
if (key<array[i]){
cout<<"new key is smaller than current,can not change"<<endl;
return -1;
}
array[i]=key;
while(i>1 && array[i/2]<array[i]){
std::swap(array[i/2],array[i]);
i=i/2;
}
return 0;
}
//Insert the x into the heap
void insert(const Comparable &x){
if(currentSize==array.size()-1)
array.resize(array.size()*2);
int hole=++currentSize;
array[hole]=INT_MIN;
increaseKey(hole,x);
}
/**
* Remove the maximum item and return it
* Throw Underflow if empty
*/
Comparable deleteMax(){
if(isEmpty())
throw UnderflowException{};
Comparable tmp=array[1];
std::swap(array[1],array[currentSize--]);
maxHeapIfy(1);
return tmp;
}
//heapsort
void heapSort(vector<Comparable> &vec){
while(currentSize){
Comparable tmp=deleteMax();
vec.push_back(tmp);
}
}
private:
int currentSize; //number of elements in heap
vector<Comparable> array;
/**
* Establish heap order property from an arbitraty
* arrangement of items.Runs in nlgn times.
*/
void buildMaxHeap(){
for(int i=currentSize/2;i>0;--i)
maxHeapIfy(i);
}
/**
* 保持最大堆的性质,使得根节点大于子节点
*/
void maxHeapIfy(int hole){
int child;
Comparable tmp=std::move(array[hole]);
for(;hole*2<=currentSize;hole=child){
child=hole*2;//the left child
//if the right child exist,choose the max child
if(child!=currentSize && array[child+1]>array[child])
++child;//child is the right child
//if the max child greater than the father,exchange
if (array[child]>tmp)
array[hole]=std::move(array[child]);
else
break;
}
array[hole]=std::move(tmp);
}
};
int main()
{
vector<int> vec{4,1,3,2,16,9,10,14,8,7};
BinaryHeap<int> heap{vec};
heap.print();
heap.increaseKey(9,15);
heap.print();
heap.insert(10);
heap.print();
vector<int> vecsort;
heap.heapSort(vecsort);
for(auto v:vecsort)
cout<<v<<" ";
cout<<endl;
}
c++11中的堆操作
#include <iostream> // std::cout
#include <algorithm> // std::make_heap, std::pop_heap, std::push_heap, std::sort_heap
#include <vector> // std::vector
using namespace std;
auto comp=[](int v1,int v2){return v1>v2;};//升序
int main () {
int myints[] = {10,20,30,5,15};
std::vector<int> v(myints,myints+5);
//建立一个最小堆
std::make_heap (v.begin(),v.end(),comp);
for(auto val:v)
cout<<val<<" ";
cout<<endl;
/**
* 将最小堆的最小元素放到数组末尾
* 因为实现方式,就是首元素与末尾元素交换后,再执行一次维护最小堆的操作
* 类似于上面自己写的类中的delete
*/
std::pop_heap (v.begin(),v.end(),comp);
for(auto val:v)
cout<<val<<" ";
cout<<endl;
v.pop_back();
for(auto val:v)
cout<<val<<" ";
cout<<endl;
v.push_back(99);
for(auto val:v)
cout<<val<<" ";
cout<<endl;
/**
* 再插入一个元素后执行一次维护最小堆的操作
* 类似于上面自己写的堆中的insert
*/
std::push_heap (v.begin(),v.end(),comp);
for(auto val:v)
cout<<val<<" ";
cout<<endl;
std::sort_heap (v.begin(),v.end(),comp);
for(auto val:v)
cout<<val<<" ";
cout<<endl;
return 0;
}
堆的相关算法题
1.Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
解题思路:vector中元素为每个列表的头部指针,vector维护一个最小堆的性质,然后不断pop出第一个元素即最小值。因为维护最小堆的复杂度为lgn,总共有K个列表,则复杂度为Klgn。
解题技巧:与其自己写一个最小堆,不如用好c++11中的make_heap,pop_heap,push_heap等,因为自己写一个最小堆,index要从1开始,所以可能要copy一遍元素。用c++中的alrogithm会比较简单。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists){
ListNode fake_head(0);
if(lists.empty()){
return NULL;
}
for(auto itr=lists.begin();itr!=lists.end();){
if(*itr==NULL){
itr=lists.erase(itr);
}
else{
itr++;
}
}
auto cmp=[](ListNode *l,ListNode *r){return l->val>r->val;};
make_heap(lists.begin(),lists.end(),cmp);
ListNode* ll=&fake_head;
while(!lists.empty()){
ll->next=lists.front();
ll=ll->next;
pop_heap(lists.begin(),lists.end(),cmp);
if(lists.back()->next==NULL)
lists.pop_back();
else{
lists.back()=lists.back()->next;
push_heap(lists.begin(),lists.end(),cmp);
}
}
return fake_head.next;
}
};