手写快速排序
来源:互联网 发布:卫生网络答题 编辑:程序博客网 时间:2024/04/30 10:22
前言
快速排序是一种很重要的排序算法,我花了不少时间去理解并总结它,希望可以通过图文的方式让你快速理解快速排序,并能手撸一个快排。
快速排序简介
快速排序是一种很不错的排序算法,算法复杂度为n*logn。快排使用了分而治之的思想,每次排序是都找到一个基准(我们学习时经常使用第一个作为基准),然后把小于基准的元素放到基准元素的左边,大于基准的元素放到基准元素的右边,这样一次排序下来,基准元素左边都是小于(等于)基准的数,基准右边的元素都是大于(等于)基准的元素了。快速排序关键点就是找到这样一个基准并将其放到恰到的位置。
算法思路
定义一个快速排序函数,arr是要排序的数组,l指向要排序的数组最左边的元素,r指向要排序的数组最右边的元素。
public static void quick_sort(int arr[],int l,int r){ if(l >= r) return; //p为快速排序返回的基准的位置 int p = partition2(arr,l,r); //对基准左边的数进行快排 quick_sort(arr,l,p-1); //对基准右边的数进行快排 quick_sort(arr,p+1,r); }
那么现在关键就是这么实现这个partition2
函数
假设现在有一个数组arr[]:
我们每次都取第一个元素为基准元素,定义i指向基准的下一个元素位置,j指向最后一个元素的位置:
i 从左向右扫描,如果arr[i] <= v , i++
j从右向左扫描,如果 arr[j] > v ,j++
直到i指向一个大于v的元素,j指向一个小于j的元素,且 这个过程中 i <= j
此时i左边(除基准元素)都是小于v的,j右边都是大于v的,现在只需要交换arr[i]与arr[j]的位置,就可以把小于v的放左边,大于v的放右边,然后i++,j–
继续比较,此时arr[i] = 4 < 5,i++ ,arr[j] > 5 j–
到这里 i > j 了,退出循环,最后把基准v与arr[j]交换位置,即把v放到了小于v的元素的最后一个,此时一次快速排序就完成了。
代码实现
//快速排序,另一种从前后扫描的 public static int partition2(int arr[],int l,int r){ //基准元素设为第一个 int v = arr[l]; //i指向基准的下一个元素,j指向最后一个元素 int i = l+1,j = r; while(true){ while(i <= r && arr[i] < v) i++; while(j > l && arr[j] > v) j--; //循环终止条件 if(i > j) break; //交换arr[i]与arr[j] int t = arr[i]; arr[i] = arr[j]; arr[j] = t; i++; j--; } //将基准元素与arr[j]交换 int t = arr[l]; arr[l] = arr[j]; arr[j] = t; //返回基准元素所在位置 return j; }
快速排序的几个问题
1、对于几乎有序的数组,快速排序返回的基准的位置都在第一个或很靠前的位置,使得对数组的切分不够平均,可能使得快速排序的时间复杂度退到o(n^2) , 对于这种情况,可以在排序时选取数组中的一个随机位置的数作为基准数。
2、对于数组中的元素有很多相等元素时,也会导致快排对数组的切分不平衡,此时快排的时间复杂度也可能退到o(n^2) , 对于这种情况,可以使用三路快速排序,把小于基准v的放左边,等于v的放中间,大于v的放右边,就避免了左右不平衡的问题。
3、在进行快排时候,当数比较少的时候,使用插入排序代替快排可提高算法效率。
三路快速排序
三路快速排序针对数组中有很多相等元素时照样能有很不错的效率,其主要思想就是将数组中的数分成三个部分:小于基准v的放左边,等于v的放中间,大于v的放右边。
代码
/** * 三路快速排序,确定基准v后将数分成"小于v的","等于v的","大于v的" * @param arr * @param l * @param r */ public static void quickSort3Ways(int arr[],int l,int r){ if(l >= r) return; int v = arr[l]; //初始时,i指向基准位置,j指向最后一个元素的下一个位置 int i = l , j = r + 1; //cur指向当前要进行比较的元素 int cur = i + 1; while(cur < j){ //如果当前元素大于基准元素,将次元素放到后面去,j-- if(arr[cur] > v){ int t = arr[cur]; arr[cur] = arr[j-1]; arr[j-1] = t; j--; //如果当前元素小于v,将它放到i前面去 }else if(arr[cur] < v){ int t = arr[cur]; arr[cur] = arr[i+1]; arr[i+1] = t; i++; cur++; //若当前元素等于v,当前指针cur后移即可 }else{ cur++; } } //最后交换arr[l](基准元素)与arr[i]的位置 int t = arr[i]; arr[i] = arr[l]; arr[l] = t; //对基准元素左边快排 quickSort3Ways(arr,l,i-1); //对基准元素右边快排 quickSort3Ways(arr,j,r); }
- 手写快速排序
- 手写快速排序
- 手写快速排序
- 手写个快速排序
- 手写的qsort快速排序
- 【手写排序算法及优化】快速排序
- 手写快速排序【随机数作基数】
- 手写快速排序——sort
- 技术面试手写代码考题--快速排序
- 需要手写的算法之----------快速排序的排序的列子
- sdnu1521手写qsort排序
- Quicksort 快速排序—注意点以及代码实现(笔试手写代码)
- (让我把右小指敲进键盘的)手写随机版快速排序模板
- 快速排序的一些实现技巧(曾经被手写快排打倒过n+1次。。。)
- 【手写排序算法及优化】冒泡排序
- 需要手写的排序算法---希尔排序
- 日文输入手写汉字模式快速切换
- 快排,堆排序,基数排序手写记录
- go 设置 GOROOT 和 GOPATH
- iOS之利用GCD信号量控制并发网络请求
- Jsp 复习材料一: XML解析
- .NET漫游指南-008-泛型,装箱,泛型委托
- LeetCode-ReversePair
- 手写快速排序
- 46. 主元素
- 字节顺序
- 媒体查询@media
- POJ 2100 Graveyard Design
- POJ 2762【强联通缩点】【拓扑排序】Going from u to v or from v to u?
- 机器学习-导论
- lintcode有效的括号序列
- Git 常用操作(二)