Effective STL 学习笔记 31:排序算法
Table of Contents
1 partial_sort
partial sort 可以进行部分排序,例如,仅 按顺序排出 某个容器中的前 20 名:
bool qualityCompare(const Widget& lhs, const Widget& rhs); partial_sort(widgets.begin(), widgets.begin()+20, widgets.end(), qualityCompare);
2 nth_element
与 partial_sort 类似, nth_element 也用于部分排序,但它只保证指定的排名前 N 个元素会存放到容器的前N,但这前 N 个元素之间的顺序不一定。更重要的是,它可以保证,如果我们对容器进行完全排序,排在 N 位置的那个元素一定和 nth_element 排序后 N 位置的元素相同(等值):
nth_element(widgets.begin(), widgets.begin()+20, widgets.end(), qualityCompare);
此外, nth_element 可以方便地计算出指定容器中指定排名的元素:
vector<Widget>::size_type goalOffset = 0.21 * widgets.size(); nth_element(begin, begin+goalOffset, end, qualityCompare);
3 stability
对于任意的等价对象 A 与 B ,如果 A 在容器中的位置比 B 靠前,且排序后 A 的位置仍然在 B 之前,则称该排序算法为稳定的 (stable) 。 partial_sort 和 nth_element 都不是稳定的,但算法 stable_sort 可以保证这一点。
4 partition
partition 可以将对 Sequence Container 进行排序,排序完成后返回的迭代器指向满足条件的最后一个元素:
bool HasAcceptableQuality(const Widget& w); vector<Widget>::iterator goodEnd = partition(widgets.begin(), widgets.end(), HasAcceptableQuality);
当上述表达式完成之后,返回的 goodEnd 指向了满足 HasAcceptableQuality 的最后一个元素,算法不保证 goodEnd 之前的元素顺序,但 stable_partition 可以保证 stability.
5 总结
- 需要对 vector, string, dequeu, array 进行完全排序 \(\rightarrow sort/stable\_sort\)
- 需要从 vector, string, dequeu, array 中获取排好序的前 N 个元素:\(\rightarrow partial\_sort\)
- 需要从 vector, string, dequeu, array 中获取无序的前 N 名或者指定的第 N 名: \(\rightarrow nth\_element\)
- 需要从顺序容器中获取符合某种条件的所有元素: \(\rightarrow partition/stable\_partition\)
- 需要对 List 进行排序,最好使用 List 本身的相关函数,或者将 List 转换成 vector 再使用 STL 算法。
上述各种算法的效率:
\(partition > stable\_partition > nth_element > partial\_sort > sort > stable\_sort\)
#include <vector> #include <algorithm> #include <stdio.h> #include <string> #include <iostream> #include <fstream> #include <iterator> #include <stdlib.h> #include <sys/time.h> using namespace std; #define N 1000000 typedef unsigned int uint32; static inline uint32 current_time_ms() { struct timeval tv; return (gettimeofday(&tv, NULL) != -1) ? \ tv.tv_sec * 1000 + tv.tv_usec / 1000 : 0; } #define show(s,e) copy(s, e, os); cout << endl ; #define nth(v, N) *(v.begin()+N-1) bool PartitionCond(int& i) { return i < 50; } int main(int argc, char *argv[]) { srand(time(NULL)); vector<int> v(N); for (int i = 0; i < N; ++i) { v[i] = i; } random_shuffle(v.begin(), v.end()); ostream_iterator<int> os(cout, " "); cout << "Original array = " << endl; show(v.begin(),v.begin()+21); cout << "Partial_sort for 20 elements... " << endl; vector<int> v1(v); uint32 ts = current_time_ms(); partial_sort(v1.begin(), v1.begin()+21, v1.end(), less<int>()); cout << "time = " << current_time_ms() - ts << endl; show(v1.begin(),v1.begin()+21); cout << "nth_element of the 20th elements... " << endl; vector<int> v2(v); ts = current_time_ms(); nth_element(v2.begin(), v2.begin()+20, v2.end(),less<int>()); cout << "time = " << current_time_ms() - ts << endl; show(v2.begin(),v2.begin()+21); cout << "v1[19] = " << nth(v1, 21) << endl; cout << "v2[19] = " << nth(v2, 21) << endl; vector<int>v5(v); sort(v5.begin(), v5.end()); if (nth(v5, 21) == nth(v2, 21)) { cout << "nth_element works! " << endl; } else { cout << "nth_element is not working correctly! " << endl; } cout << "Testing partition... " << endl; vector<int> v3(v); ts = current_time_ms(); vector<int>::iterator i1 = partition(v3.begin(), v3.end(), PartitionCond); cout << "Time cost = " << current_time_ms() - ts << endl; show(v3.begin(), i1); cout << "Testing stable_partition... " << endl; vector<int> v4(v); ts = current_time_ms(); vector<int>::iterator i2 = stable_partition(v4.begin(), v4.end(), PartitionCond); cout << "Time cost = " << current_time_ms() - ts << endl; show(v4.begin(), i2); return 0; }
(转载请注明出处,使用许可:署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议 。)