0%

algorithm-sort

选择类排序

选择排序

简单选择排序

SelectSort1.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package dsa.algorithm.da101_sort.st11;

import java.util.Arrays;

public class SelectSort1 {

public static void sort(int[] array) {
int len = array.length;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是未排序部分的范围:[i, len)
for (int i = 0; i < len - 1; i++) {

int min = i;
for (int j = i + 1; j < len; j++) {
if (array[j] < array[min]) {
min = j;
}
}

swap(array, min, i);
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}

}

双端选择排序

SelectDualSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package dsa.algorithm.da101_sort.st11;

import java.util.Arrays;

public class SelectDualSort {

public static void sort(int[] array) {
int len = array.length;

int L = 0, R = len - 1;
while (L < R) {
int min = L;
int max = R;
for (int i = L; i <= R; i++) {
if (array[i] < array[min]) {
min = i;
}

if (array[i] > array[max]) {
max = i;
}
}

// max等于L时先将L换位后的位置记下来
if (max == L) {
max = min;
}

swap(array, L, min);
swap(array, R, max);

// // min等于R时先将R换位后的位置记下来
// if (min == R) {
// min = max;
// }

// swap(array, R, max);
// swap(array, L, min);

L++;
R--;
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

冒泡排序

冒泡排序

BubbleSort1.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package dsa.algorithm.da101_sort.st13;

import java.util.Arrays;

public class BubbleSort1 {

public static void sort(int[] array) {
int len = array.length;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是未排序部分的范围:[0, len - i)
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1; j++) {
// 比自己后面的元素大,则交换位置,排到后面去
if (array[j] > array[j + 1]) {
swap(array, j, j + 1);
}
}
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

冒泡排序(带选择演示)

BubbleSelectSort1.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package dsa.algorithm.da101_sort.st13;

import java.util.Arrays;

public class BubbleSelectSort1 {

public static void sort(int[] array) {
int len = array.length;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是未排序部分的范围:[0, len - i)
for (int i = 0; i < len - 1; i++) {

int max = -1;
for (int j = 0; j < len - i - 1; j++) {
// 比自己后面的元素大,则交换位置,排到后面去
if (array[j] > array[j + 1]) {
swap(array, j, j + 1);

// 当前条件中较大值的下标交换前是j,交换后则是j + 1
max = j + 1;
} else {
// 当前条件中较大值的下标就是j + 1
max = j + 1;
}
}

// 无意义的操作,因为前面交换操作的影响使得max = (len - i) - 1
// 即选择出最大值并交换到未排序部分的尾部这个操作已经通过前面的交换操作完成了的
// 所以max指针也是多余的(去掉max指针相关的操作就是真正的冒泡排序了)
swap(array, max, (len - i) - 1);
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

冒泡排序(带标记优化)

BubbleFlagSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package dsa.algorithm.da101_sort.st13;

import java.util.Arrays;

public class BubbleFlagSort {

public static void sort(int[] array) {
int len = array.length;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是未排序部分的范围:[0, len - i)
for (int i = 0; i < len - 1; i++) {
boolean flag = true;

for (int j = 0; j + 1 < len - i; j++) {
// 比自己后面的元素大,则交换位置,排到后面去
if (array[j] > array[j + 1]) {
swap(array, j, j + 1);

flag = false;
}
}

// 没有发生过交换,代表已经有序了
if (flag) {
break;
}
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

冒泡排序(带边界优化)

BubbleBorderSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package dsa.algorithm.da101_sort.st13;

import java.util.Arrays;

public class BubbleBorderSort {

public static void sort(int[] array) {
int len = array.length;

int border = len;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是未排序部分的范围:[0, len - i)
for (int i = 0; i < len - 1; i++) {
int last = -1;

// 从border开始(包含border)往后都是排好序的了
for (int j = 0; j + 1 < border; j++) {
// 比自己后面的元素大,则交换位置,排到后面去
if (array[j] > array[j + 1]) {
swap(array, j, j + 1);

last = j;
}
}

border = last + 1;

// 用last < 0来代替flag
// flag为true时代表没有发生过交换,说明已经有序了
if (last < 0) {
break;
}
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

冒泡排序(带双端优化)

BubbleDualSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package dsa.algorithm.da101_sort.st13;

import java.util.Arrays;

public class BubbleDualSort {

public static void sort(int[] array) {
int len = array.length;

int L = 0, R = len - 1;
while (L < R) {
for (int i = L; i < R; i++) {
if (array[i] > array[i + 1]) {
swap(array, i, i + 1);
}
}
R--;

for (int i = R; i > L; i--) {
if (array[i] < array[i - 1]) {
swap(array, i, i - 1);
}
}
L++;
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

堆排序

HeapSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package dsa.algorithm.da101_sort.st15;

import java.util.Arrays;

public class HeapSort {

public static void sort(int[] array) {
heapSort1(array);
// heapSort2(array);
}

public static void heapSort1(int[] array) {
genHeapByShiftUp(array);

int len = array.length;
while (len > 1) {
swap(array, 0, --len);
shiftDown(array, 0, len);
}
}

public static void heapSort2(int[] array) {
genHeapByShiftDown(array);

int len = array.length;
while (len > 1) {
swap(array, 0, --len);
shiftDown(array, 0, len);
}
}

private static void genHeapByShiftUp(int[] arr) {
// 从上往下处理时新结点是位于堆的底部,所以新结点需要的操作是向上调整
// 因为不包含父结点的结点的不需要向上调整,所以第一个需要调整的结点是第一个包含父结点的结点
// 所以第一个需要调整的结点的下标为i=1
int len = arr.length;
for (int i = 1; i < len; i++) {
shiftUp(arr, i);
}
}

private static void genHeapByShiftDown(int[] arr) {
// 从下往上处理时新结点是位于堆的顶部,所以新结点需要的操作是向下调整
// 因为不包含子结点的结点的不需要向下调整,所以最后一个需要调整的结点是最后一个包含子结点的结点
// 所以最后一个需要调整的结点的下标为i=((len - 1) - 1)) / 2 = (len - 2) / 2
int len = arr.length;
for (int i = (len - 2) / 2; i >= 0; i--) {
shiftDown(arr, i, len);
}
}

public static void shiftUp(int[] arr, int i) {
int j = (i - 1) / 2;
while (j >= 0) {
if (arr[i] > arr[j]) {
// 大顶堆,谁大谁在上
swap(arr, i, j);

i = j;
j = (i - 1) / 2;
} else {
break;
}
}
}

public static void shiftDown(int[] arr, int i, int heapSize) {
int j = 2 * i + 1;
while (j < heapSize) {
// 大顶堆,选择左右结点中较大的那一个的下标
j = j + 1 < heapSize && arr[j + 1] > arr[j] ? j + 1 : j;
if (arr[j] > arr[i]) {
// 大顶堆,谁大谁在上
swap(arr, j, i);

i = j;
j = 2 * i + 1;
} else {
break;
}
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

插入类排序

直接插入排序

InsertSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package dsa.algorithm.da101_sort.st31;

import java.util.Arrays;

public class InsertSort {

public static void sort(int[] array) {
int len = array.length;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是已排序部分的范围:[0, i + 1)
for (int i = 0; i < len - 1; i++) {

int v = array[i + 1];

int j = i; // j + 1 < len
// 当前元素比插入元素大,则后退一步,让出位置
while (j >= 0 && array[j] > v) {
array[j + 1] = array[j];
j--;
}

// 插入元素排到当前元素(不大于插入元素)的后面
array[j + 1] = v;
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

二分插入排序

InsertSearchSort3.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package dsa.algorithm.da101_sort.st33;

import java.util.Arrays;

public class InsertSearchSort3 {

public static void sort(int[] array) {
int len = array.length;

// 外层的边界是循环次数的范围:[0,len - 1)
// 内层的边界是已排序部分的范围:[0, i + 1)
for (int i = 0; i < len - 1; i++) {

int v = array[i + 1];
int pos = search(array, 0, i, v);

int j = i; // j + 1 < len
while (j >= pos) {
array[j + 1] = array[j];
j--;
}

// 插入元素排到当前元素(不大于插入元素)的后面
array[pos] = v;
}
}

private static int search(int[] array, int L, int R, int v) {
while (L <= R) {
int m = (L + R) / 2;
if (v < array[m]) {
// 插入元素小于当前元素,则插入位置所在的区间在当前元素的位置或者当前元素的左边,即区间的右边界R = m
// R = m; // 如果R = m的话,当m = L = R时会死循环
R = m - 1;
} else {
// 插入元素大于等于当前元素,则插入位置所在的区间在当前元素的右边,即区间的左边界L = m + 1
L = m + 1;
}
}

// 当区间里面只剩一个元素时,即m = L = R时
// 插入元素小于当前元素,则插入位置为m,此时L = m,R = m - 1
// 插入元素大于等于当前元素,则插入位置为m + 1,此时L = m + 1,R = m
// 综上两种情况,则插入位置为L
return L;
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

希尔排序

ShellSort2.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package dsa.algorithm.da101_sort.st35;

import java.util.Arrays;

public class ShellSort2 {

public static void sort(int[] array) {
int len = array.length;

int gap = len / 2;
while (gap > 0) {
// gap既是分组步长,也是分组数量
// 只对第一个分组排序
for (int i = 0; i + gap < len; i = i + gap) {

int v = array[i + gap];

int j = i; // j + gap < len
// 比插入元素大,则后退一步,让出位置
while (j >= 0 && array[j] > v) {
array[j + gap] = array[j];
j = j - gap;
}

// 插入元素排到当前元素(不大于插入元素)的后面
array[j + gap] = v;
}

gap = gap / 2;
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

分治类排序

快速排序

快速排序(三分法,每次处理一个)

QuickSort11.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package dsa.algorithm.da101_sort.st51;

import java.util.Arrays;

public class QuickSort11 {

public static void sort(int[] array) {
quickSort(array, 0, array.length - 1);
}

public static void quickSort(int[] array, int L, int R) {
if (L >= R) {
return;
}

int p = partition(array, L, R);

quickSort(array, L, p - 1);
quickSort(array, p + 1, R);
}

private static int partition(int[] array, int L, int R) {
// 分割成3个部分,左边小于等于分割数,中间只有分割数一个元素,右边大于等于分割数
// 分割数选L位置的数时先从右边开始查找
// 分割数选R位置的数时先从左边开始查找

int i = L;
int j = R;

while (i < j) {
// 此时j位置的数是分割数
// 从左向右找到第一个大于分割数的元素
while (i < j && array[i] <= array[j])
i++;

if (i < j) {
// 通过交换操作将大于分割数的放在分割数的右边
// 交换后i位置的数是分割数
swap(array, i, j--);
}

// 此时i位置的数是分割数
// 从右向左找到第一个小于分割数的元素
while (i < j && array[j] >= array[i])
j--;

if (i < j) {
// 通过交换操作将小于分割数的放在分割数的左边
// 交换后j位置的数是分割数
swap(array, i++, j);
}
}

// 获取分割数的位置,此时i = j,可以任选一个
int p = i;

return p;
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

快速排序(三分法,每次处理两个)

QuickSort21.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package dsa.algorithm.da101_sort.st51;

import java.util.Arrays;

public class QuickSort21 {

public static void sort(int[] array) {
quickSort(array, 0, array.length - 1);
}

public static void quickSort(int[] array, int L, int R) {
if (L >= R) {
return;
}

int p = partition(array, L, R);

quickSort(array, L, p - 1);
quickSort(array, p + 1, R);
}

private static int partition(int[] array, int L, int R) {
// 分割成3个部分,左边小于等于分割数,中间只有分割数一个元素,右边大于等于分割数
// 分割数可以选任意位置的数

int i = L;
int j = R;

int p = (L + R) / 2;
int v = array[p];

while (i <= j) {
// 向右找到第一个大于分割数的元素
while (i <= j && array[i] <= v)
i++;

// 向左找到第一个小于分割数的元素
while (i <= j && array[j] >= v)
j--;

if (i <= j) {
// 通过交换操作将大于分割数的放在分割数的右边
// 通过交换操作将小于分割数的放在分割数的左边
// i = j 时是自我交换,不影响结果
swap(array, i++, j--);
}
}

// 循环结束后i左边(不包含)的都小于等于分割数
// 循环结束后j右边(不包含)的都大于等于分割数
// 循环结束后i - j = 1 或者 i - j = 2

int m;
if (i > R) {
// 因为循环结束后i左边(不包含)的都小于等于分割数
// 所以只分为了一个区间且里面的数都小于等于分割数
// 即分割数就是最大值

// 分割点选择区间的尾部
m = R;
} else if (j < L) {
// 循环结束后j右边(不包含)的都大于等于分割数
// 所以只分为了一个区间且里面的数都大于等于分割数
// 即分割数就是最小值

// 分割点选择区间的头部
m = L;
} else {
// L <= j < i <= R
if (p < i) {
// 分割点选择左区间的尾部
m = i - 1;
} else if (p > j) {
// 分割点选择右区间的头部
m = j + 1;
} else {
// i <= p <= j,因为i > j,所以不存在这种情况
m = -1;
}
}

if (m != p) {
swap(array, p, m);
p = m;
}

return p;
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

快速排序(二分法,每次处理两个)

QuickSort33.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package dsa.algorithm.da101_sort.st51;

import java.util.Arrays;

public class QuickSort33 {

public static void sort(int[] array) {
quickSort(array, 0, array.length - 1);
}

public static void quickSort(int[] array, int L, int R) {
if (L >= R) {
return;
}

// 分割成2个部分,左边小于等于分割数,右边大于等于分割数
// 分割数可以选任意位置的数

int i = L;
int j = R;

int p = (L + R) / 2;
int v = array[p];

while (i <= j) {
// 向右找到第一个大于等于分割数的元素
// 等于时也要交换是为了至少交换一次来让指针i和j都至少移动一次
// 从而能够分成两部分而不是一部分来避免重复递归(参考上面的quickSort1方法)
while (i <= j && array[i] < v)
i++;

// 向左找到第一个小于等于分割数的元素
// 等于时也要交换是为了至少交换一次来让指针i和j都至少移动一次
// 从而能够分成两部分而不是一部分来避免重复递归(参考上面的quickSort1方法)
while (i <= j && array[j] > v)
j--;

if (i <= j) {
// 通过交换操作将大于等于分割数的放在分割数的右边
// 通过交换操作将小于等于分割数的放在分割数的左边
// i = j 时是自我交换,不影响结果
swap(array, i++, j--);
}
}

// i位置左边的都小于等于分割数
// j位置右边的都大于等于分割数
// 结束时 i - j = 1 或者 i - j = 2
// --- 证明1 ---
// i - j = 1时,即i = j + 1 或 i - 1 = j
// 则左部分的右边界为 i - 1 = i - (i - j) = j
// 则右部分的左边界为 j + 1 = j + (i - j) = i
// --- 证明2 ---
// i - j = 2时,即i - 1 = j + 1
// 令 k = i - 1 = j + 1
// 因为i位置左边的都小于等于分割数,且k = i - 1小于i
// 所以k位置的数小于等于分割数
// 因为j位置右边的都大于等于分割数,则k = j + 1大于j
// 所以k位置的数大于等于分割数
// 由上可知k位置的数小于等于分割数且k位置的数大于等于分割数
// 所以k位置的数只能等于分割数
// 因此分割时可以不需要包含k位置的数(备注:k = i - 1 = j + 1)
// 则左部分的右边界为 i - 2 = i - (i - j) = j
// 则右部分的左边界为 j + 2 = j + (i - j) = i
// --- 总结 ---
// 综上所述,左部分的右边界为j,右部分的左边界为i

quickSort(array, L, j);
quickSort(array, i, R);
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

归并排序

归并排序(每次归并一个)

MergeSort11.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package dsa.algorithm.da101_sort.st53;

import java.util.Arrays;

public class MergeSort11 {

public static void sort(int[] array) {
mergeSort(array, 0, array.length - 1);
}

private static void mergeSort(int[] array, int L, int R) {
if (L >= R) {
return;
}

int M = L + (R - L) / 2;
mergeSort(array, L, M);
mergeSort(array, M + 1, R);

merge(array, L, M, R);
}

// 单层循环 + 正向合并
private static void merge(int[] array, int L, int M, int R) {
int c = R - L + 1;
int[] tmp = new int[c];
int i = L;
int j = M + 1;
int e1 = M;
int e2 = R;
int k = 0;

while (i <= e1 && j <= e2) {
if (array[i] <= array[j]) {
tmp[k++] = array[i++];
} else {
tmp[k++] = array[j++];
}
}

// 根据上面循环的结束条件可知两部分都有剩余数据时不会退出
// 即退出时最多只可能有一个部分还有剩余数据
// 所以下面的两个循环最多只有一个会生效而不必担心剩余数据追加后会导致数组乱序
while (i <= e1)
tmp[k++] = array[i++];
while (j <= e2)
tmp[k++] = array[j++];

for (int t = 0; t < c; t++) {
array[L + t] = tmp[t];
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

归并排序(每次归并多个)

MergeSort21.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package dsa.algorithm.da101_sort.st53;

import java.util.Arrays;

public class MergeSort21 {

public static void sort(int[] array) {
mergeSort(array, 0, array.length - 1);
}

private static void mergeSort(int[] array, int L, int R) {
if (L >= R) {
return;
}

int M = L + (R - L) / 2;
mergeSort(array, L, M);
mergeSort(array, M + 1, R);

merge(array, L, M, R);
}

// 双层循环 + 正向合并
private static void merge(int[] array, int L, int M, int R) {
int c = R - L + 1;
int[] tmp = new int[c];
int i = L;
int j = M + 1;
int e1 = M;
int e2 = R;
int k = 0;

while (i <= e1 && j <= e2) {
while (i <= e1 && j <= e2 && array[i] <= array[j]) {
tmp[k++] = array[i++];
}

while (i <= e1 && j <= e2 && array[j] <= array[i]) {
tmp[k++] = array[j++];
}
}

// 根据上面循环的结束条件可知两部分都有剩余数据时不会退出
// 即退出时最多只可能有一个部分还有剩余数据
// 所以下面的两个循环最多只有一个会生效而不必担心剩余数据追加后会导致数组乱序
while (i <= e1)
tmp[k++] = array[i++];
while (j <= e2)
tmp[k++] = array[j++];

for (int t = 0; t < c; t++) {
array[L + t] = tmp[t];
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

桶排序

BucketSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package dsa.algorithm.da101_sort.st55;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BucketSort {

public static void sort(int[] array) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < array.length; i++) {
int v = array[i];
if (v < min) {
min = v;
}
if (v > max) {
max = v;
}
}
float dis = max - min + 1;

int bucketCount = 6;// 桶数量
List<List<Integer>> lists = new ArrayList<>();
for (int i = 0; i < bucketCount; i++) {
lists.add(new ArrayList<>());
}

for (int i = 0; i < array.length; i++) {
int v = array[i];
int bucketIndex = (int) ((v - min) / dis * bucketCount);
lists.get(bucketIndex).add(v);
}

int k = 0;
for (List<Integer> list : lists) {
list.sort(null);
for (Integer v : list) {
array[k++] = v;
}
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

计数排序

CountSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package dsa.algorithm.da101_sort.st71;

import java.util.Arrays;

public class CountSort {

public static void sort(int[] array) {
int len = array.length;

int min = array[0];
int max = array[0];
for (int i = 1; i < len; i++) {
if (array[i] < min) {
min = array[i];
}

if (array[i] > max) {
max = array[i];
}
}

// 修正数组的数据到正数(包含0)的区间
// 如果最小值是负数,可以解决负数不能做下标的问题
// 如果最小值是正数,可以减少统计数组的空间
int offset = max - min;
for (int i = 0; i < len; i++) {
array[i] = array[i] + offset;
}
// min = min + offset;
max = max + offset;

int count[] = new int[max + 1];

// 计算某个值的数量
for (int i = 0; i < len; i++) {
count[array[i]] = count[array[i]] + 1;
}

// 用累加法计算某个值在排序后的最高排位(排位从1开始)
for (int i = 1; i < count.length; i++) {
count[i] = count[i] + count[i - 1];
}

// 从后向前处理保证计数排序算法的稳定性
int[] tmp = new int[len];
for (int i = len - 1; i >= 0; i--) {
int v = array[i];

// 获取当前数的排位
int j = count[v];

// 计算当前数在新数组中的下标(排位数减去1)
j = j - 1;

// 将当前数放到新数组的正确位置上
tmp[j] = v;

// 更新可用的排位
count[v] = count[v] - 1;

// 下面是简洁写法
// tmp[count[array[i]] - 1] = array[i];
// count[array[i]] = count[array[i]] - 1;
}

// 拷贝回原数组
for (int i = 0; i < tmp.length; i++) {
array[i] = tmp[i];
}

// 恢复数组的数据到原来的数据
for (int i = 0; i < len; i++) {
array[i] = array[i] - offset;
}
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}

基数排序

RadixSort.javaview raw
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package dsa.algorithm.da101_sort.st91;

import java.util.Arrays;

public class RadixSort {

public static void sort(int[] array) {
int len = array.length;

int min = array[0];
int max = array[0];
for (int i = 1; i < len; i++) {
if (array[i] < min) {
min = array[i];
}

if (array[i] > max) {
max = array[i];
}
}

// 修正数组的数据到正数(包含0)的区间
// 如果最小值是负数,可以解决负数不能做下标的问题
// 如果最小值是正数,可以减少统计数组的空间
int offset = max - min;
for (int i = 0; i < len; i++) {
array[i] = array[i] + offset;
}
// min = min + offset;
max = max + offset;

// 对每个分量使用其他稳定性排序算法
// 推荐用计数排序(其他稳定性排序算法的得建立数组并排序)
int c = getFigure(max);
for (int k = 1; k <= c; k++) {
int[] count = new int[10];

for (int i = 0; i < len; i++) {
int d = getDigit(array[i], k);
count[d] = count[d] + 1;
}

for (int i = 1; i < count.length; i++) {
count[i] = count[i] + count[i - 1];
}

// 从后向前处理保证计数排序算法的稳定性
int[] tmp = new int[len];
for (int i = len - 1; i >= 0; i--) {
int d = getDigit(array[i], k);

// 获取当前数的排位
int j = count[d];

// 计算当前数在新数组中的下标(排位数减去1)
j = j - 1;

// 将当前数放到新数组的正确位置上
tmp[j] = array[i]; // 注意当前数是array[i]而不是d

// 更新可用的排位
count[d] = count[d] - 1;

// 下面是简洁写法
// int d = getDigit(array[i], k);
// tmp[count[d] - 1] = array[i];
// count[d] = count[d] - 1;
}

// 只能拷贝回原数组,不能改变引用
// 因为改变引用的话方法外部的数组引用和方法内部的数组引用就不是同一个数组了
// if (k < c) {
// array = tmp;
// continue;
// }

// 拷贝回原数组
for (int i = 0; i < tmp.length; i++) {
array[i] = tmp[i];
}
}

// 恢复数组的数据到原来的数据
for (int i = 0; i < len; i++) {
array[i] = array[i] - offset;
}
}

private static int getFigure(int v) {
if (v < 0) {
v = -v;
}

// 求取最大位数
int c = 0;
while (v > 0) {
v = v / 10;
c++;
}

return c;
}

private static int getDigit(int v, int k) {
if (v < 0) {
v = -v;
}

while (v > 0 && k > 1) {
v = v / 10;

k--;
}

return v % 10;
}

private static void swap(int[] array, int i, int j) {
// 注释掉,因为每次判断带来的开销并不比无效的自我交换带来的开销少
// if (i == j) {
// return;
// }

int t = array[i];
array[i] = array[j];
array[j] = t;
}

public static void main(String[] args) {
// SortTest.testFixedExample(array -> sort(array));
SortTest.testRandomExample(t -> sort(t));
}

public static class SortTest {
public static interface SortFunc {
void sort(int[] array);
}

private static boolean testSort(int[] array, SortFunc sf) {
System.out.println();
System.out.println("--->");

int[] mybak = Arrays.copyOf(array, array.length);

print(array, "数组排序前");

Arrays.sort(mybak);
print(mybak, "正确结果为");

sf.sort(array);
print(array, "数组排序后");

boolean ret = check(array, mybak);

System.out.println("<---");
System.out.println();

return ret;
}

private static void testRandomExample(SortFunc sf) {
boolean ret;
for (int i = 0; i < 36; i++) {
ret = testSort(random(9), sf);
if (!ret) {
break;
}

ret = testSort(random(10), sf);
if (!ret) {
break;
}
}
}

private static void testFixedExample(SortFunc sf) {
int[] array = new int[] { 310, 78, 237, 773, 96, 165, 70, 757, 665, 508 };

testSort(array, sf);
}

private static int[] random(int n) {
int[] array = new int[n];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 1000) + 1;
}

return array;
}

private static boolean check(int[] array, int[] bak) {
boolean ok = Arrays.equals(array, bak);

System.out.println();
if (ok) {
System.out.println("排序结果为: 正确(right)");
} else {
System.out.println("排序结果为: 错误(error)");
}

return ok;
}

private static void print(int[] array, String tip) {
System.out.println(tip + ":" + Arrays.toString(array));
}
}
}
只想买包辣条