快速排序

引子:Partition 过程

给定一个数组arr,和一个整数num。请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。

要求额外空间复杂度O(1),时间复杂度O(N)

思路

维护一个 小于区,i 从第一个数开始:

  • 只要 i 小于 num,就把 i 与 *小于区右侧的第一个数 *交换,并将小于区向右扩大一个数
  • 如果 i 大于等于 num,将 i++

这样做的原理依据是:
在 i 的左侧,都是看过的数,并且每一次比较,都把比 num 小的数发送到小于区。而 i 右侧是没看过的数,随着 i++,将来一定会被看。

Partition 过程升级版:荷兰旗问题

荷兰器问题的描述,可查看:https://www.jianshu.com/p/356604b8903f

我们将数组划分为三个区域,即:小于区,等于区,大于区

  1. 首先,随机选择一个基准数字 num

  2. 下标 i 从第一个数字开始,与基准数字 num 比较,分为三种情况:

    • 如果 [i] == num,则 i++

    • 如果 [i] < num,则让 [i] 与小于区右侧的第一个元素交换,小于区右移一个元素,i++

    • 如果 [i] > num,则让 [i] 与大于区左侧的第一个元素交换,大于区右移一个元素,i 留在原地

  3. 直到 i 与大于区相撞,即可停止,此时已经完成第一轮比较

  4. 此时可以认为,等于区已经在它们正确的位置上。用同样的方法,递归对小于区、大于区分别进行再一次划分

第一轮排序过程 详细图解

快速排序 3.0 (随机快排 + 荷兰国旗技巧优化)

在arr[L…R]范围上,进行快速排序的过程:

1)在这个范围上,随机选一个数记为num,

1)用num对该范围做partition,< num的数在左部分,== num的数中间,>num的数在右部分。假设== num的数所在范围是[a,b]

2)对arr[L…a-1]进行快速排序(递归)

3)对arr[b+1…R]进行快速排序(递归)

因为每一次partition都会搞定一批数的位置且不会再变动,所以排序能完成

随机快排:时间复杂度分析

在arr[L…R]范围上,进行快速排序的过程:

1)在这个范围上,随机选一个数记为num,

1)用num对该范围做partition,< num的数在左部分,== num的数中间,>num的数在右部分。假设== num的数所在范围是[a,b]

2)对arr[L…a-1]进行快速排序(递归)

3)对arr[b+1…R]进行快速排序(递归)

因为每一次partition都会搞定一批数的位置且不会再变动,所以排序能完成

代码

public static void quickSort(int[] arr) {if (arr == null || arr.length < 2) {return;}process(arr, 0, arr.length - 1);
}public static void process(int[] arr, int L, int R) {if (L >= R) return;swap(arr, L + (int) (Math.random() * (R - L + 1)), R); // 随机选一个数作为基准,放在最右侧int[] equalArea = netherlandsFlag(arr, L, R);process(arr, L, equalArea[0] - 1); // 小于区递归process(arr, equalArea[1] + 1, R); // 大于区递归
}// arr[L...R] 玩荷兰国旗问题的划分,以arr[R]做划分值,分为:小于区,等于区,大于区
public static int[] netherlandsFlag(int[] arr, int L, int R) {if (L > R) {return new int[] { -1, -1 };}if (L == R) {return new int[] { L, R };}int less = L - 1; // 小于区的右边界,L-1保持基准始终在最右侧,或者你可以用独立的变量记录它int more = R;     // 大于区的左边界int index = L;while (index < more) {if (arr[index] == arr[R]) {index++;} else if (arr[index] < arr[R]) {swap(arr, index++, ++less);} else {swap(arr, index, --more);}}swap(arr, more, R);return new int[] { less + 1, more };
}public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;
}

完整代码(带对数器)

