维护堆的性质

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中的堆操作

see reference

#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;
    }
};

2.POJ1442 Black Box

你可能感兴趣的:(堆)