2009-05-01 29 views

回答

15

從理論上比較算法有很好的答案。爲了好奇,我將std::sortstd::stable_sortgoogle/benchmark進行了基準比較。

提前指出是有用的;

  • 基準機具有1 X 2500 MHz CPU1 GB RAM
  • 基準OS Arch Linux 2015.08 x86-64
  • 基準與g++ 5.3.0clang++ 3.7.0-std=c++11-O3-pthread)編譯
  • BM_Base*基準試圖測量填充std::vector<>的時間。爲了更好地比較,應該從排序結果中減去該時間。

第一基準排序std::vector<int>512k大小。

[ g++ ]# benchmark_sorts --benchmark_repetitions=10 
Run on (1 X 2500 MHz CPU) 
2016-01-08 01:37:43 
Benchmark       Time(ns) CPU(ns) Iterations 
---------------------------------------------------------------- 
... 
BM_BaseInt/512k_mean    24730499 24726189   28 
BM_BaseInt/512k_stddev    293107  310668   0 
... 
BM_SortInt/512k_mean    70967679 70799990   10 
BM_SortInt/512k_stddev    1300811 1301295   0 
... 
BM_StableSortInt/512k_mean  73487904 73481467   9 
BM_StableSortInt/512k_stddev  979966  925172   0 
[ clang++ ]# benchmark_sorts --benchmark_repetitions=10 
Run on (1 X 2500 MHz CPU) 
2016-01-08 01:39:07 
Benchmark       Time(ns) CPU(ns) Iterations 
---------------------------------------------------------------- 
... 
BM_BaseInt/512k_mean    26198558 26197526   27 
BM_BaseInt/512k_stddev    320971  348314   0 
... 
BM_SortInt/512k_mean    70648019 70666660   10 
BM_SortInt/512k_stddev    2030727 2033062   0 
... 
BM_StableSortInt/512k_mean  82004375 81999989   9 
BM_StableSortInt/512k_stddev  197309  181453   0 

第二個基準排序std::vector<S>512k大小(sizeof(Struct S) = 20)。

[ g++ ]# benchmark_sorts --benchmark_repetitions=10 
Run on (1 X 2500 MHz CPU) 
2016-01-08 01:49:32 
Benchmark       Time(ns) CPU(ns) Iterations 
---------------------------------------------------------------- 
... 
BM_BaseStruct/512k_mean   26485063 26410254   26 
BM_BaseStruct/512k_stddev   270355  128200   0 
... 
BM_SortStruct/512k_mean   81844178 81833325   8 
BM_SortStruct/512k_stddev   240868  204088   0 
... 
BM_StableSortStruct/512k_mean 106945879 106857114   7 
BM_StableSortStruct/512k_stddev 10446119 10341548   0 
[ clang++ ]# benchmark_sorts --benchmark_repetitions=10 
Run on (1 X 2500 MHz CPU) 
2016-01-08 01:53:01 
Benchmark       Time(ns) CPU(ns) Iterations 
---------------------------------------------------------------- 
... 
BM_BaseStruct/512k_mean   27327329 27280000   25 
BM_BaseStruct/512k_stddev   488318  333059   0 
... 
BM_SortStruct/512k_mean   78611207 78407400   9 
BM_SortStruct/512k_stddev   690207  372230   0 
... 
BM_StableSortStruct/512k_mean 109477231 109333325   8 
BM_StableSortStruct/512k_stddev 11697084 11506626   0 

任何人誰喜歡跑的標杆,這裏是代碼,

#include <vector> 
#include <random> 
#include <algorithm> 

#include "benchmark/benchmark_api.h" 

#define SIZE 1024 << 9 

static void BM_BaseInt(benchmark::State &state) { 
    std::random_device rd; 
    std::mt19937 mt(rd()); 
    std::uniform_int_distribution<int> dist; 

    while (state.KeepRunning()) { 
    std::vector<int> v; 
    v.reserve(state.range_x()); 
    for (int i = 0; i < state.range_x(); i++) { 
     v.push_back(dist(mt)); 
    } 
    } 
} 
BENCHMARK(BM_BaseInt)->Arg(SIZE); 

static void BM_SortInt(benchmark::State &state) { 
    std::random_device rd; 
    std::mt19937 mt(rd()); 
    std::uniform_int_distribution<int> dist; 

    while (state.KeepRunning()) { 
    std::vector<int> v; 
    v.reserve(state.range_x()); 
    for (int i = 0; i < state.range_x(); i++) { 
     v.push_back(dist(mt)); 
    } 

    std::sort(v.begin(), v.end()); 
    } 
} 
BENCHMARK(BM_SortInt)->Arg(SIZE); 

static void BM_StableSortInt(benchmark::State &state) { 
    std::random_device rd; 
    std::mt19937 mt(rd()); 
    std::uniform_int_distribution<int> dist; 

    while (state.KeepRunning()) { 
    std::vector<int> v; 
    v.reserve(state.range_x()); 
    for (int i = 0; i < state.range_x(); i++) { 
     v.push_back(dist(mt)); 
    } 

    std::stable_sort(v.begin(), v.end()); 
    } 
} 
BENCHMARK(BM_StableSortInt)->Arg(SIZE); 


struct S { 
    int key; 
    int arr[4]; 
}; 

static void BM_BaseStruct(benchmark::State &state) { 
    std::random_device rd; 
    std::mt19937 mt(rd()); 
    std::uniform_int_distribution<int> dist; 

    while (state.KeepRunning()) { 
    std::vector<S> v; 
    v.reserve(state.range_x()); 
    for (int i = 0; i < state.range_x(); i++) { 
     v.push_back({dist(mt)}); 
    } 
    } 
} 
BENCHMARK(BM_BaseStruct)->Arg(SIZE); 

static void BM_SortStruct(benchmark::State &state) { 
    std::random_device rd; 
    std::mt19937 mt(rd()); 
    std::uniform_int_distribution<int> dist; 

    while (state.KeepRunning()) { 
    std::vector<S> v; 
    v.reserve(state.range_x()); 
    for (int i = 0; i < state.range_x(); i++) { 
     v.push_back({dist(mt)}); 
    } 

    std::sort(v.begin(), v.end(), 
       [](const S &a, const S &b) { return a.key < b.key; }); 
    } 
} 
BENCHMARK(BM_SortStruct)->Arg(SIZE); 

static void BM_StableSortStruct(benchmark::State &state) { 
    std::random_device rd; 
    std::mt19937 mt(rd()); 
    std::uniform_int_distribution<int> dist; 

    while (state.KeepRunning()) { 
    std::vector<S> v; 
    v.reserve(state.range_x()); 
    for (int i = 0; i < state.range_x(); i++) { 
     v.push_back({dist(mt)}); 
    } 

    std::stable_sort(v.begin(), v.end(), 
        [](const S &a, const S &b) { return a.key < b.key; }); 
    } 
} 
BENCHMARK(BM_StableSortStruct)->Arg(SIZE); 


BENCHMARK_MAIN(); 
9

大到足以保證一個單獨的函數,它穩定的排序,而不是有std::sort()做到透明。

+0

HAHAH。好的,所以也許不是技術上最詳細的答案,但肯定是我最喜歡的。 – 2013-06-21 18:15:18

15

std::stable_sort當有足夠的內存可用時,執行NlogN比較。當內存不足時,它會降級到N((logN)^ 2)比較。因此,當存儲器可用時,其效率與std::sort(在平均值和最差情況下執行O(NlogN)比較)的效率大致相同。對於那些有興趣的人,sort()使用introsort(當遞歸達到特定深度時切換到堆排序的快排),而stable_sort()使用merge sort

+6

LogN^2通常並不意味着log(N^2),而是(log N)^ 2,尤其是如果它出現在大O符號中。這種情況通常發生在算法上,O(N log N)步與O(log N)步一起工作,反之亦然。 因此,不,這不是一個常數2. – MSalters 2009-05-01 13:35:54

+0

你是對的,因此,我的答案大大改變了。 – marcog 2009-05-01 14:58:51

+0

你說`std :: sort(在平均和最差的情況下執行O(NlogN)比較)``。但是,自從C++ 11以來,在所有情況下,std :: sort的鏈接都表示爲:O(N·log(N))。在C++ 11之前,在最壞的情況下不需要O(Nlog(N))。 – 2013-12-05 11:31:57

2

練習中的性能差距有多大?你有什麼經驗 呢?

是的,但它並沒有去你所期望的方式。

我採用了Burrows-Wheeler Transform和C++的C實現 - ified。結果比C代碼慢得多(儘管代碼更清晰)。所以我把計時器放在那裏,看起來qsort的執行速度比std :: sort快。這是在VC6中運行。然後用stable_sort重新編譯,測試運行速度比C版本快。其他優化設法將C++版本比C版本快25%。我認爲有可能提高速度,但代碼的清晰度正在消失。

+0

基本上我想說的是嘗試兩種方式。 – 2009-05-01 13:56:49

9

有時需要std :: stable_sort(),因爲它維護的元素的順序是相等的。

而傳統的建議是,如果維護順序不重要,則應該使用std :: sort()來代替。

但是,其上下文依賴。有大量數據的最好用穩定的排序進行排序,即使你並不需要維持秩序:

快速排序很快變得最壞情況下的性能,如果該數據一貫較差支點。

的​​是用作數據壓縮,例如的一部分的算法bzip2。它需要對文本的所有旋轉進行排序。對於大多數文本數據,合併排序(通常由std :: stable_sort()使用)比quicksort(通常由std :: sort()使用)快得多。

bbb是BWT實現,指出()性病的優勢:: stable_sort()在排序這種應用。

1

如果要排序大量的結構,你的內存的IO速度/盤開始變得比漸近運行時間更重要。此外,還應該考慮內存使用情況。

我試圖在數據(64B結構)的2Gb上的std :: stable_sort,不知道std :: stable_sort創建數據的內部副本。隨後的交換垃圾幾乎鎖定了我的電腦。

使用不穩定的std :: sort會將內存使用量減少2倍,這對排序大型數組非常有用。我終止了std :: stable_sort,所以我不能確定它是多慢。但是,如果不需要穩定的排序,那麼我認爲最好使用不穩定的std :: sort。

1

一直在尋找類似的東西 - 但很驚訝沒有人談論的輔助空間。

正如我相信 - stable_sort和排序的實施應該保證O(NlogN)的所有(最好,平均最差)案件。

但是,所使用的輔助空間存在差異。 stable_sort需要O(N)的輔助空間。

可能是性能上的差異在於獲取該空間。 :)
否則,理論上 - 他們應該是相同的w.r.t表現。

排序應該做你需要的,除非你需要這個 - > stable_sort保留元素與等價值的相對順序。

相關問題