package class03;public class Code03_PartitionAndQuickSort {public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}public static int partition(int[] arr, int L, int R) {if (L > R) {return -1;}if (L == R) {return L;}int lessEqual = L - 1;int index = L;while (index < R) {if (arr[index] <= arr[R]) {swap(arr, index, ++lessEqual);}index++;}swap(arr, ++lessEqual, R);return lessEqual;}// arr[L...R] 玩荷兰国旗问题的划分,以arr[R]做划分值//  <arr[R]  ==arr[R]  > arr[R]public static int[] netherlandsFlag(int[] arr, int L, int R) {if (L > R) {return new int[]{-1, -1};}if (L == R) {return new int[]{L, R};}int less = L - 1; // < 区 右边界int more = R;     // > 区 左边界int index = L;while (index < more) {if (arr[index] == arr[R]) {index++;} else if (arr[index] < arr[R]) {swap(arr, index++, ++less);} else { // >swap(arr, index, --more);}}swap(arr, more, R);return new int[]{less + 1, more};}public static void quickSort1(int[] arr) {if (arr == null || arr.length < 2) {return;}process1(arr, 0, arr.length - 1);}public static void process1(int[] arr, int L, int R) {if (L >= R) {return;}// L..R partition arr[R]  [   <=arr[R]   arr[R]    >arr[R]  ]int M = partition(arr, L, R);process1(arr, L, M - 1);process1(arr, M + 1, R);}public static void quickSort2(int[] arr) {if (arr == null || arr.length < 2) {return;}process2(arr, 0, arr.length - 1);}public static void process2(int[] arr, int L, int R) {if (L >= R) {return;}int[] equalArea = netherlandsFlag(arr, L, R);process2(arr, L, equalArea[0] - 1);process2(arr, equalArea[1] + 1, R);}public static void quickSort3(int[] arr) {if (arr == null || arr.length < 2) {return;}process3(arr, 0, arr.length - 1);}public static void process3(int[] arr, int L, int R) {if (L >= R) {return;}swap(arr, L + (int) (Math.random() * (R - L + 1)), R);int[] equalArea = netherlandsFlag(arr, L, R);process3(arr, L, equalArea[0] - 1);process3(arr, equalArea[1] + 1, R);}// for testpublic static int[] generateRandomArray(int maxSize, int maxValue) {int[] arr = new int[(int) ((maxSize + 1) * Math.random())];for (int i = 0; i < arr.length; i++) {arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());}return arr;}// for testpublic static int[] copyArray(int[] arr) {if (arr == null) {return null;}int[] res = new int[arr.length];for (int i = 0; i < arr.length; i++) {res[i] = arr[i];}return res;}// for testpublic static boolean isEqual(int[] arr1, int[] arr2) {if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {return false;}if (arr1 == null && arr2 == null) {return true;}if (arr1.length != arr2.length) {return false;}for (int i = 0; i < arr1.length; i++) {if (arr1[i] != arr2[i]) {return false;}}return true;}// for testpublic static void printArray(int[] arr) {if (arr == null) {return;}for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}// for testpublic static void main(String[] args) {int testTime = 500000;int maxSize = 100;int maxValue = 100;boolean succeed = true;for (int i = 0; i < testTime; i++) {int[] arr1 = generateRandomArray(maxSize, maxValue);int[] arr2 = copyArray(arr1);int[] arr3 = copyArray(arr1);quickSort1(arr1);quickSort2(arr2);quickSort3(arr3);if (!isEqual(arr1, arr2) || !isEqual(arr2, arr3)) {succeed = false;break;}}System.out.println(succeed ? "Nice!" : "Oops!");}
}

