面對查找需求如何選擇容器

面對查找需求如何選擇容器

在寫代碼的時候,即使編程老手經常會遇到一個不知道如何抉擇的事情,面對查詢的需求如何選擇容器,容器的大小等因素也會困擾我們的選擇。爲什麼呢?新手面對查詢往往會直接選擇map,因爲map是內部是支持查詢函數的,但老手知道map是通過複雜性換取查詢的性能的(map的實現往往是紅黑樹),那如果要保存的數據個數不多呢,是否值得使用map這樣的容器呢?

最近兩天寫了幾行短小的代碼,針對這個問題進行了一測試,測試對vector,map,hash_map三種有代表性的容器進行了測試,測試容器的長度爲10501002005001000.測試的方法是使用int作爲測試對象,vector的查詢使用順序查找,maphash_map的查詢使用容器的find函數。爲了能表現出測試結果,查詢測試了1000000次,開始時,查詢的數據我用rand函數產生隨機數作爲查詢對象,後來發現好像對查詢干擾過大,最後還是使用了順序數據作爲查詢對象。

由於測試結果數據枯燥,我在後面再附錄上測試的程序。每個測試都作了3次,取平均值給大家看看結果。測試使用的是STLPortVisual Studio 2003DEBUG版本。測試結果如下:

                                                                                                                                                             表1 各種容器的耗時

容器容納的尺寸

vector(ms)

map(ms)

hash_map(ms)

10

578

1333

1333

20

1078

1562

1328

50

2520

1921

1328

100

4953

2176

1328

200

9806

2422

1322

500

24437

2739

1323

1000

48827

2942

1317

 

在容器的數量小於20個的時候,vector的還表現良好,即使有查詢的需求,也可以考慮直接選擇vector,但當容器的數據超過50個以後、,map的優勢就顯示出來了。而且當容器的容量繼續增大後,map的查詢速度增加也很平穩,當然這和map的實現是採取紅黑樹,查詢的時間複雜度是log2(N)有關。而且hash_mapunorder_map)表現只能用穩定高效形容。所以在大部分時候hash_map是我們的首選。

由於測試中有其他的干擾信息,所以測試數據不等於實際效率。這個數據只是一個參考數據。但是我們大致可以得到一些感覺,容器的尺寸小於20時,我們大可以選擇vector作爲容器。不用選擇更加複雜的容器。如果要容納的對象個數大於50而且需要查詢的時候,vector就不要選擇了。用更快的容器。對於maphash_map,優先選擇hash_map。當然我說的是STLporthash_map,不是微軟默認的。我在前面《慎用Visual Studio C++默認的hash_map》的文章說明過這個問題了。在此不復述了。

同時測試的是很我還測試一個其他問題,就是swtich case的性能,發現swtich case 的性能基本不會隨case的條件增加而增加耗時(懂彙編的要笑話我了,哈哈),而且非常非常非常非常快,所以,如果有時候你追求的極限性能的目標,而且可以用swtich case的時候,可以考慮用這個比較“醜陋”一點的寫法。

BTW:c++編程規範》一書的第76條是,默認使用vector,否則使用其他容器。其中提到了選擇容器的3個原則:

1.    正確性事,簡單,清晰是第一位的

2.    在必要時考慮效率

3.    儘可能編寫事務安全的代碼。(注意插入和刪除的迭代器失效問題的影響)

 

 

附錄測試代碼如下,我懶得寫註釋了。偷懶。

#include <stdio.h>

#include <string.h>

#include <time.h>

#include <math.h>

#include <stdlib.h>

#include <conio.h>

#include <iostream>

#include <fstream>

#include <memory.h>

#include <map>

#include <hash_map>

#include <ace/OS.h>

#include <ace/Time_Value.h>

#include <ace/SString.h>

#include <ace/Shared_Memory_MM.h>

#include <ace/Shared_Memory_SV.h>

#include <ace/Mem_Map.h>

#include <ace/SV_Shared_Memory.h>

 

using namespace std;

 

const size_t TEST_NUMBER = 100000*10;

void test_findwith_container(size_t container_len)

{

    vector<int>          int_vector;

    map<int,int>         int_map;

    hash_map<int,int>    int_hash;

 

    int_vector.resize(container_len);

    int_hash.resize(container_len);

    //

    for(size_t i = 0;i<container_len;i++)

    {

        int_vector[i]=i;

        int_map[i] = i;

        int_hash[i]=i;

    }

    ACE_Time_Value tvStart(0);

    ACE_Time_Value tvEnd(0);

    ACE_Time_Value tvPassTime(0);

 

    tvStart = ACE_OS::gettimeofday();

 

    for (size_t i= 0;i<TEST_NUMBER;++i)

    {

        int find_number =  i%container_len;

        //

        for(size_t j = 0;j<container_len;j++)

        {

            if (int_vector[j]==find_number)

            {

                break;

            }

        }

    }

    tvEnd = ACE_OS::gettimeofday();

    tvPassTime = tvEnd - tvStart;

    cout<<"test vector gettimeofday :"<<tvPassTime.msec()<<" "<<endl;

    tvStart = ACE_OS::gettimeofday();

    for (size_t i= 0;i<TEST_NUMBER;++i)

    {

        int find_number =  i%container_len;

        int_map.find(find_number);

    }

    tvEnd = ACE_OS::gettimeofday();

    tvPassTime = tvEnd - tvStart;

    cout<<"test map gettimeofday :"<<tvPassTime.msec()<<" "<<endl;

    tvStart = ACE_OS::gettimeofday();

    for (size_t i= 0;i<TEST_NUMBER;++i)

    {

        int find_number =  i%container_len;

        int_hash.find(find_number);

    }

    tvEnd = ACE_OS::gettimeofday();

    tvPassTime = tvEnd - tvStart;

    cout<<"test hash gettimeofday :"<<tvPassTime.msec()<<" "<<endl;

}

 

//

int main(int argc, ACE_TCHAR* argv[])

{

  

    for (int j=0;j<3;++j)

    {

        cout<<"container length = 10 "<<endl;

        test_findwith_container(10);

        cout<<"container length = 20 "<<endl;

        test_findwith_container(20);

        cout<<"container length = 50 "<<endl;

        test_findwith_container(50);

        cout<<"container length = 100 "<<endl;

        test_findwith_container(100);

        cout<<"container length = 200 "<<endl;

        test_findwith_container(200);

        cout<<"container length = 500 "<<endl;

        test_findwith_container(500);

        cout<<"container length = 1000 "<<endl;

        test_findwith_container(1000);

    }

 

    _getch();

    return 0;

}

 

發佈了79 篇原創文章 · 獲贊 32 · 訪問量 56萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章