優先隊列實現

先上測試:

#include<iostream>
#include<vector>
#include<queue>
#include<random>
#include<fstream>
#include"max_heap.h"
#include"boost/progress.hpp"


using namespace std;

fstream output("log.log" , fstream::out);

//生成1000個隨機數,插入,
void test1(){
    boost::progress_timer t; //計算時間
    default_random_engine e;//生成隨機數

    max_heap<int> m;
    for(int i = 0; i != 10000 ; ++i)
        m.push (e());

    //打印頂點的值,彈出頂點,循環直到空爲止.
    while(!m.empty ()){
        output << m.top () << endl;//輸出到文件,查看文件發現輸出全部正確
        m.pop ();
    }
    cout << "max_heap:";
}


//std::priority_queue,與自己的實現性能對比
void test2(){
    boost::progress_timer t;
    default_random_engine e;

    priority_queue<int> q;
    for(int i = 0; i != 10000 ; ++i)
        q.push (e());
    while(!q.empty ()){
        output << q.top () << endl;
        q.pop ();
    }
    cout << "std::priority_queue:";


}

int main()
{
    test1();
    output << "\n========================\n";
    test2 ();
}


結果:

windows\linux:

由於使用了隨機數,所以多測了幾次,結果基本一致.居然比windows的實現快這麼多,我不敢相信我的眼晴.於是去Linux下測試了一下,同一個代碼,windows的居然差這麼多.

結論:1.這次實現還是比較好的.2.windows的實現真的有傳說中的那麼差?


再測試一下使用string的性能(實現的大部份操作是通過簡單的傳值而不是引用),所以有必要測試一下傳值的性能.

void test1(){
    boost::progress_timer t;
    uniform_int_distribution<int> u(0,26);
    default_random_engine e;

    max_heap<string> m;
    for(int i = 0; i != 10000 ; ++i){
        char buf[] = " ";
        buf[0] = 'a' + u(e);
        m.push (buf);

    }
    while(!m.empty ()){
        output << m.top () << endl;
        m.pop ();
    }
    cout << "max_heap:";
}

再上結果:

windows居然用了5秒,果然跟傳聞一樣,另外看來我的實現還是不錯的,

頭文件:

#ifndef MAX_HEAP_H
#define MAX_HEAP_H

#include<vector>

template<typename T>
class max_heap
{
public:
    max_heap();  
    T& top(); 
    void pop(); 
    void push(const T item);
    bool empty ();  
    int size();
private:
    std::vector<T> vector_;  //用vector實現

    int left(int pos);  //返回左兒子的索引
    int right(int pos); //右兒子索引
    int parent(int pos);  //父親索引
    bool isleaf(int pos); //判斷是否爲葉結點
    void heapify(int pos); //使pos結點保持最大堆性質

    void build_heap(); //建堆
};


#include"max_heap.cpp"  //分離模版
#endif // MAX_HEAP_H

實現部分:

#ifndef HEAPCPP
#define HEAPCPP

#include"max_heap.h"

template<typename T>
max_heap<T>::max_heap(){ //默認構造函數
}

template<typename T>
bool max_heap<T>::empty (){
    return vector_.empty ();  
}

template<typename T>
T& max_heap<T>::top(){  
    return vector_.front ();
}

template<typename T>
int max_heap<T>::left(int pos){ 
    return 2*pos +1;
}

template<typename T>
int max_heap<T>::right (int pos){
    return 2*pos + 2;
}

template<typename T>
int max_heap<T>::parent (int pos){
    return (pos-1)/2;
}

template<typename T>
int max_heap<T>::size(){
    return vector_.size (); //元素個數
}

template<typename T>
bool max_heap<T>::isleaf(int pos){
    int n = size();
    return (n/2 <= pos) && (pos <= n-1);  //元素位於最底一層,並不能大於size-1,則爲葉結點
}

template<typename T>
void max_heap<T>::heapify (int pos){
    if (isleaf (pos))
        return;  //葉結點,跳出

    int largestpos = pos; // 最大的索引
    int left_pos = left(pos); //左索引
    int right_pos = right(pos); //右索引

    //1.兒子的索引不能超過size - 1, 找出比較大的元素在哪裏
    if (left_pos <= size()-1 && vector_[left_pos] > vector_[largestpos])
        largestpos = left_pos; 

    if (right_pos <= size()-1 && vector_[right_pos] > vector_[largestpos])
        largestpos = right_pos;

    //如果比較大的元素不是本結點,則要交換本結點的最大元素結點的值,對被交換的結點遞歸
    if (largestpos != pos){  
        auto temp = vector_[pos];
        vector_[pos] = vector_[largestpos];
        vector_[largestpos] = temp;

        heapify (largestpos);
    }

}

//建堆,從倒數第二層開始,往根結點推進
template<typename T>
void max_heap<T>::build_heap (){
    for (int pos = (size()-1)/2 ; pos >= 0 ; --pos)
        heapify (pos);
}

template<typename T>
void max_heap<T>::pop(){
    if (size() == 0) //沒有元素,拋出異常
        throw std::runtime_error("out of range");

    //把最後一個元素調至第一位,刪除最後一個元素,調用heapify使堆保持性質.
    vector_[0] = vector_[size() -1];
    vector_.pop_back ();
    
    heapify (0);

}

//在尾部插入值,然後迭代上升,找到適合的位置.
template<typename T>
void max_heap<T>::push (const T item){
    vector_.push_back (item);

    int currpos = size()-1;
    int parentops = parent (currpos);

    while (vector_[parentops] < vector_[currpos]){
        auto temp = vector_[currpos];
        vector_[currpos] =  vector_[parentops];
        vector_[parentops] = temp;

        currpos = parentops;
        parentops = parent (currpos);

        if (currpos == 0) //到頂部,結束
            break;

    }
}
#endif




實現沒什麼好說的.標準的二叉堆,另個,在頭文件的尾部加一句#include"max_heap.cpp",能使模版的實現的定義分離


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章