快速排序(经典)

实现1参考了博客,快排讲得很清晰,看完思路代码容易自己写出来。(开头给出的各类排序算法的总结图真的很好!)

实现2参考了atguigu视频,代码部分稍难理解,if条件判断过多,重要的是,代码不美观。

另外还有一篇博客提到了原地排序非原地排序的概念,涉及到空间复杂度,有空了解一下。

思路分析

快速排序是对冒泡排序的一种改进。有分治[^5]思想

基本思想为:

通过一趟排序将待排序元素分割成独立的两个部分,其中一部分的所有数据要比另一部分的所有数据要小,然后再按此方法对这两部分分别进行快速排序,整个排序过程可以递归进行,以此使得所有数据变成有序序列。

但是光凭这个基本思想还没法写出代码

代码实现

测试数据大小 花费时间(单位:毫秒)
10000 1
50000 6
80000 9
140000 12
500000 37
900000 64

实现1

个人感觉这种好理解

QuickSort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.yukinoshita.algorithm.sort;

import java.util.Arrays;
import java.util.Random;

public class QuickSort {
public static void main(String args[]) {
int[] arr = {3, 9, -1, 10, -2};

System.out.println("排序前:" + Arrays.toString(arr));
quickSort(arr, 0, arr.length - 1);
System.out.println("排序后:" + Arrays.toString(arr));

// 测试算法性能
testPerformance();

}

public static void quickSort(int[] arr, int start, int end) {
if (start < end) {
int l = start;
int r = end;
int base = arr[l];
while (l < r) {
//先从右向左,找到第一个小于base的数,将其移动到l的位置上
while (l < r && arr[r] >= base) {
r--;
}
arr[l] = arr[r];

//再从左向右,找到第一个大于base的数,将其移动到r的位置上
while (l < r && arr[l] <= base) {
l++;
}
arr[r] = arr[l];
}
//退出时,l == r
arr[l] = base;

//再分别对左、右的数组进行快排
quickSort(arr, start, l - 1);
quickSort(arr, r + 1, end);
}
}

// 测试算法性能的方法
public static void testPerformance() {
int size = 140000; // 数组大小
int[] arr = new int[size];
Random random = new Random();

// 生成无序数组
for (int i = 0; i < size; i++) {
arr[i] = random.nextInt(100000); // 随机数范围可以根据需要调整
}

long startTime = System.currentTimeMillis(); // 记录开始时间
quickSort(arr, 0, arr.length - 1); // 排序
long endTime = System.currentTimeMillis(); // 记录结束时间

System.out.println("排序大小: " + size);
System.out.println("排序时间: " + (endTime - startTime) + " 毫秒");
}
}

实现1’

QuickSort

仅对上述quickSort部分作了一定修改如下,只是形式不同罢了

展示核心部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void quickSort(int[] arr, int start, int end) {
if (start < end) {
int pos = partition(arr,start,end);
//再分别对左、右的数组进行快排
quickSort(arr, start, pos-1);
quickSort(arr, pos + 1, end);
}
}

public static int partition(int[] arr, int left, int right) {
int l = left;
int r = right;
int pivot = arr[l];
while(l<r){
while(l<r && arr[r]>=pivot){
r--;
}
arr[l] = arr[r];
while(l<r && arr[l]<=pivot){
l++;
}
arr[r] = arr[l];
}
return l;
}

实现2

QuickSort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.yukinoshita.algorithm.sort;

import java.util.Arrays;
import java.util.Random;

public class QuickSort {
public static void main(String args[]) {
int[] arr = {3, 9, -1, 10, -2};

System.out.println("排序前:" + Arrays.toString(arr));
quickSort(arr, 0, arr.length - 1);
System.out.println("排序后:" + Arrays.toString(arr));

// 测试算法性能
testPerformance();

}

public static void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int pivot = arr[(l + r) / 2];//把中间元素定为基准
int temp = 0;//临时的交换变量

while (l < r) {
while (arr[l] < pivot) {
l++;
}
while (arr[r] > pivot) {
r--;
}

if (l >= r) {
break;
}


temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;

//如果交换完后,arr[l]==pivot,则需将 r-- (试想一下arr[l]和arr[r]同时==pivot的情况,会无限循环)
if (arr[l] == pivot) {
r--;
}
if (arr[r] == pivot) {
l++;
}
}
//如果l==r必须l++,r--
if (l == r) {
l++;
r--;
}

//向左递归
if (left < r) {
quickSort(arr, left, r);
}

//向右递归
if (right > l) {
quickSort(arr, l, right);
}
}

// 测试算法性能的方法
public static void testPerformance() {
int size = 140000; // 数组大小
int[] arr = new int[size];
Random random = new Random();

// 生成无序数组
for (int i = 0; i < size; i++) {
arr[i] = random.nextInt(100000); // 随机数范围可以根据需要调整
}

long startTime = System.currentTimeMillis(); // 记录开始时间
quickSort(arr, 0, arr.length - 1); // 排序
long endTime = System.currentTimeMillis(); // 记录结束时间

System.out.println("排序大小: " + size);
System.out.println("排序时间: " + (endTime - startTime) + " 毫秒");
}
}