经典排序算法:快速排序(Quick Sort)
来源:互联网 发布:mac下视频音频格式转换 编辑:程序博客网 时间:2024/06/05 04:52
快速排序算法
快速排序算法被称为20世纪十大算法之一,是最重要的算法之一,是一定要掌握和熟练的!
快速排序的基本思想是:(分治法)
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
案例分析
假如现在我们要对这个序列,{50,10,90,30,70,40,80,60,20}进行快速排序,序列的原始状态是这样的:
关键代码
//算出中间值关键代码 int partition(SqList *L, int low, int high){ int pivotkey = L->r[low]; while(low < high){ while(low<high&&L->r[high] >= pivotkey){ high--; } swap(L, low, high); while(low<high&&L->r[low] <= pivotkey){ low++; } swap(L, low, high); } return low;}//对无序序列进行排序 void qSort(SqList *L, int low, int high){ int mid; if(low < high){ mid = partition(L, low, high);//算出中间值 qSort(L, low, mid-1);//对左边的表递归排序 qSort(L, mid+1, high);//对右边的表递归排序 }}
方法qSort表现了我们的算法思想,首先通过partition算出中间值,然后再对两边的值进行递归排序。
partition方法,初始时pivotkey 为50,然后进行逻辑判断。
当high指针所指向的值大于pivotkey,则一直让high指针递减,直到high指向一个比pivotkey小的数时,然后让high指针和low指针的值交换,目的就是为了把较小的值移到左边。图中20会与50交换。
当low指针指向的值小于pivotkey时,则一直让low递增,直到low指向一个比pivotkey大的数时,然后让high指针和low指针的值交换,目的就是为了把较大的值移到右边。图中low指针会移到90,然后90和50交换。
完整代码
#include <stdio.h>#include <stdlib.h>#define MAXSIZE 10typedef struct{ int r[MAXSIZE]; int length;}SqList;void swap(SqList *L, int i, int j){ int temp = L->r[i]; L->r[i] = L->r[j]; L->r[j] = temp;}void initSort(SqList *L){ L->length = 9; L->r[0] = 0; int a[9] = {50,10,90,30,70,40,80,60,20} ; for(int i = 1; i<MAXSIZE; i++){ L->r[i] = a[i-1]; }}//算出中间值关键代码 int partition(SqList *L, int low, int high){ int pivotkey = L->r[low]; while(low < high){ while(low<high&&L->r[high] >= pivotkey){ high--; } swap(L, low, high); while(low<high&&L->r[low] <= pivotkey){ low++; } swap(L, low, high); } return low;}//对无序序列进行排序 void qSort(SqList *L, int low, int high){ int mid; if(low < high){ mid = partition(L, low, high);//算出中间值 qSort(L, low, mid-1);//对左边的表递归排序 qSort(L, mid+1, high);//对右边的表递归排序 }}void quickSort(SqList *L){ qSort(L, 1, L->length);}void searchSort(SqList *L){ for(int i = 1; i < MAXSIZE; i++){ printf("%d ", L->r[i]); }}int main(){ SqList *L = new SqList; initSort(L); searchSort(L); printf("\n"); quickSort(L); searchSort(L); return 0;}
结果如下:
算法时间复杂度分析
在最好的情况下,第一次partition会扫描n个关键字,做n次比较,因此此时的时间复杂度为n,记为T(n)。然后,获得的中间值将数组一分为二,那么各自需要T(n/2),此时的总时间为:2 T(n/2)+n
如下:
T(n) <= 2T(n / 2) + n
T(n) <= 2(2T(n / 4) + n/2) + n = 4T(n/4) + 2n
T(n) <= 4(2T(n / 8) + n/4) + 2n = 8T(n/8) + 3n
….
T(n) <= nT(1) + (logn) * n = O(nlogn)
所以,最优情况下,快速排序的算法时间复杂度为O(nlogn)
优化
- 发现一个问题,partition函数中,中间值pivotkey的取值是一个很值得商榷的问题,我们一开始设它为L->r[low],只是刚好L->r[low]为50,因此pivotkey的值是比较接近中间值的。但是假如在有这样一个序列,{9,1,4,8,6,5,2,3,7},那么此时pivotkey的值为9,但是9是整个序列最大值,这样我们的无用比较会做多少次啊!
我们可以用三数取中法,取三个关键字排序,再将中间值作为序列的中间值,一般取左端,中间,右端三个数。
//算出中间值关键代码 int partition(SqList *L, int low, int high){ int pivotkey; //增加了优化代码 int m = low + (high - low) / 2;//中间元素的下标 if(L->r[low] > L->r[high]){ swap(L, low, high);//保证左端较小 } if(L->r[m] > L->r[high]){ swap(L, m, high);//保证中间值较小 } if(L->r[m] > L->r[low]){ swap(L, low, m);//保证low位置的值为low,mid,high中第二大的 } pivotkey = L->r[low]; while(low < high){ while(low<high&&L->r[high] >= pivotkey){ high--; } swap(L, low, high); while(low<high&&L->r[low] <= pivotkey){ low++; } swap(L, low, high); } return low;}
- pivotekey的交换次数不必要,因为他最终都会到达中间(low
public static int partition(int low, int high){ int privoteKey = array[low]; int back = privoteKey; while(low < high){ while(low<high && array[high] >= privoteKey){ high--; } //直到发现了有半部分有小于privotekey的数 //采用替换 array[low] = array[high]; while(low<high && array[low] <= privoteKey){ low++; } array[high] = array[low]; } array[low] = back; return low; }
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法 - 快速排序Quick sort
- 经典排序算法:快速排序(Quick Sort)
- 排序算法---快速排序(Quick Sort)
- 快速排序算法(Quick Sort)
- 算法---快速排序(quick sort)
- 快速排序算法-Quick Sort
- 【排序算法】 快速排序 quick sort(交换类排序)
- 白话经典算法系列之六 快速排序(Quick sort)
- [算法导论][排序算法]快速排序(quick sort)
- 【算法基础】【排序】快速排序 - Quick Sort
- 常见排序算法 - 快速排序 (Quick Sort)
- 排序算法之快速排序(Quick sort)
- 我的JavaScript起步
- expect解决ssh无法使用shell直接登录的问题
- (Caffe)LSTM层分析
- SpringMVC简单整合Angular2
- Codeforces 525E Anya and Cubes【折半枚举法+剪枝Dfs】好题~
- 经典排序算法:快速排序(Quick Sort)
- Swift教程-类与结构体
- C语言的几种循环
- Java - JFrame 设置背景图片
- 跑马灯实验-寄存器版
- Android Dev 进程与线程 学习
- 180中国跳棋(12)186(13)191(14)196(15)201(16)205(17)209.5(18)
- Android 横竖屏切换总结
- 一个极其简陋的C/C++日志工具