目录

  • 快速排序:
    • 1.1 hoare法(左右指针法)
    • 1.2 挖坑法(重点)
    • 1.3 快速排序优化
    • 1.4 非递归快速排序
    • 1.5 基准值的选择方法 :
    • 1.6 思路总结

快速排序:

原理:

  1. 从待排序区间选择一个数,作为基准值(pivot);
  2. Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
  3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。

1.1 hoare法(左右指针法)

思路:

  1. 选出一个key,一般是最左边或是最右边的。
  2. 定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则需要end先走;若选择最右边的数据作为key,则需要bengin先走)。
  3. 在走的过程中,若end遇到小于key的数,则停下,begin开始走,直到begin遇到一个大于key的数时,将begin和right的内容交换,end再次开始走,如此进行下去,直到begin和end最终相遇,此时将相遇点的内容与key交换即可。(选取最左边的值作为key)
  4. 此时key的左边都是小于key的数,key的右边都是大于key的数
  5. 将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作,此时此部分已有序

动图演示如下 :

1.2 挖坑法(重点)

博主认为挖坑法比hoare法更容易理解,所以本篇博文博主采用挖坑法进行代码实现

思路:
挖坑法思路与hoare版本(左右指针法)思路类似
1.选出一个数据(一般是最左边或是最右边的)存放在key变量中,在该数据位置形成一个坑
2、还是定义一个L和一个R,L从左向右走,R从右向左走。(若在最左边挖坑,则需要R先走;若在最右边挖坑,则需要L先走)
后面实现思路与hoare法类似,这里就不再赘述了

动图演示如下:

代码如下:

/*** 快速排序* 时间复杂度:* 最好【每次可以均匀的分割待排序序列】:O(N*logn)* 最坏:数据有序 或者逆序的情况 O(N^2)* 空间复杂度:* 最好:O(logn)* 最坏:O(n)   单分支的一棵树* 稳定性:不稳定的排序* @param array*/public static void quickSort(int[] array){quick(array,0,array.length-1);}public static void quick(int[] array,int left,int right){int pivot=partition(array,left,right);quick(array,left,pivot-1);quick(array,pivot+1,right);}// 快速排序 挖坑法找基准private static int partition(int[] array,int start,int end){int tmp=array[start];while (start<end){while (start<end && array[end]>=tmp){end--;}//end下标的值遇到了小于tmp的值array[start]=array[end];while (start<end && array[start]<=tmp){start++;}//start下标的值遇到了大于tmp的值array[end]=array[start];}array[start]=tmp;return start;}

1.3 快速排序优化

再实现了上面的挖坑法快速排序之后,我们可以进行优化快速排序的操作,如下:

 public static void quickSort(int[] array){quick(array,0,array.length-1);}//用于优化快速排序的选择排序public static void insertSort2(int[] array,int start,int end){for (int i =1 ; i <=end ; i++) {int tmp=array[i];int j=i-1;for (; j>=start ; j--) {if (array[j]>tmp){array[j+1]=array[j];}else {// 只要j回退的时候,遇到了比tmp小的元素,就结束这次的比较break;}}//j回退到了 小于0 的地方array[j+1]=tmp;}}public static void quick(int[] array,int left,int right){if (left>=right){ //递归出口return;}//0.如果区间内的数据,在排序的过程中,小于某个范围了,可以使用直接插入排序if (right-left+1<=40){ //right-left+1求得的是当前元素个数insertSort2(array,left,right);return;}//1.找基准之前,我们找到中间大小的值---使用三数取中法int midValIndex=findMidValIndex(array,left,right);swap(array,midValIndex,left);int pivot=partition(array,left,right);quick(array,left,pivot-1);quick(array,pivot+1,right);}//找出三个值中间大小的值的函数private static int findMidValIndex(int[] array,int start,int end){int mid=start+((end-start)/2);if (array[start]<array[end]){if (array[mid]<array[start]){return start;}else if (array[mid]>array[end]){return end;}else {return mid;}}else {if (array[mid]>array[start]){return start;}else if (array[mid]<array[end]){return end;}else {return mid;}}}// 快速排序 挖坑法找基准private static int partition(int[] array,int start,int end){int tmp=array[start];while (start<end){while (start<end && array[end]>=tmp){end--;}//end下标的值遇到了小于tmp的值array[start]=array[end];while (start<end && array[start]<=tmp){start++;}//start下标的值遇到了大于tmp的值array[end]=array[start];}array[start]=tmp;return start;}

优化总结

  1. 选择基准值很重要,通常使用几数取中法
  2. partition 过程中把和基准值相等的数也选择出来
  3. 待排序区间小于一个阈值时(例如 48),使用直接插入排序

1.4 非递归快速排序

非递归快速排序需要借助栈来实现

  //非递归快速排序public static void quickSortF(int[] array){Stack<Integer> stack=new Stack<>();int left=0;int right=array.length-1;int pivot=partition(array,left,right);if (pivot>left+1){//左边有2个元素stack.push(left);stack.push(pivot-1);}if (pivot<right-1){//右边有2个元素stack.push(pivot+1);stack.push(right);}while (!stack.isEmpty()){right=stack.pop();left=stack.pop();pivot=partition(array,left,right);if (pivot>left+1){//左边有2个元素stack.push(left);stack.push(pivot-1);}if (pivot<right-1){//右边有2个元素stack.push(pivot+1);stack.push(right);}}}