数据结构与算法(一):排序算法之 - 快速排序(详细步骤图解,附代码)相关推荐

  1. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...

  2. 数据结构排序算法实验报告_[数据结构与算法系列]排序算法(二)

    我的上一篇文章向大家介绍了排序算法中的冒泡排序.插入排序和选择排序.它们都是平均时间复杂度为 O(n^2) 的排序算法,同时还为大家讲解了什么是原地排序和什么是排序的稳定性.下图是这三种算法的比较,不 ...

  3. 数据结构与算法(三) 排序算法(代码示例)

    数据结构与算法三 排序算法 1. 选择排序 2. 插入排序 3. 冒泡排序 4. 归并排序 5. 快速排序 6. 希尔排序 7. 堆排序 总结 1. 选择排序 选择排序的基本原理: 对于未排序的一组记 ...

  4. 数据结构与算法之排序算法

    数据结构与算法之排序算法 排序算法的介绍 ​ 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程. 排序的分类 1)内部排序:指将需要处理的数据都加载到内部 ...

  5. 大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 21

    大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 211 第 ...

  6. 排序算法 快速排序【详细步骤图解】

    排序算法 快速排序[详细步骤图解] 快速排序 主要思想 图解 第一轮分割序列 第二轮分割序列 --- 左子序列 小结 第三轮分割序列 --- 右子序列 C++实现 总结 快速排序 给定一个序列:22 ...

  7. 【图解算法】排序算法——快速排序

    简介 首先还是得简单的介绍一下快速排序这个算法. 快速排序(Quicksort),又称划分交换排序(partition-exchange sort),一种排序算法,最早由东尼·霍尔提出.在平均状况下, ...

  8. python结构排序_Python数据结构(七)排序算法 上

    Python数据结构(七)排序算法 上 上回: 本文的重点不是代码,而是带着大家分析每一个排序算法背后的思想以及使用到的数据结构.很多时候不是我们想不出算法该如何去写,而是题目并没有指定特定的数据结构 ...

  9. 查找算法与排序算法之Python实现

    查找算法与排序算法 查找算法 顺序查找 二分查找 排序算法 冒泡排序 选择排序 简单选择排序 选择排序 插入排序 快速排序 堆排序 堆排序topk问题 归并排序 希尔排序 计数排序 桶排序 基数排序 ...

  10. 算法---比较排序算法

    在大批量的刷题之前,做好前期的准备工作,首先明白了时间复杂度和空间复杂度的计算方法,这个在我的上一篇博文里有提到,然后对经典排序算法做一个全面了解,2017.7.13,本文大部分内容引自http:// ...

最新文章

  1. modernizer的意义
  2. python不定参数的函数实现_python传入不定参数是什么
  3. 求助!C++ 实践之引入外部头文件失败
  4. ABAQUS2021界面改成中文
  5. windbg中ntsd使用用户态调试器链接到内核调试器的常用技巧
  6. AVOD-代码理解系列(四)
  7. C语言运行时检查失败#2 周围的堆栈已损坏。
  8. 即将首发 | 业界首个零售数字化创新白皮书,解锁全链路数字化致胜秘籍
  9. 英特尔的集显和Nvidia的独显切换(切换之后永久有效)
  10. zotero+坚果云
  11. 探索Java中empty()与isEmpty()的区别
  12. 最新TIM校园学校表白墙系统源码+UI挺不错
  13. 解决各种中文乱码的方法
  14. 页内嵌多媒体内容的完美实现
  15. 计算机丢失cryptui.dll黑屏,提示无法找到cryptui.dll文件
  16. element input=number 限制输入长度,输入数字的大小和禁止输入e
  17. 操作系统 - 1. 绪论
  18. 回首过去自学编程之路,开启新的篇章
  19. Acunetix 简介 为什么需要保护您的 Web 应用程序
  20. java楼盘管理系统_基于Java的楼盘销售管理系统的设计与实现

热门文章

  1. POJ - 2676 Sudoku(dfs)
  2. java io字符输出流_JAVA IO 字符输入流与输出流总结说明
  3. C++读图片——Mac下对于bmp文件读写读取过大的解决方案
  4. [HAOI2015][loj2127]按位或
  5. 来自看雪的手把手调试DebugPort清零
  6. 看完这篇文章,我奶奶都懂了https的原理
  7. 劫起|再谈Linux epoll惊群问题的原因和解决方案
  8. 简历上的“熟练掌握 RPC”,到底是个什么水平?
  9. Leetcode-Median of Two Sorted Arrays
  10. 如何给小白解释什么是编解码器