Java 快速排序
来源:互联网 发布:手机连不上4g网络 编辑:程序博客网 时间:2024/05/17 04:37
快速排序作为一种快速的排序算法,所以现在就详细的介绍一下 。
快速排序是冒泡的一种改进 都是交换类的排序算法
( 冒泡排序是每轮都把当前排序范围中最大的数放到最后 )
快速排序是确定一个PivotKey ,把当前数组范围分成三份,左边是小于PivotKey的,中间是PivotKey,右边是大于PivotKey的
当然可能PivotKey最小 没有左边的部分 ,反之。
快速排序是基于分治策略的一种算法 (分治法的思想是将一个规模为n 的问题分解成k个较小规模的子问题,子问题互相独立且与原问题相同)
快速排序的基本思想是三个步奏:
1,分解 : 通常以待排列数组第一个元素为 PivotKet(或用随机选择策略 随机选取其中一个元素作为PivotKey), 将数组划分成三段 , 中间是小于PivotKey的元素
中间是PivotKey 右侧是大于它的元素 (要是PivotKey为最小的元素 就直接去第二步)
2,递归求解:通过递归手段 对上一步的左边 和 右边的数组进行快速排序
3,合并 ;由于对于子数组的排列是直接用的原数组,所以在递归结束,整个数组已经是有序的了 不需要额外的合并操作
上代码,这里的代码只是一种解法 别的解法暂无研究 ,代码有错误 或者不完美的留言指正,你说我就改,就怕你不来
public class Test {private static int[] data;/** * 对 数组 s 到 e 这一段进行快速排序 步骤如下: 定义 i = s; j = e; i,j 都为数组下标 * * 从j向前搜索找第一个小于 X 的元素, i , j 交换 --------------步骤1 * 从i向前搜索找第一个大于 X 的元素, i , j 交换 --------------步骤2 * 重复步骤 1 2 直到 i = j * * **** 总的思想就是以PivotKey为中心分解成两拨数的时候 一直都是PivotKey这个数一直在交换 所以我们需要交换一次 就得调转方向 * 以便让比较的范围逐渐缩小 也让PivotKey一直向中心靠近 */public static void Divide(int s, int e) {int i, j;i = s;j = e;boolean isLeft = true; // 表示当前PivotKey是在相对于左边一点的位置还是右边一点的位置 // 其实就是上一次交换中PivotKey是被换到左边还是右边if (i >= j) { return;}while (i != j) {if (data[j] < data[i]) { // j,i对应的数组元素必有一个是PivotKey (慢慢根据结果分析得出) // 当 j = PivotKey,按步骤2 // 当 i = PivotKey,按步骤1 // 所以一个判断就搞定 是不是niceint temp = data[i];data[i] = data[j];data[j] = temp;isLeft = (isLeft == true) ? false : true;}if (!isLeft) { // 每次比较之后,如果PivotKey在右边,根据步骤1,左边的指针后移,反之i++;} else {j--;}}// while循环结束 i,j 相等 停在PivotKey上 所以递归求解时 必须i,j分离i--;j++;
//递归时刻 两次递归调用 分别对应分解出的左边和右边的数组Divide(s, i); Divide(j, e);}/** * * 输出当前数组 */public static void PrintData() {for (int i = 0; i < 10; i++) {System.out.print(" " + data[i]);}System.out.println("");}public static void main(String[] args) {data = new int[10];Scanner scanner = new Scanner(System.in);System.out.println("输入十个数字进行快速排序");for (int m = 0; m < 10; m++) {data[m] = scanner.nextInt();}Divide(0, 9);PrintData();scanner.close();}}代码固定了只输入十个数 是为了方便观察结果 数组长度可以自定义,稍微修改下代码即可
示例输入 : 41 1 23 14 78 55 69 15 6 51
每次交换后的数组变化 :
6 1 23 14 78 55 69 15 41 51
6 1 23 14 41 55 69 15 78 51
6 1 23 14 15 55 69 41 78 51
6 1 23 14 15 41 69 55 78 51
1 6 23 14 15 41 69 55 78 51
1 6 15 14 23 41 69 55 78 51
1 6 14 15 23 41 69 55 78 51
1 6 14 15 23 41 51 55 78 69
1 6 14 15 23 41 51 55 69 78
以上面数据为例 说一下第一次分解的过程
开始 : 41 1 23 14 78 55 69 15 6 51
以41 为PivotKey , i = 0, j = 9 , data[j] < data[i] 即51<41 不满足 ;
j-- 变为8 , 6 <41 满足if判断,交换。
数组变为 :6 1 23 14 78 55 69 15 41 51
然后i++ 变为1 ,1 不满足 , i++ 变为2 ,23 不满足,i++ 变为3 ,14也不满足,i++变为4 ,78满足交换
数组变为: 6 1 23 14 41 55 69 15 78 51
此时j-- , 变为 7,15 < 41 ,满足 交换
数组变为: 6 1 23 14 15 55 69 41 78 51
此时i++,变为5 ,41 <55 满足交换
数组变为: 6 1 23 14 15 41 69 55 78 51
此时j-- ,变为6 ,69>41 不满足 ,j-- 变为5
i == j while循环结束 进入递归。。。。。。。
快速排序的平均时间复杂度 :O(n*lgn) 最坏时间复杂度为 : O(n^2),最好情况:O(nlgn) 空间复杂度 : O(lgn)
* 快速排序的时间复杂度与 划分是否对称 有关;
* ***最坏情况** 为:每次递归都划分为产生两个区域分别包含 n-1和 1 个元素 由于分解当前数组这部分的时间复杂度为O(n),
* 所以快排的时间复杂度T(n)满足:
* { O(1) n<=1
* T(n) = |
* { T(n-1) + O(n) n>1
* 解此递归方程得 T(n) = O(n^2)
*
* ***最好情况*** 为:每次划分的 PivotKey都处在最中间,即产生了两个大小为 n/2的区域
* { O(1) n<=1
* T(n) = |
* { 2T(n/2) + O(n) n>1
* 解得 : T(n) = O(nlgn)
快速排序最坏的情况就是待排数据基本有序,退化为冒泡排序,时间复杂度为O(n^2)
快速排序递归过程对应一棵二叉树,其递归工作栈的大小与递归调用二叉树的深度相对应,最好情况下是一棵完全二叉树
可以证明快速排序在平均情况下时间复杂度也是O(nlgn) ~~~~~怎么证明的搞不懂
下一讲将最简单的交换类排序:冒泡
- 排序-快速排序-Java
- java排序之快速排序
- Java排序算法 快速排序
- 快速排序(java排序)
- java 快速排序,冒泡排序
- 算法:排序----Java快速排序
- 【交换排序】快速排序--Java
- java 插入排序+快速排序
- Java 排序之 快速排序
- java排序之快速排序
- Java排序算法:快速排序
- Java排序-快速排序
- Java排序算法:快速排序
- Java排序算法--》快速排序
- JAVA排序算法---快速排序
- Java 快速排序 归并排序
- Java排序算法--快速排序
- java 冒泡排序、快速排序
- 微信零钱提现不到账
- Android通过DexClassLoader加载apk文件
- POJ3252数位DP
- LeetCode题解:Maximum Depth of Binary Tree
- 《JAVA编程思想》日志(三)------操作符
- Java 快速排序
- mybatis学习笔记(1)-对原生jdbc程序中的问题总结
- H5 canvas drawImage 无法显示
- CMD卸载3035583、去win10
- androidstudio入门-新建模拟器
- AndroidStudio初体验
- mybatis学习笔记(2)-mybatis概述
- 11.2 RAC: In "crsctl stat res -t" State Details May Be Missing or Incorrect (文档 ID 1086563.1)
- Spring之ApplicationContext