1.5 基准值的选择方法 :

基准值的选择

  1. 选择边上(左或者右)
  2. 随机选择
  3. 几数取中(例如三数取中):array[left], array[mid], array[right] 大小是中间的为基准值(优化实现了)

1.6 思路总结

  1. 在待排序区间选择一个基准值
    选择左边或者右边
    随机选取
    几数取中法

  2. 做 partition,使得小的数在左,大的数在右
    hoare法
    挖坑法
    前后遍历
    将基准值相等的也选择出来

  3. 分治处理左右两个小区间,直到小区间数目小于一个阈值,使用插入排序

【Java】排序算法 之 【快速排序】 总结相关推荐

  1. java 排序算法之快速排序(挖坑法)

    快速排序是(挖坑法)是挖坑填数 + 分治来实现. 快速排序的基本思想: 1.先从数列中取出一个数作为基准数. 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边. 3.再对左 ...

  2. 十大排序算法之快速排序(两种方法)

    十大排序算法之快速排序 本文采用Java书写选择排序,其他语言类似可以借鉴着写 思想:在待排序序列中选择一个分割元素,将待排序序列中所有比分割元素关键字小的元素移动到分割元素左侧位置:将待排序序列中所 ...

  3. Java十大排序算法总结,Java排序算法总结之冒泡排序

    本文实例讲述了Java排序算法总结之冒泡排序.分享给大家供大家参考.具体分析如下: 前言:冒泡排序(BubbleSort)就是依次比较相邻的两个数,将小数放在前面,大数放在后面. 下面让我们一起    ...

  4. java 排序算法总结,Java排序算法总结之归并排序

    本文实例讲述了Java排序算法总结之归并排序.分享给大家供大家参考.具体分析如下: 归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作.和快速排序类似,让我们一起来看 ...

  5. Java排序算法:冒泡排序

    Java排序算法:冒泡排序 //创建数组并赋值int[] data = new int[] {11,10,55,78,100,111,45,56,79,90,345,1000};for(int i=0 ...

  6. 排序算法之----快速排序(快速上手快速排序)

    排序算法之----快速排序(快速上手快速排序) 何为快速排序算法? 快速排序的基本思想又是什么? 其实很简单: 快速排序的基本思想是 1.先从数列中取出一个数作为基准数(这里我们的算法里面取数组最右边 ...

  7. Java排序算法之直接选择排序

    Java排序算法之直接选择排序 基本过程:假设一序列为R[0]~R[n-1],第一次用R[0]和R[1]~R[n-1]相比较,若小于R[0],则交换至R[0]位置上.第二次从R[1]~R[n-1]中选 ...

  8. java排序算法 sort_Java排序算法之SleepSort排序示例

    本文实例讲述了Java排序算法之SleepSort排序.分享给大家供大家参考,具体如下: 分享一个很有创意的排序算法:sleepSort .巧妙利用了线程的sleep(),代码如下: public c ...

  9. php1到5000排序,常用的排序算法(一)--快速排序(PHP实现)

    常用的排序算法系列 快速排序 假设当前需要从小到大进行排序,快速排序的核心思路是,从当前数组中,找到一个元素作为基准比较值(key),分别从两个方向进行比较.从后往前找,比key小元素放在数组前面.然 ...

  10. Java排序算法——插入排序(Insertion Sort)

    之前总结了交换排序的冒泡排序与选择排序的简单选择排序,这次我们来看看插入排序的简单插入排序~ 往期传送门: 冒泡排序: Java排序算法--冒泡排序(Bubble Sort)https://blog. ...

最新文章

  1. 目标检测 - Tensorflow Object Detection API
  2. python语音程序设计基础篇_【笔记】python自学笔记(基础篇)——字典操作
  3. golang 二维切片
  4. soap方式的远程调用示例代码
  5. 计算机系统层次中应用语言级,计算机系统的多级层次结构
  6. 如何将FPGA资源平民化?阿里工程师有了新突破
  7. input文本框设置和移除默认值
  8. tpm php,TPM系列
  9. 真机上装不上测试应用,Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
  10. as与asp.net通信
  11. Golang的GC和内存逃逸
  12. dep指定版本 go_Go 包管理工具-dep
  13. java整数int的32位输出
  14. 开源分词系统pkuseg学习
  15. 如何掌握苹果发布会 PPT 制作要点
  16. ucfirst php_PHP ucfirst()函数与示例
  17. Grafana 短信报警
  18. EBS中二次开发FSG报表2(SQL)
  19. ctfshow七夕杯 writeup
  20. MySQL数据库整理

热门文章

  1. 讲讲Git如何合并分支(一)
  2. 项目性能优化(MySQL读写分离、MySQL主从同步、Django实现MySQL读写分离)
  3. 线性回归之案例:波士顿房价预测
  4. Linux之查找文件命令
  5. OSI第六层:表示层功能作用
  6. 中秋将至,联合几个号主送出价值500元的中秋大礼包
  7. 用python和opencv检测图像中的条形码
  8. 使用Keras进行迁移学习
  9. lattice LFE3-17EA 调试记录
  10. Spring MVC常用注解--“姐妹花”@RequestBody和@ResponseBody