C++ STL 排序源码详解(一)

来源:互联网 发布:多层嵌套 知乎 编辑:程序博客网 时间:2024/06/15 12:18
(全部以int类型的vector为处理对象)

     STL有关排序的几个函数如下所示,需要更少资源(时间和空间)的算法列在需要更多的前面,需要指出的是他们完成的工作是不一样的。

1. partition                  4. partial_sort
2. stable_partition      5. sort
3. nth_element           6. stable_sort

个人笔记:

        在快速排序中,切分函数是基本操作,那么在往后和往前移动的过程中存在边界判断的需要,由于排序中的这种边界判断,处在底层,如果能够取消,将极大提升效率,对此要有一定认识。特别注意,low<len-1 这样的边界判断有时是不需要的。之所以判断边界,是因为有可能容器中所有的元素都小于(或不小于)枢轴,也即都满足判断条件,会导致越界。这跟枢轴选取的方式有关系,如果可以断定枢轴会在待排序区出现,那么很大可能不会越界,这取决于等于枢轴是否满足调整条件。


一、partition

主要功能是将数据分成两部分,一部分满足条件,另一部分不满足条件。满足与否,是通过一个返回bool量的单参数函数实现的。

#include<iostream>#include<vector>using namespace std;void swap(int &a,int &b){int temp;temp = a;a = b;b = temp;}bool fun(int a)   //判别函数{int key = 5;return a < key;}int partition(vector<int> &vec,bool (*pred)(int))  //通过函数指针传入{int len = vec.size();if (len < 2) return 0;int low = 0;int hi = len - 1;while (true){while ((low<len-1)&&(*pred)(vec[low]))  //存在边界判断{low++;}while ((hi>0) && !((*pred)(vec[hi]))){hi--;}if (low >= hi) break;swap(vec[low],vec[hi]);}return low;}void myprint(const vector<int> a){for (int i = 0; i < a.size(); i++){cout << a[i] << " ";}cout << endl;}int main(){vector<int> data = {2,4,7,8,1};myprint(data);partition(data,fun);myprint(data);system("pause");return 0;}

二、nth_element

     void nth_element(vector<int> &vec, int num)   将最小(或最大)的num个数放在数组的开始处。注意num个数是无序的。

     主要是利用快速排序的切分操作,源码针对枢轴的选取了优化措施(取待处理区间首、中间、尾3个值中的中间值作为枢轴,防止切分操作退化),这里为了简化,没有对枢轴的选取进行优化。

      根据切分函数的返回值,判断是否达到了找出了num个满足要求的数,如果不满足,判断下一处理区间。

#include<iostream>#include<vector>using namespace std;void swap(int &a, int &b){int temp;temp = a;a = b;b = temp;}int partition(vector<int> &vec,int low,int hi){int mid = (hi - low) / 2 + low;int pivot = vec[low];int i = low + 1;int j = hi;while (true){while (i < hi && vec[i] < pivot) i++;while (j>low && vec[j]>pivot) j--;if (i >= j) break;swap(vec[i], vec[j]);i++;j--;}swap(vec[low],vec[j]);return j;}void nth_element(vector<int> &vec, int num){int len = vec.size();int low = 0;int hi = len - 1;while (low<hi){int j = partition(vec,low,hi);if (j == num - 1) return;else if (j < num - 1) low = j+1;else hi = j - 1;}}void myprint(const vector<int> a){for (int i = 0; i < a.size(); i++){cout << a[i] << " ";}cout << endl;}int main(){vector<int> data = { 11,5, 4, 7, 6, 8, 1,10 };myprint(data);nth_element(data,2);myprint(data);system("pause");return 0;}

三、partial_sort

void partial_sort(vector<int> &vec,int len)    将最小的前len个数放到数组最前面,并保持有序

局部排序的原理是,建立一个len大小的堆,初始时堆中数据就是数组的前len个数据,将剩余的数据逐个与堆顶的数据比较,如果小于堆顶数据,则交换,并调整堆,最后对堆进行排序。此方案可以实现nth_element函数,差别仅在于有没有最后一步排序。

#include<iostream>#include<vector>using namespace std;void swap(int &a, int &b){int temp;temp = a;a = b;b = temp;}void adjustHeap(vector<int> &vec,int len,int i){int max = i;int left = 2 * i + 1;int right = 2 * i + 2;if (left<len && vec[left]>vec[max]) max = left;if (right<len && vec[left]>vec[max]) max = right;if (max != i){swap(vec[i],vec[max]);adjustHeap(vec, len, max);}}void buildHeap(vector<int> &vec,int len){if (len < 2) return;for (int i = len / 2 - 1; i >= 0; i--){adjustHeap(vec, len, i);}}void sortHeap(vector<int> &vec,int len){for (int i = len - 1; i>0; i--){swap(vec[0],vec[i]);adjustHeap(vec,i,0);}}void partial_sort(vector<int> &vec,int len){buildHeap(vec,len);for (int i = len; i < vec.size(); i++){if (vec[0]>vec[i]) swap(vec[0], vec[i]);adjustHeap(vec,len,0);}sortHeap(vec,len);}void myprint(const vector<int> a){for (int i = 0; i < a.size(); i++){cout << a[i] << " ";}cout << endl;}int main(){vector<int> data = { 11,5, 4, 7, 6, 8, 1,10 };myprint(data);partial_sort(data, 4);myprint(data);system("pause");return 0;}


原创粉丝点击