快速排序 (Quick Sort)(Java实现)
快速排序(Quicksort)是对冒泡排序的一种改进,借用了分治的思想,由C. A. R. Hoare在1962年提出。
1、基本思想
快速排序的基本思想:挖坑填数+分治法。
首先选一个轴值(pivot,也有叫基准的),通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
2、算法描述
快速排序使用分治策略来把一个序列(list)分为两个子序列(sub-lists)。步骤为:
- 从数列中挑出一个元素,称为"基准"(pivot)
- 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
- 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序
递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
3、代码实现
用伪代码描述如下:
- i = L; j = R; 将基准数挖出形成第一个坑a[i]
- j–,由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中
- i++,由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中
- 再重复执行②,③二步,直到i==j,将基准数填入a[i]中
3.1 递归实现
/*** 快速排序(递归)** ①. 从数列中挑出一个元素,称为"基准"(pivot)。* ②. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。* ③. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。* @param arr 待排序数组* @param low 左边界* @param high 右边界*/
public static void quickSort(int[] arr, int low, int high){if(arr.length <= 0) return;if(low >= high) return;int left = low;int right = high;int temp = arr[left]; //挖坑1:保存基准的值while (left < right){while(left < right && arr[right] >= temp){ //坑2:从后向前找到比基准小的元素,插入到基准位置坑1中right--;}arr[left] = arr[right];while(left < right && arr[left] <= temp){ //坑3:从前往后找到比基准大的元素,放到刚才挖的坑2中left++;}arr[right] = arr[left];}arr[left] = temp; //基准值填补到坑3中,准备分治递归快排System.out.println("Sorting: " + Arrays.toString(arr));quickSort(arr, low, left-1);quickSort(arr, left+1, high);
}
上面是递归版的快速排序:通过把基准temp插入到合适的位置来实现分治,并递归地对分治后的两个划分继续快排。那么非递归版的快排如何实现呢?
因为递归的本质是栈,所以我们非递归实现的过程中,可以借助栈来保存中间变量就可以实现非递归了。在这里中间变量也就是通过Pritation函数划分区间之后分成左右两部分的首尾指针,只需要保存这两部分的首尾指针即可。
3.2 非递归实现
/*** 快速排序(非递归)** ①. 从数列中挑出一个元素,称为"基准"(pivot)。* ②. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。* ③. 把分区之后两个区间的边界(low和high)压入栈保存,并循环①、②步骤* @param arr 待排序数组*/
public static void quickSortByStack(int[] arr){if(arr.length <= 0) return;Stack<Integer> stack = new Stack<Integer>();//初始状态的左右指针入栈stack.push(0);stack.push(arr.length - 1);while(!stack.isEmpty()){int high = stack.pop(); //出栈进行划分int low = stack.pop();int pivotIdx = partition(arr, low, high);//保存中间变量if(pivotIdx > low) {stack.push(low);stack.push(pivotIdx - 1);}if(pivotIdx < high && pivotIdx >= 0){stack.push(pivotIdx + 1);stack.push(high);}}
}private static int partition(int[] arr, int low, int high){if(arr.length <= 0) return -1;if(low >= high) return -1;int l = low;int r = high;int pivot = arr[l]; //挖坑1:保存基准的值while(l < r){while(l < r && arr[r] >= pivot){ //坑2:从后向前找到比基准小的元素,插入到基准位置坑1中r--;}arr[l] = arr[r];while(l < r && arr[l] <= pivot){ //坑3:从前往后找到比基准大的元素,放到刚才挖的坑2中l++;}arr[r] = arr[l];}arr[l] = pivot; //基准值填补到坑3中,准备分治递归快排return l;
}
快速排序是通常被认为在同数量级(O(nlog2n))的排序方法中平均性能最好的。但若初始序列按关键码有序或基本有序时,快排序反而蜕化为冒泡排序。为改进之,通常以“三者取中法”来选取基准记录,即将排序区间的两个端点与中点三个记录关键码居中的调整为支点记录。快速排序是一个不稳定的排序方法。
以下是快速排序算法复杂度:
平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 |
---|---|---|---|
O(nlog₂n) | O(nlog₂n) | O(n²) | O(1)(原地分区递归版) |
快速排序排序效率非常高。 虽然它运行最糟糕时将达到O(n²)的时间复杂度, 但通常平均来看, 它的时间复杂为O(nlogn), 比同样为O(nlogn)时间复杂度的归并排序还要快. 快速排序似乎更偏爱乱序的数列, 越是乱序的数列, 它相比其他排序而言, 相对效率更高.
Tips: 同选择排序相似, 快速排序每次交换的元素都有可能不是相邻的, 因此它有可能打破原来值为相同的元素之间的顺序. 因此, 快速排序并不稳定.
4、拓展
https://github.com/iTimeTraveler/SortAlgorithms#六快速排序quick-sort
https://blog.csdn.net/shujuelin/article/details/82423852
快速排序 (Quick Sort)(Java实现)相关推荐
- 快速排序 Quick Sort
快速排序 Quick Sort 我们已经知道,在决策树计算模型下,任何一个基于比较来确定两个元素相对位置的排序算法需要Ω(nlogn)计算时间.如果我们能设计一个需要O(n1ogn)时间的排序算法,则 ...
- 【排序算法】快速排序(Quick Sort)
快速排序(Quick Sort)使用分治法算法思想. 快速排序介绍 它的基本思想是: 选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分:其中一部分的所有数据都比另外一部分的所有数据都要小. ...
- Golang TDD实践报告:快速排序Quick Sort
Golang TDD实践报告:快速排序Quick Sort [阅读时间:约5分钟] 0.项目需求 1.编写符合项目输入输出的一个测试 2.尝试运行测试 3.先使用最少的代码来让失败的测试先跑起来 4. ...
- C语言快速排序 quick sort 算法(附完整源码)
快速排序 quick sort 算法 快速排序 quick sort 算法的完整源码(定义,实现,main函数测试) 快速排序 quick sort 算法的完整源码(定义,实现,main函数测试) # ...
- Java实现快速排序 Quick Sort
本文带来八大排序算法之快速排序算法. 快速排序(QuickSort)是对冒泡排序的一种改进.基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小, ...
- java sort算法名称_快速排序算法(Quick Sort)(java)
/** * 快速排序算法是基于分治策略的一种排序算法,下面是一个递归的快速排序. * @author liuy */ public class QuickSort { public static vo ...
- 快速排序quick sort
一.快速排序的基本思想: 1.在集合中找一个数作为基准数: 2.集合分为三部分:左分区.基准数.右分区,其中左分区的数都小于等于基准数,右分区的数都大于等于基准数: 3.分别对左分区.右分区执行第2步 ...
- 基础算法之快速排序Quick Sort
原理 快速排序(Quicksort)是对冒泡排序的一种改进. 从数列中挑出一个元素,称为"基准"(pivot); 排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的 ...
- 两种风格的快速排序 Quick Sort
啊哈算法中的quick_sort.cpp // // Created by jal on 18-9-2. // #include <bits/stdc++.h>using namespac ...
最新文章
- 第二十课.DeepGraphLibrary(一)
- 深入Atlas系列:Web Sevices Access in Atlas示例(6) - 在客户端隐藏服务器端类型信息...
- golang中的TestMain
- GlobalAlloca GlobalLock GlobalUnlock函数的作用
- autotype安全 fastjson_Fastjson 安全更新,建议升级到 1.2.28 或更新版本
- python网络编程要学吗_总算发现如何学习python网络编程
- 如何优雅的利用Windows服务来部署ASP.NET Core程序
- 死锁 预防死锁避免死锁_死锁和处理死锁的方法
- 使用phpize建立php扩展(Cannot find config.m4)
- Win10电脑系统文件损坏怎么修复
- go语言学习之切片、字典、defer语句
- GAN相关论文《Spectral Regularization for Combating Mode Collapse in GANs》
- Android地图中根据缩放级别显示Marker
- 用moment将时间戳格式化为周几 几月几日
- 济南大雨,银座亲历(转载)
- tg测试软件,TG Pro for mac(硬件温度检测工具)
- Windows下使用脚本文件删除指定文件
- 华脉智联可视化指挥调度系统
- autoit学习笔记---“While…WEnd”循环
- hdmi网线延长器_HDMI转RJ45单网线延长器HE12
热门文章
- Android之学习安卓每天成长笔记
- php获取当前操作系统类型 PHP_OS
- mysql老是自动停止_ecs云服务器 mysql经常自动停止挂掉重启问题分析
- ORA-00257+mysql_ORA-00257错误的解决办法
- 简单而又不平凡的杨辉三角形
- 通过Python实现马尔科夫链蒙特卡罗方法的入门级应用
- 数据告诉你,抖音是如何在半年之内逆袭的
- 《SAS编程与数据挖掘商业案例》学习笔记之十一
- 程学旗 计算机,徐明伟-青年科学家奖-中国计算机学会
- getchar()到底怎么用_怎样才能真正发挥肥效,腐植酸水溶肥到底怎么用