快速排序--全集
来源:互联网 发布:mac os x office 编辑:程序博客网 时间:2024/05/17 22:04
快速排序:一听名字就知道这种排序很快的,是吧?没错,它是一种效率比较高的排序算法。
快速排序采用的是分治的思想。
比如,将一串数中的一个元素作为基准,然后将比它小的数排在它的左边,比它大的数排在它的右边。将作为基准的那个元素排在正确的位置。然后通过递归,依次将所有的元素都排好。(实质就是递归子问题)
在这里,快速排序也有几种不同的方式,下面我给大家一一叙述吧。
快速排序的几种方法:
1.左右指针法(交换):
有一个数组a[size],左指针left指向下标为0的位置,右指针right指向下标为size-1的位置,同时标志key=a[right];left找a[left]>key的元素的下标,right找a[right] < key的元素的下标。left先开始走,当遇到比key大的数时,停下来,再由right开始走,当遇到比key小的数时,停下来。将left和right分别指的数交换,前提是left<right时,如果left>=right就说明一次快排结束。再将left指向的值与key值交换即可。此时的数组呈现出左边的值都比key值小,右边的值都比key值大。一次快排将数组分为两个区间,我们再对每个区间进行上述的排序方式。直到每个小区间已不能再划分。(即一个区间只有两个元素)
代码实现:
int PartSort(int* a,int left,int right){int& key = a[right];//int key = right;while(left < right) {while(left < right && a[left] <= key) //a[left] <= a[key]++left;while(left < right && a[right] >= key) //a[right] >= a[key]--right;swap(a[left],a[right]);}swap(a[left],key);//swap(a[left],a[key]);return left;}void QuickSort(int* a,int left,int right){if(left < right){int div = PartSort(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}}void Display(int *a,size_t size){for(size_t i = 0; i < size; ++i){cout<<a[i]<<" ";}cout<<endl;}
2.挖坑法
有一个数组a[size],左指针left指向下标为0的位置,右指针right指向下标为size-1的位置,同时标志key=a[right];首先将key的位置设为一个坑,从left开始,找比key值大的,找到后将a[left]放到坑里,即a[right]=a[left],同时将left的位置再设为坑;再从right开始找比key小的,找到后将a[right]放到上次设的坑里,即a[left]= a[right];直到left>=right,将key值放到现在的坑中即可。此时的数组呈现出左边的值都比key值小,右边的值都比key值大。一次快排将数组分为两个区间,我们再对每个区间进行上述的排序方式。直到每个小区间已不能再划分。(即一个区间只有两个元素)
代码实现:
int PartSort1(int* a,int left,int right){int key = a[right];while(left < right) {while(left < right && a[left] <= key) ++left;a[right] = a[left];while(left < right && a[right] >= key) --right;a[left] = a[right];}a[left] = key;return left;}void QuickSort(int* a,int left,int right){if(left < right){int div = PartSort1(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}}
3.前后指针法
有一个数组a[size],指针cur指向0的位置,prev指向cur-1的位置,key为a[size-1];当cur对应的值大于key值时,cur++,然后将++prev对应的值与cur对应的值交换。继续比它大的值就跳过,找到a[cur]<key的值时,交换a[cur]和a[++prev]的值。直到cur指向最后一个元素,此时将a[++prev]和最后一个元素交换。此时的数组呈现出左边的值都比key值小,右边的值都比key值大。一次快排将数组分为两个区间,我们再对每个区间进行上述的排序方式。直到每个小区间已不能再划分。(即一个区间只有两个元素)
代码实现:
int PartSort2(int* a,int left,int right){int key = a[right];int cur = left;int prev = cur-1;while(cur < right){if(a[cur] < key && ++prev != cur)swap(a[cur],a[prev]);++cur;}swap(a[++prev],a[cur]);return prev;}void QuickSort(int* a,int left,int right){if(left < right){int div = PartSort2(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}}
以上就是快速排序的几种方法。
当然,分析过时间复杂度和空间复杂度之后,在某些特定的情况下,快速排序依然不是很快。下面就给大家介绍几种快速排序优化后的算法。
1.三数取中法
在快排算法中,如果数组本来就有序,key值就不会是中间的数字,那么快排每次遍历N次,时间复杂度就为O(N*N)为了避免快排遇到最坏的情况,我们采用三数取中法的方式,取到中间值的数与最后一个数交换,再进行快排方式。 这样可以使数组的key值都在较中间的位置,趋向于二叉树结构。时间复杂度也将提升到N*lgN。
代码实现:
//三数取中法int MidNum(int* a,int left,int right){int mid = left+((right-left)>>1);if(a[mid] < a[right]){if(a[mid] < a[right])return mid;else if(a[left] < a[right])return right;elsereturn left;}else{if(a[left] < a[right])return left;else if(a[mid] < a[right])return right;elsereturn mid;}}int PartSortMid(int* a,int left,int right){int MidKey = MidNum(a,left,right);swap(a[MidKey],a[right]);int key = right;while(left < right){while(left < right && a[left] <= a[key]) //左边如果比key位置的数小,则跳过++left;while(left < right && a[right] >= a[key]) //右边如果比key位置的数大,则跳过--right;swap(a[left],a[right]);}swap(a[left],a[key]);return left;}void QuickSort(int* a,int left,int right){if(left < right){int div = PartSortMid(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}}
2.小区间优化
对于上述三数取中法的快排算法,每次都是将一小段区间进行快排算法,即使区间很小也重复快排算法。我们前面学过 插入算法,当数组接近有序时,时间复杂度就为O(N),那么在快排算法中,我们可以对小区间进行优化,区间很小时,我们可以将数组视为接近有序,此时用插入排序来代替快排,比如当right-left<一个小区间的值时(自己规定,一般为13或20较好),这样就大大提高了快排的效率。
代码实现:
//小区间优化void QuickSort(int* a,int left,int right){if(left < right){if(right - left < 3) //当区间比较小,接近有序时,适合使用插入排序{InsertSort(a,right-left+1);}int div = PartSort(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}}
1.之前写的快排都是递归实现的。我们也可以用非递归实现快速排序。这里会用到栈。
代码实现:
//用栈实现#include<stack>int MidNum(int* a,int left,int right){int mid = left+((right-left)>>1);if(a[mid] < a[right]){if(a[mid] < a[right])return mid;else if(a[left] < a[right])return right;elsereturn left;}else{if(a[left] < a[right])return left;else if(a[mid] < a[right])return right;elsereturn mid;}}int PartSortMid(int* a,int left,int right){int MidKey = MidNum(a,left,right);swap(a[MidKey],a[right]);int key = right;while(left < right){while(left < right && a[left] <= a[key])++left;while(left < right && a[right] >= a[key])--right;swap(a[left],a[right]);}swap(a[left],a[key]);return left;}void QuickSortNonR(int *a,int left,int right){stack<int> st;st.push(right);st.push(left);while(!st.empty()){if(right-left < 3)InsertSort(a,right-left+1);left = st.top();st.pop();right = st.top();st.pop();int div = PartSortMid(a,left,right);if(div-1 > left){st.push(div-1); //注意入栈顺序st.push(left);}if(div+1 < right){st.push(right);st.push(div+1);}}}
运行结果:
- 快速排序--全集
- 排序算法全集
- 排序算法全集
- 各种排序算法全集
- 各种排序算法全集
- C++经典排序算法全集
- C++排序算法全集【附代码】
- c++经典排序算法全集(转)
- 快速排序
- 快速排序
- 快速排序
- 快速排序!
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- php模拟post提交请求
- Javascript内置对象和面向对象的实现----对象和数组的概念
- c++作业7
- s3c2440 IIC AT24C08
- 强悍的 Linux —— 文件解压与解压
- 快速排序--全集
- ## Unity3D实现粒子光环效果
- html&&html5(3)
- java web3 jsp编程基础
- Java大牛养成记(10)----Maven
- c++实验7-素数和回文
- SQL SERVER 用户名、密码登入判断
- jQuery中this与$(this)的区别
- LruCache源码浅析