zoukankan      html  css  js  c++  java
  • 堆的构建

           堆,又可以称为优先级队列,这种数据结构插入和删除操作需要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(base<=minHeap[j])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(),greater<int>,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;
    }
  • 相关阅读:
    UVa 11991 Easy Problem from Rujia Liu?
    UVa 11995 I Can Guess the Data Structure!
    LA 3485 (积分 辛普森自适应法) Bridge
    LA 5009 (三分法求极值) Error Curves
    软帝学院:一万字的Java基础知识总结大全(实用)
    学java可以做些什么
    从零开始学习java一般需要多长时间?
    学习java需要英语很好吗?
    java的8种基本数据类型
    什么是java变量,java变量是什么
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3228712.html
Copyright © 2011-2022 走看看