排序算法系列:快速排序算法JAVA版(靠谱、清晰、真实、可用、不罗嗦版)
在网上搜索算法的博客,发现一个比较悲剧的现象非常普遍:
- 原理讲不清,混乱
- 啰嗦
- 图和文对不上
- 不可用,甚至代码还出错
为了不误人子弟耽误时间,推荐看一些靠谱的资源,如【啊哈!算法】系列:
https://www.cnblogs.com/ahalei/p/3568434.html
他是C语言实现,其实都是一样的。
我总结一个清晰不罗嗦版:
原理:
快速排序使用分而治之策略。下面描述递归步骤:
选择一个pivot支点值(在啊哈算法中叫“基准值”)。我们将中间元素的值作为支点值,但是它也可以是任何值,甚至它可以不存在于数组中。
第一次排序:
- 小于支点值的所有元素都到支点值的左侧
- 而大于支点值的所有元素都到支点值的右侧
- 与支点值相等的值保留。
递归,再次以支点两侧排序:对两部分进行排序,将快速排序算法递归地应用到左右部分。数组可以以不相等数量的部分划分。
算法要点:
- 有两个索引i和j,在算法的第一次排序,i 指向数组中的第一个元素,j 指向最后一个元素。
- i向前移动,直到找到一个值大于或等于支点值的元素。
- 索引j向后移动,直到找到一个值小于或等于支点值的元素。
- 如果i小于j,则它们被交换,然后进入下一个位置(i + 1),j进到前一个(j - 1)。
- 当大于j时,算法停止。
第一次排序的说明:
在第一轮排序之后,会进入左右的递归。依次类推。
复杂度分析
排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 | 复杂性 | ||
平均情况 | 最坏情况 | 最好情况 | ||||
快速排序 | O(nlog2n) | O(n2) | O(nlog2n) | O(log2n) | 不稳定 | 较复杂 |
用JAVA实现(真实可用):
package Sort; public class QuickSort { public static void main(String[] args) { int arr[] = {1, 12, 5, 26, 7, 14, 3, 7, 2};
int n = arr.length; QuickSort ob = new QuickSort();
ob.quickSort(arr, 0, n-1);
//ob.sort(arr, 0, n-1); System.out.println("快速排序结果:");
printArray(arr);
} int partition(int arr[], int left, int right){ int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
System.out.println("pivot="+pivot+"; left="+left+"; right="+right); while (i <= j) { while (arr[i] < pivot){
System.out.println("跳过,i="+i+"; arr[i]="+arr[i]+", pivot="+pivot);
i++;
} while (arr[j] > pivot){
System.out.println("跳过,j="+j+"; arr[j]="+arr[j]+", pivot="+pivot);
j--;
} if (i <= j) {
System.out.println("交换前,i="+i+", j="+j+"; arr[i]="+arr[i]+", arr[j]="+arr[j]); tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp; System.out.println("交换后,i="+i+", j="+j+"; arr[i]="+arr[i]+", arr[j]="+arr[j]);
System.out.println("---"); i++;
j--; }
}; return i;
} void quickSort(int arr[], int left, int right) { int index = partition(arr, left, right);
if (left < index - 1){
System.out.println("递归 左侧,left="+left+", index="+index);
quickSort(arr, left, index - 1);
} if (index < right){
System.out.println("递归右侧,right="+right+", index="+index);
quickSort(arr, index, right);
}
} static void printArray(int arr[])
{
int n = arr.length;
for (int i=0; i<n; ++i)
System.out.print(arr[i]+" ");
System.out.println();
} //另一种简洁写法
int partition1(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low-1);
for (int j=low; j<high; j++)
{ if (arr[j] <= pivot)
{
i++; int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp; }
} int temp = arr[i+1];
arr[i+1] = arr[high];
arr[high] = temp; return i+1;
} void sort(int arr[], int low, int high)
{
if (low < high)
{
int pi = partition1(arr, low, high); sort(arr, low, pi-1);
sort(arr, pi+1, high);
}
}
}
调试信息:
pivot=7; left=0; right=8
跳过,i=0; arr[i]=1, pivot=7
交换前,i=1, j=8; arr[i]=12, arr[j]=2
交换后,i=1, j=8; arr[i]=2, arr[j]=12
---
跳过,i=2; arr[i]=5, pivot=7
交换前,i=3, j=7; arr[i]=26, arr[j]=7
交换后,i=3, j=7; arr[i]=7, arr[j]=26
---
交换前,i=4, j=6; arr[i]=7, arr[j]=3
交换后,i=4, j=6; arr[i]=3, arr[j]=7
---
跳过,j=5; arr[j]=14, pivot=7
递归 左侧,left=0, index=5
pivot=5; left=0; right=4
跳过,i=0; arr[i]=1, pivot=5
跳过,i=1; arr[i]=2, pivot=5
交换前,i=2, j=4; arr[i]=5, arr[j]=3
交换后,i=2, j=4; arr[i]=3, arr[j]=5
---
跳过,j=3; arr[j]=7, pivot=5
递归 左侧,left=0, index=3
pivot=2; left=0; right=2
跳过,i=0; arr[i]=1, pivot=2
跳过,j=2; arr[j]=3, pivot=2
交换前,i=1, j=1; arr[i]=2, arr[j]=2
交换后,i=1, j=1; arr[i]=2, arr[j]=2
---
递归 左侧,left=0, index=2
pivot=1; left=0; right=1
跳过,j=1; arr[j]=2, pivot=1
交换前,i=0, j=0; arr[i]=1, arr[j]=1
交换后,i=0, j=0; arr[i]=1, arr[j]=1
---
递归右侧,right=4, index=3
pivot=7; left=3; right=4
交换前,i=3, j=4; arr[i]=7, arr[j]=5
交换后,i=3, j=4; arr[i]=5, arr[j]=7
---
递归右侧,right=8, index=5
pivot=7; left=5; right=8
跳过,j=8; arr[j]=12, pivot=7
跳过,j=7; arr[j]=26, pivot=7
交换前,i=5, j=6; arr[i]=14, arr[j]=7
交换后,i=5, j=6; arr[i]=7, arr[j]=14
---
递归右侧,right=8, index=6
pivot=26; left=6; right=8
跳过,i=6; arr[i]=14, pivot=26
交换前,i=7, j=8; arr[i]=26, arr[j]=12
交换后,i=7, j=8; arr[i]=12, arr[j]=26
---
递归 左侧,left=6, index=8
pivot=14; left=6; right=7
交换前,i=6, j=7; arr[i]=14, arr[j]=12
交换后,i=6, j=7; arr[i]=12, arr[j]=14
---
快速排序
1 2 3 5 7 7 12 14 26
排序算法系列:快速排序算法JAVA版(靠谱、清晰、真实、可用、不罗嗦版)的更多相关文章
- JAVA算法系列 快速排序
java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...
- 【排序算法】快速排序算法 Java实现
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序.它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod). 基本思想 先从数组中找出一个数作为基 ...
- java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述
算法是在有限步骤内求解某一问题所使用的一组定义明确的规则.通俗点说,就是计算机解题的过程.在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法.前者是推理实现的算法,后者是操作实现的算法. ...
- c#冒泡排序算法和快速排序算法
依次比较相邻的两个数,将小数放在前面,大数放在后面. 第1趟: 首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放 ...
- Java实现 蓝桥杯 算法提高 快速排序
试题 算法提高 快速排序 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 用递归来实现快速排序(quick sort)算法.快速排序算法的基本思路是:假设要对一个数组a进行排序,且a ...
- 快速排序算法(C)
sort快排函数的基本版,效率n*logn,快排的完全版就是在递归之中夹杂对序列的预判断,最优的选择排序方法,快速排序算法只是其中之一. 简单的说明一下快速排序的思想,对于一个数列,首先选择一个基数( ...
- 常用算法1 - 快速排序 & 二分查找
1. 二分查找法: 二分查找法是对一组有序的数字中进行查找,传递相应的数据,进行比较查找到与原数据相同的数据,查找到了返回对应的数组下标,没有找到返回-1. 二分查找法要求数据为一组有序的序列(大到小 ...
- c++ 图解快速排序算法
第一.算法描述 快速排序由C. A. R. Hoare在1962年提出,该算法是目前实践中使用最频繁,实用高效的最好排序算法, 快速排序算法是采用分治思想的算法,算法分三个步骤 从数组中抽出一个元素作 ...
- Algorithms - Quicksort - 快速排序算法
相关概念 快速排序法 Quicksort 也是一个分治思想的算法. 对一个子数组 A[p: r] 进行快速排序的三步分治过程: 1, 分解. 将数组 A[p : r] 被划分为两个子数组(可能为空) ...
随机推荐
- Halcom学习笔记1——Halcon知识点
文件: 1.浏览HDevelop示例程序 2.程序另存在:Ctrl+Shift+S 3.导出:Ctrl+Shift+O X 编辑: 1.快捷键: F3 激活 F4 注销 重复查找:C ...
- mui页面传值
以下代码全部在script标签内 一.通过mui.openWindow()打开新页面(若目标页面为已预加载成功的页面,则在openWindow方法中传递的extras参数无效): mui.openWi ...
- flash/flex builder在IE中stage.stageWidth始终为0的解决办法
这应该是IE的bug,解决办法: 原作者:菩提树下的杨过出处:http://yjmyzz.cnblogs.com stage.align=StageAlign.TOP_LEFT; stage.scal ...
- “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (下)
在前一部分的最后,我们给出了一个寻路的示例,在大多数情况下,运行还算良好,但是有一个小问题,如下图: 很明显,障碍物已经把路堵死了,但是小球仍然穿过对角线跑了出来! 问题在哪里:我们先回顾一下ASta ...
- 【笔记】计算机原理,网络,Linux操作系统
一,计算机原理 1,化繁为简的思想,产生二进制,产生把所有计算归结为加法运算 二,网络 1,分层思想,产生ISO七层协议,商用了TCP/IP的五层协议 三,Linux操作系统 1,分层思想,硬件-&g ...
- 7za命令报错Error: xxx is not supported archive
问题: 执行7za命令时报错:Error: xxx is not supported archive 原因: 当前7za版本过低 直接执行7za可以看到当前版本: 7-Zip (A) [64] ...
- oracle数据库分页总结
/* BEGIN CREATE TABLE APPUSER(IDS NUMBER(8), USERNAME VARCHAR2(20), PASSWORD VARCHAR2(20), CTIME DAT ...
- 亿级 ELK 日志平台构建部署实践
本篇主要讲工作中的真实经历,我们怎么打造亿级日志平台,同时手把手教大家建立起这样一套亿级 ELK 系统.日志平台具体发展历程可以参考上篇 「从 ELK 到 EFK 演进」 废话不多说,老司机们座好了, ...
- js的一些总结
函数 函数是一等公民 函数可以有属性,并且能连接到它的构造方法 函数可以像一个变量一样存在内存中 函数可以当做参数传给其他函数 函数可以返回其他函数 加法操作表 Number + Number -&g ...
- powershell获取windows子文件夹的大小
$startFolder = "E:\Migration\" $colItems = (Get-ChildItem $startFolder | Where-Object {$_. ...