一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
我认为写算法类文章的几个行文要素:
- 专注核心概念,不做过多延伸
- 一遍也能看懂
- 应用!应用!应用! 总的来说就是不要说太多废话,也不要太惜字!
梳理快排的概念💎
一种将无需数组排列成有序数组的方式。
先从无序数组中找出一个基准数,然后遍历一遍数组,将小于基准数的元素放在基准数左边,大于的放基准数右边。这样的一次遍历就能够确定基准数在这个数组中的最终位置。(因为有序数组中基准数左边也是都小于基准数的元素,基准书右边都是大于基准数的元素)
然后将基准数右边形成的一半数组序列再定一个基准数,再次遍历,确定新基准数的位置。 旧基准数左边形成的一半数组序列也遍历一次,确定一个新基准数的位置。
这样一直往下分别遍历,就能最终确定所有数的位置。
必须记住的快排特点❤❤❤❤❤
- 因为每次遍历用到的方法都一样,所以肯定是递归的思想。
- 快排是不稳定的,也就是快排后的有序数组中,原来数据相同的元素之间次序可能会发生改变。
- 理想快排的时间复杂度是:
怎么写快排
1.搭框架
使用java语言,用到两个函数,一个main函数,一个专门用来快排的方法函数。
重点来写方法函数,起个名字叫QuickSortMethod(), 首先肯定得传递要排序的数组arr这个参数。
而且由于递归思想,我们这个函数要递归调用,所以要多出两个参数——所传入数组的上下标,用来确定我们要排序的是数组的哪一个部分。
先不写方法中具体排序方式,而是分析框架:
- 基准数?就用数组第一个元素。也就是i指针指向的元素
- 用什么遍历?定义两个指针变量i=0,j=arr.length-1,
- 怎么遍历?
- 先从后向前让每个元素值arr[j]与基准数arr[i]比较,不断的让j--,直到找到第一个小于基准的元素值arr[j],让基准arr[i]和arr[j]的数值交换。现在基准值到了arr[j]上。
- 再从前向后,从arr[i]开始找,不断的让i++,直到找到第一个大于基准arr[j]的元素值arr[i],两个数交换位置。现在基准值到了arr[i]
- 重复前两步
- 什么时候停止遍历?
- i不断增大,j不断减小,到i=j的时候,基准值的位置就确定在这里了。
- 怎么重启遍历
- 分别对基准数左右两半的数组序列调用快排方法QuickSortMethod()
忽略第三步里具体的遍历步骤(我们下面再细讲),大致的代码框架就是下面这样:
import java.util.Arrays;
public class QuickSort {
//主函数做测试
public static void main(String[] args) {
int[] arr = {5,7,10,48,3,16,56,20,70,32,90,100,1,88,4};
QuickSortMethod(arr,0,arr.length-1); //调用快排方法
System.out.println(Arrays.toString(arr)); //输出排序后的数组
}
//快速排序的方法,传递三个参数,数组名,数组开始下标,数组结束下标
private static void QuickSortMethod(int[] arr, int low, int high) {
//递归结束条件,就是当low>=high时,说明要排序的数组序列已经被细分到个体,可以结束递归了
if(low>=high){
return;
}
//定义两个移动数组下标的指针
int i = low;
int j = high;
//操作指针,这次循环是为了确定一个基准数的位置
while(i<j){
}
//当跳出循环,说明一次快排结束,需要对分成的两个数组部分分别进行快排
QuickSortMethod(arr,low,j-1);
QuickSortMethod(arr,j+1,high);
}
}
2.写具体方法
接下来,我们丰富while语句内的代码,必须注意这里的while语句就是为了不断的让i++,j--,直到i和j相等,说明我们找到了该次遍历的终点:基准数的正确位置!
要做的就是罗列出来的这段话:
- 怎么遍历?
- 先从后向前让每个元素值arr[j]与基准数arr[i]比较,不断的让j--,直到找到第一个小于基准的元素值arr[j],让基准arr[i]和arr[j]的数值交换。现在基准值到了arr[j]上。
- 再从前向后,从arr[i]开始找,不断的让i++,直到找到第一个大于基准arr[j]的元素值arr[i],两个数交换位置。现在基准值到了arr[i]
- 重复前两步
先确定,现在的基准数默认在arr[i]上,也就是数组的第一个元素上,我们从后往前,不断让j--,“不断”两字说明这里又用到一个循环语句,才能让j不断的--,直到发现arr[j]小于基准数时,停止,当然如果arr[j]一直都大于基准数,j就一直--到和i相等的时候,我们也要停止。
停止后就可以交换基准数和arr[i]所在的位置,也就是交换arr[j]和arr[i]的值。交换两数值这个动作很常见,所以就专门定义了一个函数,用到的时候直接调用了。
交换完,我们就可以从前往后遍历,让i不断++,停止i++的时候就是我们交换值的时候!
这个过程转换为代码就是这样:
while(i<j){
//从后往前比较,如果arr【j】< arr【i】,就交换两个的位置
while(i<j && arr[j]>arr[i]){
j--;
}
swap(arr,i,j);//用来交换arr[i]和arr[j]的值
//从前往后比较,如果arr【i】> arr【j】(基准),交换位置
while(i<j && arr[i]<arr[j]){
i++;
}
swap(arr,i,j);//用来交换arr[i]和arr[j]的值
}
运行主函数来测试一下:
练习题:
leetcode: 912. 排序数组 - 力扣(LeetCode) (leetcode-cn.com)