快速排序
来源:互联网 发布:淘宝更改发货地址 编辑:程序博客网 时间:2024/06/05 19:34
一、快排的几种实现方法:
1.左右指针法:
a.算法思想:选定数组中最后一个数为关键值,从左往右遍历当遇到比关键值大的数就停下,
从右往左遍历遇到比关键值小的数就停下,交换两个数,直到当左右相遇,将关键值与指针所在
的位置互换,一轮过后关键值前面的数都比它小,关键值后的数都比它大。此时key将这段区间
划分成两半,然后依次对这两半区间排序,直到每个区间就剩一个数,那么就排好序了。
b.时间复杂度:快排每次都会划分区间,直到区间有一个数,这点类似于二叉树,单趟排序交换数的
过程大概走了n步,递归了lg n层,所以时间复杂度为o(n*lg n);
c.空间复杂度:递归了高度次所以空间复杂度为o(lg n);
d.代码实现:
int PartSort(int *a, int left, int right){ int key = right; //最后一个下标为基准值 while (left < right) { while (left < right&&a[left] <= a[key]) { ++left; } while (left < right&&a[right] >= a[key]) { --right; } if (left<right) swap(a[left], a[right]); } swap(a[left], a[key]); return left;}void QuickSortR(int *a, int left,int right){ int mid; if(left < right) { mid = PartSort(a, left, right); QuickSortR(a, left, mid - 1); QuickSortR(a, mid + 1, right); }}void PrintArray(int *a, size_t N){ for (size_t i = 0; i < N; i++) { cout << a[i] << " "; } cout << endl;}void TestQuickSort(){ int a[] = { 2, 0, 4, 9, 3, 6, 8, 7, 1, 5 }; size_t length = sizeof(a) / sizeof(a[0]); QuickSortR(a, 0, (length - 1)); PrintArray(a, length);}
2.挖坑法:
a.算法思想:挖坑法和左右指针法原理类似,也是每次选取最后一个数为基准值,把这个数拿出来存放在
tmp中,然后这个位置就相当于一个坑,然后从前到后遍历,如果大于tmp就把这个数填到坑中,然后
这个位置就变成了新的坑,再从后往前遍历如果比tmp小,就把这个数填在刚才的坑中,直到left=right,
把最后的数填在left中。
b.时间复杂度:o(n*lg n);
c.空间复杂度:o(lg n);
e.代码实现:
//挖坑法int PartSort(int* a, int left, int right){ int tmp = a[right]; //记录最后一个位置 while (left < right) { while (left < right&&a[left] <= tmp) { ++left; } a[right] = a[left]; while (left < right&&a[right] >= tmp) { --right; } a[left] = a[right]; } a[left] = tmp; return left;}void QuickSortR(int *a, int left,int right){ int mid; if(left < right) { mid = PartSort(a, left, right); QuickSortR(a, left, mid - 1); QuickSortR(a, mid + 1, right); }}void PrintArray(int *a, size_t N){ for (size_t i = 0; i < N; i++) { cout << a[i] << " "; } cout << endl;}void TestQuickSort(){ int a[] = { 2, 0, 4, 9, 3, 6, 8, 5, 7, 1, 5 }; size_t length = sizeof(a) / sizeof(a[0]); QuickSortR(a, 0, (length - 1)); PrintArray(a, length);}
3.前后指针法:
a.算法思想:选取最后一个值为基准值key,定义两个指针一个是cur指向开始位置,prev指向cur的前一个
位置,遍历数组,如果a[cur]<=key,那么++prev,不交换cur和prev的值,++cur,如果a[cur]>key,那么
++cur,直到a[cur]<=key,++prev此时prev!=cur,交换cur和prev指向的值,直到cur==right,然后
++prev,交换cur和prev指向的值,此时一轮排序结束。
代码实现:
//前后指针法int PartSort(int* a, int left, int right){ int cur = left; int prev = cur - 1; while (cur < right) { if (a[cur] <= a[right]) { ++prev; if (a[prev] != a[cur]) swap(a[prev], a[cur]); } ++cur; } ++prev; swap(a[prev], a[cur]); return prev;}void QuickSortR(int *a, int left,int right){ int mid; if(left < right) { mid = PartSort(a, left, right); QuickSortR(a, left, mid - 1); QuickSortR(a, mid + 1, right); }}void PrintArray(int *a, size_t N){ for (size_t i = 0; i < N; i++) { cout << a[i] << " "; } cout << endl;}void TestQuickSort(){ int a[] = { 2, 0, 4, 9, 3, 6, 8, 7, 5, 1, 5 }; size_t length = sizeof(a) / sizeof(a[0]); QuickSortR(a, 0, (length - 1)); PrintArray(a, length);}
快排优化算法:
1.三数取中法
算法思想:当我们每次取得基准值都是最大的或最小的,那么快排就会变得很慢,类似于冒泡排序,
时间复杂度为o(n^2),所以我们每次期待选到比较居中的数,采取三数取中法,在第一个数
还有最后一个数以及中间的那个数,挑选中间的数。
int GetBestKey(int *a, int left, int right) //三数取中法{ int mid = left + (right - left) >> 1; if (a[left] < a[right]) { if (a[mid]>a[right]) return right; else if (a[mid] < a[left]) return left; else return mid; } else //left>right { if (a[mid] > a[left]) return left; else if (a[mid] < a[right]) return right; else return mid; }}
2.小区间优化法:
算法思想:当我们对海量数据进行排序时,递归是值得的,如果区间被划分为很小的时候,不用递归
直接采用直接插入排序,因为区间很小,由快排的特性可知,小区间已经快接近有序,当接近有序采用
直接插入排序的时间复杂度为o(n);节省了快排压栈的开销(对快排的几种方法都适用)。
完整代码:
int GetBestKey(int *a, int left, int right) //三数取中法{ int mid = left + (right - left) >> 1; if (a[left] < a[right]) { if (a[mid]>a[right]) return right; else if (a[mid] < a[left]) return left; else return mid; } else //left>right { if (a[mid] > a[left]) return left; else if (a[mid] < a[right]) return right; else return mid; }}void InsertSort(int* a, size_t N){ for (size_t i = 0; i < N - 1; i++) { int end = i; int tmp = a[end + 1]; for (; end >= 0; --end) { if (a[end]>tmp) { a[end + 1] = a[end]; } else { break; } } a[end + 1] = tmp; }}//左右指针法int PartSort(int *a, int left, int right){ int mid = GetBestKey(a, left, right); swap(a[mid], a[right]); int key = right; //最后一个下标为基准值 while (left < right) { while (left < right&&a[left] <= a[key]) { ++left; } while (left < right&&a[right] >= a[key]) { --right; } if (left<right) swap(a[left], a[right]); } swap(a[left], a[key]); return left;}void QuickSortR(int *a, int left, int right){ int mid; if (left < right) { if ((right - left) < 5) { InsertSort(a + left, right - left + 1); } mid = PartSort(a, left, right); QuickSortR(a, left, mid - 1); QuickSortR(a, mid + 1, right); }}void PrintArray(int *a, size_t N){ for (size_t i = 0; i < N; i++) { cout << a[i] << " "; } cout << endl;}void TestQuickSort(){ int a[] = { 2, 0, 4, 9, 3, 6, 8, 7, 1, 5 }; size_t length = sizeof(a) / sizeof(a[0]); QuickSortR(a, 0, (length - 1)); PrintArray(a, length);}
在对海量数据进行排序时,有可能递归栈溢出,我们可以采用非递归的方式,借用栈。
void QuickSortNR(int *a, int begin, int end){ assert(a); stack<int> s; if (begin < end) { s.push(end); s.push(begin); while (!s.empty()) { int left = s.top(); s.pop(); int right = s.top(); s.pop(); int mid = PartSort(a, left, right); if (left < mid - 1) { s.push(mid - 1); s.push(left); } if (mid + 1 < right) { s.push(right); s.push(mid + 1); } } }}
- 快速排序
- 快速排序
- 快速排序
- 快速排序!
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- (转)查理·芒格:光靠已有的知识,你走不了多远
- 关于Mybatis整合SpringMVC:报Java.lang.AbstractMethodError
- Spring+Quartz && Java.util.Timer 实现定时任务
- session详解
- JAVA多线程真的提高了效率吗?
- 快速排序
- 编写mysleep
- VS2012配置CATIA R2016 CAA RADE
- 集合1 collection
- Monkey Script
- 问题:求一个数的二进制中1的个数。
- 欢迎使用CSDN-markdown编辑器
- JS的常见的错误类型讲解
- Elasticsearch分片/脑裂/优化