排序算法
C++ STL 的排序算法(Sorting algorithms)是一组将无序序列排列成有序序列的模板函数或与排序相关的模板函数,提供了排序、折半搜索、归并、集合操作、堆操作、最值求解、字典比较和排列组合等功能。
排序算法一般要求容器提供随机访问迭代器,一般适用于序列容器,如向量容器、队列容器和字符串容器等,但不适用于内部数据结构较为复杂的关联容器,如集合容器、映照容器、哈希集合容器和哈希映照容器等(有些容器是 SGI C++ STL里面的,在编译器自带的STL里面没有,这里不深入讨论,有兴趣的可以自己查相关资料)。
目录:
集合求异 set_sysmmetric_difference
应用 push_heap 算法将新元素压入堆 /* 下面示例程序将已构成堆的向量容器 v={38, 29, 32, 17, 26, 15, 11, 9, 10},压入最后一个元素60,使之仍然是堆。打印输出为“60 38 32 17 29 15 11 9 10 26”。 */ ----------------------------------------------- 应用 push_heap 算法将新元素压入堆 #include <algorithm> #include <vector> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { vector<int> v; v.push_back(38); v.push_back(29); v.push_back(32); v.push_back(17); v.push_back(26); v.push_back(15); v.push_back(11); v.push_back(9); v.push_back(10); v.push_back(60); // 将最后的元素60 入堆 push_heap(v.begin(), v.end()); for_each(v.begin(), v.end(), print); cout << endl; return 0; }
应用 make_heap 算法在向量容器元素中建立堆 /* 下面示例程序,将向量容器 v={5, 6, 4, 8, 2, 3, 7, 1, 9}元素调整为一个堆. */ ----------------------------------------------- 应用 make_heap 算法在向量容器元素中建立堆 #include <algorithm> #include <vector> #include <iostream> using namespace std; // 小顶堆 bool comp(int x, int y) { return x > y ? 1 : 0; } void print(int x) { cout << x << " "; } int main() { vector<int> v; v.push_back(5); v.push_back(6); v.push_back(4); v.push_back(8); v.push_back(2); v.push_back(3); v.push_back(7); v.push_back(1); v.push_back(9); for_each(v.begin(), v.end(), print); cout << endl; cout << "创建堆" << endl; // make_heap默认是2个参数,默认是创建大顶堆 make_heap(v.begin(), v.end(), comp); for_each(v.begin(), v.end(), print); cout << endl; return 0; }
应用 pop_heap 算法进行堆元素的出堆操作 /* 下面示例程序先将数组 iArray构建成一个堆,然后进行一次元素出堆操作。 从程序中可以看到,元素出堆,并没有将元素删除,只是将其移动位置,便于进行堆排序 */ ----------------------------------------------- 应用 pop_heap 算法进行堆元素的出堆操作 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int iArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; const int len = sizeof(iArray) /sizeof(int); cout << "创建堆" << endl; make_heap(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl; cout << "执行一次元素出堆" << endl; pop_heap(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl; return 0; }
应用 sort_heap 算法对向量容器元素进行堆排序 /* 下面示例程序先对向量容器v={3, 9, 6, 3, 12, 17, 20} 构建堆,然后利用 sort_heap 算法进行排序。(默认是小顶堆排序方式) */ ----------------------------------------------- 应用 sort_heap 算法对向量容器元素进行堆排序 #include <algorithm> #include <vector> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { vector<int> v; v.push_back(3); v.push_back(9); v.push_back(6); v.push_back(3); v.push_back(12); v.push_back(17); v.push_back(20); for_each(v.begin(), v.end(), print); cout << endl; // 创建堆 make_heap(v.begin(), v.end()); // 堆排序 cout << "进行堆排序" << endl; sort_heap(v.begin(), v.end()); for_each(v.begin(), v.end(), print); cout << endl; return 0; }
应用 partial_sort 算法对数组元素进行局部排序 /* 下面示例程序将数组iArray进行局部排序,middle=5时,给出前5个元素的排序;middle=8时,给出前8个元素的排序。 */ ----------------------------------------------- 应用 partial_sort 算法对数组元素进行局部排序 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int iArray[] = {3, 9, 6, 8, -10, 7, -11, 19, 30, 12, 23}; const int len = sizeof(iArray) / sizeof(int); for_each(iArray, iArray+len, print); cout << endl; // 前5个元素的局部排序 int middle = 5; partial_sort(iArray, iArray+middle, iArray+len); cout << "middle=" << middle << endl; for_each(iArray, iArray+len, print); cout << endl << endl; // 前8个元素的局部排序 middle = 8; partial_sort(iArray, iArray+middle, iArray+len); cout << "middle=" << middle << endl; for_each(iArray, iArray+len, print); cout << endl << endl; return 0; }
应用 partial_sort_copy 算法将数组拷贝到向量容器 /* 下面示例程序分别将数组iArray局部排序复制6个元素到向量容器v1。将整个数组局部排序复制到向量容器v2。 */ ----------------------------------------------- 应用 partial_sort_copy 算法将数组拷贝到向量容器 #include <algorithm> #include <vector> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int iArray[] = {3, 9, 6, 2, 11, 23, 80, 27, 1, 62, 55}; const int len = sizeof(iArray) / sizeof(int); // 仅拷贝6个元素到v1 vector<int> v1(6); partial_sort_copy(iArray, iArray+len, v1.begin(), v1.end()); for_each(v1.begin(), v1.end(), print); cout << endl << endl; // 全部拷贝到 v2 vector<int> v2(len); partial_sort_copy(iArray, iArray+len, v2.begin(), v2.end()); for_each(v2.begin(), v2.end(), print); cout << endl; return 0; }
应用 sort 算法将数组排序 /* 下面示例程序将数组iArray元素进行 sort 排序,元素默认由小到大排列过来,然后用 greater 函数对象(也可以自己重新定义)作为 sort 的谓词判断,将元素有大到小排列出来。 */ ----------------------------------------------- 应用 sort 算法将数组排序 #include <algorithm> #include <iostream> using namespace std; bool greater(int x, int y) { return x > y; } void print(int x) { cout << x << " "; } int main() { int iArray[] = {2, 8, -15, 90, 26, 7, 23, 30, -27, 39, 55}; const int len = sizeof(iArray) / sizeof(int); cout << "由小到大排序" << endl; sort(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl; cout << "由大到小排序" << endl; sort(iArray, iArray+len, greater); for_each(iArray, iArray+len, print); cout << endl; return 0; }
应用 merge 算法二路归并两个有序数组 /* 下面示例程序分别对升序和降序的两个数组元素进行归并 */ ----------------------------------------------- 应用 merge 算法二路归并两个有序数组 #include <algorithm> #include <iostream> using namespace std; bool greater(int x, int y) { return x > y; } void print(int x) { cout << x << " "; } int main() { int iArray1[3] = {20, 23, 38}; int iArray2[6] = {2, 9, 13, 18, 26, 30}; // 升序归并 int result[9]; merge(iArray1, iArray1+3, iArray2, iArray2+6, result); for_each(result, result+9, print); cout << endl << endl; // 降序归并 int iArray3[5] = {30, 20, 17, 8, 6}; int iArray4[4] = {10, 5, 2, 0}; merge(iArray3, iArray3+5, iArray4, iArray4+4, result, greater); for_each(result, result+9, print); cout << endl; return 0; }
应用 inplace_merge 算法内部归并数组元素 /* 下面示例程序对升序的数组iArray1 和 降序的数组 iArray2 分别进行内部归并。 */ ----------------------------------------------- 应用 inplace_merge 算法内部归并数组元素 #include <algorithm> #include <iostream> using namespace std; bool greater(int x, int y) { return x > y; } void print(int x) { cout << x << " "; } int main() { int iArray1[] = {2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11, 13}; const int len1 = sizeof(iArray1) / sizeof(int); // 从第 5 个元素开始,可以将iArray看作是 2 个单独的有序序列。 // 升序内部归并 inplace_merge(iArray1, iArray1+5, iArray1+len1); for_each(iArray1, iArray1+len1, print); cout << endl << endl; // 降序内部归并 int iArray2[] = {100, 80, 60, 40, 20, 10, 90, 70, 50, 30}; const int len2 = sizeof(iArray2) / sizeof(int); inplace_merge(iArray2, iArray2+6, iArray2+len2, greater); for_each(iArray2, iArray2+len2, print); cout << endl; return 0; }
应用 stable_sort 算法对向量容器元素进行稳定排序 /* 下面示例程序将学生记录放入向量容器,按学号进行 sort 算法排序,同分数的“李强”排在“丁宏”前面。然后,按分数进行 stable_sort 算法排序,“李强”依然在“丁宏”的前面,相对顺序维持不变。 */ ----------------------------------------------- 应用 stable_sort 算法对向量容器元素进行稳定排序 #include <algorithm> #include <vector> #include <iostream> using namespace std; // 学生结构体 struct Student { int id; char* name; int score; Student(int id_, char* name_, int score_) { id = id_; name = name_; score = score_; } }; // 按学号比较 bool compByid(Student s1, Student s2) { return s1.id < s2.id ? 1 : 0 ; } // 按分数比较 bool compByscore(Student s1, Student s2) { return s1.score < s2.score ? 1 : 0; } void print(Student s) { cout << s.id << " " << s.name << " " << s.score << endl; } int main() { vector<Student> v; v.push_back(Student(5, "李强", 90)); v.push_back(Student(9, "王文", 80)); v.push_back(Student(8, "张天", 87)); v.push_back(Student(6, "丁宏", 90)); v.push_back(Student(7, "赵庆", 99)); cout << "按学号执行 sort 算法排序:" << endl; sort(v.begin(), v.end(), compByid); for_each(v.begin(), v.end(), print); cout << endl; cout << "按分数执行 stable_sort 算法排序:" << endl; stable_sort(v.begin(), v.end(), compByscore); for_each(v.begin(), v.end(), print); cout << endl; return 0; }
应用 nth_element 算法排列数组元素 /* 下面示例程序将数组iArray,进行重新排序,使第9个元素(从0开始计起)满足 nth_element算法要求。重排后的打印输出为“7, 8, 6, 2, 9, 5, 1, 3, 0, 10, 11, 13, 12”,可见重新排列后的第9个元素的值为10,它大于前面的元素,而又不大于后面的元素。 */ ----------------------------------------------- 应用 nth_element 算法排列数组元素 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int iArray[] = {7, 8, 6, 2, 9, 5, 10, 3, 0, 1, 13, 11, 12}; const int len = sizeof(iArray) / sizeof(int); cout << "打印 iArray 数组元素" << endl; for_each(iArray, iArray+len, print); cout << endl; // 执行 nth_element 算法 cout << "*nth设为第9个元素,打印iArray数组元素" << endl; nth_element(iArray, iArray+9, iArray+len); for_each(iArray, iArray+len, print); cout << endl; return 0; }
用 lower_bound 算法找出不小于某值的有序数组下确界元素 /* 下面示例程序找出数组iArray中首个不小于16的元素 */ ----------------------------------------------- 应用 lower_bound 算法找出不小于某值的有序数组下确界元素 #include <algorithm> #include <iostream> using namespace std; int main() { int iArray[] = {3, 6, 9, 13, 18, 20, 27}; const int len = sizeof(iArray) / sizeof(int); int *result = lower_bound(iArray, iArray + len, 16); cout << "数组iArray中不小于16的下确界元素为:" << *result << endl; return 0; }
用 upper_bound 算法,找出大于某值的有序数组上确界元素 /* 下面示例程序找出数组iArray中首个大于13的元素 */ ----------------------------------------------- 应用 upper_bound 算法,找出大于某值的有序数组上确界元素 #include <algorithm> #include <iostream> using namespace std; int main() { int iArray[] = {3, 6, 9, 13, 18, 20, 27}; const int len = sizeof(iArray) / sizeof(int); int *result = upper_bound(iArray, iArray+len, 13); cout << "数组iArray 中大于13的上确界元素为:" << *result << endl; return 0; }
应用 equal_range 算法找出可插入某值的区间元素 /* 下面示例程序查找数组iArray中,可以在前面插入10的区间元素。 */ ----------------------------------------------- 应用 equal_range 算法找出可插入某值的区间元素 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int iArray[] = {3, 6, 9, 10, 10, 10, 13, 16, 17, 20}; const int len = sizeof(iArray) / sizeof(int); pair<int*, int*> range = equal_range(iArray, iArray+len, 10); cout << "第一个可以插入10的元素为:" << *range.first << endl; cout << "最后一个可以插入10的元素为:" << *range.second << endl; cout << "所有可以在前面插入10的元素为:"; for_each(range.first, range.second+1, print); cout << endl; return 0; }
应用 binary_search 算法在有序区间中搜索元素 /* 下面示例程序在已排序的数组 iArray 中,搜索出整数13 */ ----------------------------------------------- 应用 binary_search 算法在有序区间中搜索元素 #include <algorithm> #include <iostream> using namespace std; int main() { int iArray[] = {2, 3, 9, 12, 13, 20, 23, 26}; const int len = sizeof(iArray) / sizeof(int); if (binary_search(iArray, iArray+len, 13)) cout << "数组iArray包含元素13 " << endl; else cout << "数组iArray不包含元素13 " << endl; return 0; }
应用 includes 算法判断集合包含关系 /* 下面示例程序检查出数组 A={1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 构成的集合,包含数组 B={2, 4, 6, 8, 10} 的集合。 */ ----------------------------------------------- 应用 includes 算法判断集合包含关系 #include <algorithm> #include <iostream> using namespace std; int main() { int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; const int lenA = sizeof(A) / sizeof(int); int B[] = {2, 4, 6, 8, 10}; const int lenB = sizeof(B) / sizeof(int); if (includes(A, A+lenA, B, B+lenB)) cout << "B 是A 的子集合" << endl; else cout << "B 不是A 的子集合" << endl; return 0; }
应用 set_union 算法进行集合求并 /* 下面示例程序将集合A 和集合 B 进行求并操作,并集为 C. 可见C 的元素是稳定排序的,而且重复的元素3只出现两次。 */ ----------------------------------------------- 应用 set_union 算法进行集合求并 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int A[6] = {3, 3, 6, 9, 10, 12}; int B[3] = {3, 8, 11}; int C[8] = {0}; set_union(A, A+6, B, B+3, C); for_each(C, C+8, print); cout << endl; return 0; }
应用 set_intersection 算法进行集合求交 /* 下面示例程序对集合 A 和 B 进行求交。 */ ----------------------------------------------- 应用 set_intersection 算法进行集合求交 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int A[10] = {3, 6, 6, 9, 13, 17, 18, 20, 23, 25}; int B[7] = {-2, -1, 6, 9, 18, 30, 32}; int C[3] = {0}; // 求交集 set_intersection(A, A+10, B, B+7, C); for_each(C, C+3, print); cout << endl; return 0; }
应用 set_difference 算法进行集合求差 /* 下面示例程序对集合 A 、B 进行集合求差。 */ ----------------------------------------------- 应用 set_difference 算法进行集合求差 #include <algorithm> #include <vector> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int A[12] = {1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10}; int B[6] = {2, 3, 4, 6, 8, 10}; int C[6] = {0}; // 求差集 set_difference(A, A+12, B, B+6, C); for_each(C, C+6, print); cout << endl; return 0; }
应用 set_symmetric_difference 算法进行集合求异 /* 下面示例程序对集合A、B进行求异。 */ ----------------------------------------------- 应用 set_symmetric_difference 算法进行集合求异 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } int main() { int A[9] = {3, 6, 6, 9, 12, 13, 15, 18, 20}; int B[5] = {2, 6, 15, 20, 30}; int C[8] = {0}; // 集合求异 set_symmetric_difference(A, A+9, B, B+5, C); for_each(C, C+8, print); cout << endl; return 0; }
应用 min_element 算法求双向链表的最小元素 /* 下面示例程序求出双向链表{13, 6, 9, 3, 20}的最小元素3 */ ----------------------------------------------- 应用 min_element 算法求双向链表的最小元素 #include <algorithm> #include <list> #include <iostream> using namespace std; int main() { list<int> l; l.push_back(13); l.push_back(6); l.push_back(9); l.push_back(3); l.push_back(20); cout << "链表l的最小元素为:" << *min_element(l.begin(), l.end()) << endl; return 0; }
应用 max_element 算法求向量容器的最大元素 /* 下面示例程序求出向量容器 v={30, 25, 32, 23, 38, 21} 的最大元素为38 */ ----------------------------------------------- 应用 max_element 算法求向量容器的最大元素 #include <algorithm> #include <vector> #include <iostream> using namespace std; int main() { vector<int> v; v.push_back(30); v.push_back(25); v.push_back(32); v.push_back(23); v.push_back(38); v.push_back(21); cout << "向量容器 V 的最大元素为:" << *max_element(v.begin(), v.end()) << endl; return 0; }
应用 lexicographical_compare 算法比较字符串字典大小 /* 下面示例程序比较单词“book” 和 "house" 的字典顺序大小。 */ ----------------------------------------------- 应用 lexicographical_compare 算法比较字符串字典大小 #include <algorithm> #include <iostream> using namespace std; int main() { char *s1 = "book"; const int len1 = sizeof("book") / sizeof(char); char* s2 = "house"; const int len2 = sizeof("house") / sizeof(char); bool result = lexicographical_compare(s1, s1+len1, s2, s2+len2); if (result) cout << "单词"book"在"house"前面" << endl; else cout << "单词"book"在"house"后面" << endl; return 0; }
next_permutation 算法重新组合排序数组元素 /* 下面示例程序利用 next_permutation 算法,找出数组iArray 的下一较大组合排列,并进行由小到大的排序。 */ ----------------------------------------------- next_permutation 算法重新组合排序数组元素 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } // 排序函数 template<class BidirectionalIter> void nextPermu_sort(BidirectionalIter first, BidirectionalIter last) { while(next_permutation(first, last)) {} // 利用较大的组合返回 true } int main() { int iArray[] = {3, 6, 2, 9, 8}; const int len = sizeof(iArray) / sizeof(int); cout << "原组合" << endl; for_each(iArray, iArray+len, print); cout << endl << endl; // 新组合 cout << "新组合" << endl; next_permutation(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl << endl; // cout << "利用较慢的 next_permutation算法排序" << endl; nextPermu_sort(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl; return 0; }
应用 prev_permutation 算法重新组合排序数组元素 /* 下面示例程序利用 prev_permutation 算法,找出数组 iArray={1, 3, 9, 6, 7}的上一较小组合排列{1, 3, 7, 9, 6},并进行由小到大的排序。 */ ----------------------------------------------- 应用 prev_permutation 算法重新组合排序数组元素 #include <algorithm> #include <iostream> using namespace std; void print(int x) { cout << x << " "; } template <class BidirectionalIter> void prevPermu_sort(BidirectionalIter first, BidirectionalIter last) { while (prev_permutation(first, last)) {}; // 利用较小的组合返回 true } int main() { int iArray[] = {1, 3, 9, 6, 7}; const int len = sizeof(iArray) / sizeof(int); cout << "原组合" << endl; for_each(iArray, iArray+len, print); cout << endl << endl; cout << "新组合" << endl; prev_permutation(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl << endl; cout << "利用较慢的 prev_permutation算法排序" << endl; prevPermu_sort(iArray, iArray+len); for_each(iArray, iArray+len, print); cout << endl; return 0; }