程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 堆的構建

堆的構建

編輯:C++入門知識

     堆,又可以稱為優先級隊列,這種數據結構插入和刪除操作需要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; 
}; 

/*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)向上調整(插入元素,插入堆尾部)

 

[cpp
/*從下往上調整 ---往堆中插入元素的調整*/ 
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; 
}; 

/*從下往上調整 ---往堆中插入元素的調整*/
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)堆排序


[cpp]
//逆序--》從大到小  
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); 
    } 
}; 

//逆序--》從大到小
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);

   

注:通過給上面各函數傳入不同的仿函數,分別構造最大堆還是最小堆


[cpp] 
#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; 

#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,構造最小堆。


[cpp] 
#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"); 
}<SPAN style="FONT-SIZE: 18px"> 
</SPAN> 

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

換一個仿函數就能構造最小堆:

[cpp] 
#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; 

#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頁)

[cpp]
#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; 

#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;
}[cpp] 
<P></P><PRE></PRE> 
<PRE></PRE> 
<PRE></PRE> 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved