1. 程式人生 > >STL partial_sort排序演算法

STL partial_sort排序演算法

通過示例很容易理解什麼是部分排序。假設有一個容器,它儲存了 100 萬個數值,但我們只對其中最小的 100 個感興趣。可以對容器的全部內容排序,然後選擇前 100 個元素,但這可能有點消耗時間。這時候需要使用部分排序,只需要這些數中的前100個是有序放置的。

對於部分排序,有一個特殊的演算法 partial_sort(),它需要 3 個隨機訪問迭代器作為引數。如果這個函式的引數是 first、second 和 last,那麼這個演算法會被應用到 [first,last) 這個範圍內的元素上。執行這個演算法後,[first,second) 會包含降序序列 [first,last) 中最小的 second-first 個元素。

注意,在這個示例中,有一種之前沒遇到過的表示方式 [first,last),用它來表示一個元素段,這是一個來自於數學領域的用來定義數字範圍的概念——區間。這兩個值叫作結束點,在這種表示法中,方括號表示包含相鄰的結束點,圓括號表示相鄰的結束點不包括在內。 例如,如果 (2,5) 是一個整數區間,2 和 5 都被排除在外,所以它只表示整數 3 和 4;這也被叫作開區間,因為兩個結束點都不包含。區間 [2,5) 包含 2 但不包含 5,所以它表示 2、3 和 4。(2,5] 表示 3、4 和 5。[2,5] 表示 2、3、4、5,並且它被叫作閉區間,因為包含了兩個結 束點。當然,first 和 last 都是迭代器,並且 [first,last) 表示包含 first 指向的元素而不包含 last 指向的元素,所以可以用它準確表示 

C++ 中的範圍。

下面這段程式碼演示了 partial_sort() 演算法的工作方式:

size_t count {5}; // Number of elements to be sorted
std::vector<int> numbers {22, 7, 93, 45, 19, 56, 88, 12, 8, 7, 15, 10};
std::partial_sort(std::begin(numbers), std::begin(numbers) + count, std::end(numbers));

執行partial__sort()後的效果如圖 1 所示。

最小的 count 個元素是有序的。在 [first,second) 範圍內,second 指向的元素沒有被包含在內,因為 second 是一個開結束點。圖 1 展示的是在本人系統上這段程式碼執行後的結果。在你的系統上結果可能會不同。需要注意的是,不能保持未排序元素的原始順序。在執行 partial_sort() 後這些元素的順序是不確定的,這取決於我們的實現。

如果想讓 partial_sort() 演算法使用和 < 運算子不同的比較函式,可以提供一個函式物件作為它的額外引數。例如:

std::partial_sort(std::begin(numbers), std::begin(numbers) + count, std:: end (numbers) , std::greater<>());

現在,number 中最大的 count 個元素會是容器開始處的一個降序序列。在此係統上這條語句的輸出結果為:

93 88 56 45 22 7 19 12 8 7 15 10

同樣,沒有保持 numbers 中未排序元素的原始順序。

partial_sort_copy() 在本質上和 partial_sort() 是相同的,除了前者會將排序元素複製到一個不同的元素段(另一個容器中)。它的前兩個引數是指定部分排序應用範圍的迭代器; 第 3 個和第 4 個引數是標識結果存放位置的迭代器。目的位置的元素個數決定了輸入元素段中被排序元素的個數。例如:

std::vector<int> numbers {22, 7, 93, 45, 19, 56, 88, 12, 8, 7, 15, 10};
size_t count {5}; // Number of elements to be sorted
std::vector<int> result(count); // Destination for the results 一 count elements
std::partial_sort_copy(std::begin(numbers), std::end(numbers), std::begin (result) , std::end (result)); std::copy(std::begin(numbers), std::end(numbers), std::ostream_iterator<int>{std::cout," " });
std::cout << std::endl;
std::copy(std::begin(result), std::end(result),std::ostream_iterator <int> {std::cout, " "}); std::cout << std::endl

這些語句實現了對 numbers 容器的部分排序。這個想法是先對 numbers 中最小的 count 個元素排序,然後把它們儲存在結果容器中。我們指定的用於存放元素的目的位置必須存在,也就是說,目的容器 result 必須至少有 count 個元素,在這個示例中我們需要分配準確數目的記憶體。執行這段程式碼後的輸出如下:

22 7 93 45 19 56 88 12 8 7 15 10
7 7 8 10 12

可以看到,numbers 中元素的順序並沒有被打亂,result 中包含了 number 中按升序排列的最小的 count 個元素。

當然,也可以用額外的引數來指定不同的比較函式:

指定一個 greater<> 的例項作為函式物件,將最大的 count 個元素以降序的形式複製到 result 中。如果這條語句後跟的是前一個程式碼段中的輸出語句,會輸出如下內容:

std::partial_sort_copy(std::begin(numbers), std::end(numbers), std::begin(result), std::end(result),std::greatero());

同前面一樣,原始容器中元素的順序沒有被打亂。