引子
最近有童鞋问我快排算法,为了一劳永逸,所以放一把"矢"。
快排的思想
总的来说,是“先二分,再归并”
二分:
有如下数组:
int[] data = { 9, -16, 30, 23, -30, -49, 25, 21, 30 };
- 取数组第一个元素 作为基准
data数组中基准为9
- 有两个指针 i 和 j,数组左边的指针i指向数组第二个元素,数组右边的指针j指向最后一个元素
初始状态:i指向数组第二个元素-16,j指向最后一个元素30
- 指针 j从右向左开始移动,指向的元素如果小于基准则停止,等待左边的指针i从左向右找到了大于基准的元素,然后将两个元素交换。
第一次移动: [9, -16, 30, 23, -30, -49, 25, 21, 30] j依次指向30,21,25都不成立,指向-49成立 i指向-16不成立,指向30成立 -49和30交换位置 [9, -16, -49, 23, -30, 30, 25, 21, 30]
- 重复步骤3,直到指针i和指针j相交
第二次移动: [9, -16, -49, 23, -30, 30, 25, 21, 30] j从30向左移动,指向-30成立 i从-49向右移动,指向23成立 -30和23交换位置 [9, -16, -49, -30, 23, 30, 25, 21, 30]
第三次移动:j向左移动与指针i相交,执行第5步
- 将相交位置的元素与基准进行交换,此时,基准左边的元素小于基准,基准右边的元素大于基准,完成了整个二分过程
[9, -16, -49, -30, 23, 30, 25, 21, 30] 基准9与指针i,j相交的元素-30进行交换 [-30, -16, -49, 9, 23, 30, 25, 21, 30]
归并
- 递归调用二分,基准之前为一个数组进行二分,基准之后为一个数组进行二分
[-30, -16, -49] 9 [23, 30, 25, 21, 30]
- 二分之后归并,归并之后二分。如此反复,直到数组无法分割,则完成排序
理论说完了,上代码实践一下:
//测试快排的main方法,爱看不看,我都不想贴
public static void main(String[] args) {
int[] data = { 9, -16, 30, 23, -30, -49, 25, 21, 30 };
System.out.println("排序之前:\n" + java.util.Arrays.toString(data));
quickSort(data);
System.out.println("排序之后:\n" + java.util.Arrays.toString(data));
}
//归并调用自己
public static void quickSort(int[] data) {
subSort(data, 0, data.length - 1);
}
//交换数组元素的方法,没什么好说的
private static void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
// 这是关键代码
private static void subSort(int[] data, int start, int end) {
if (start < end) {
int base = data[start];//基准
int low = start;//指针i
int high = end + 1;//指针j
while (true) {
//指针从左向右 移动
while (low < end && data[++low] - base <= 0);
System.out.println(data[low]);//查看i指针指向的元素
//指针从右向左 移动
while (high > start && data[--high] - base >= 0);
System.out.println(data[high]);//查看j指针指向的元素
// low<high 说明指针i和j并没有相交,相交break
if (low < high) {
swap(data, low, high);//指针i和指针j的元素相交
} else {
break;
}
}
swap(data, start, high);//将基准和两指针相交的元素交换
// 拆分后的两个数组分别递归调用
subSort(data, start, high - 1);
subSort(data, high + 1, end);
}
}
后记
一看就懂,一写就废,收藏吧