-
Notifications
You must be signed in to change notification settings - Fork 23
/
Sort.java
170 lines (159 loc) · 6.98 KB
/
Sort.java
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
package com.acker.android;
import java.util.Arrays;
/*各种排序算法,默认从小到大排序*/
public class Sort {
public static void main(String[] args) {
int[] test = {12, 3, 6, 19, 11, 17, 23, 16, 25, 2, 0, 1, 45, 33, 7, 10};
System.out.println("原始:" + Arrays.toString(test));
bubbleSort(test);
System.out.println("冒泡:" + Arrays.toString(test));
selectSort(test);
System.out.println("选择:" + Arrays.toString(test));
insertSort(test);
System.out.println("插入:" + Arrays.toString(test));
shellSort(test);
System.out.println("希尔:" + Arrays.toString(test));
quickSort(test, 0, test.length - 1);
System.out.println("快速:" + Arrays.toString(test));
mergeSort(test, 0, test.length - 1);
System.out.println("归并:" + Arrays.toString(test));
}
private static void swap(int[] source, int i, int j) {
int temp = source[i];
source[i] = source[j];
source[j] = temp;
}
// 冒泡排序:让更大的数一直往上漂,漂到数组尾部,成为已排序部分
// 稳定,假如一次扫描过程中没有交换就认为排序完成,则最好时间复杂度O(n),否则最好时间复杂度O(n^2),
// 最坏时间复杂度O(n^2),平均时间复杂度O(n^2),空间复杂度O(1)
public static void bubbleSort(int[] source) {
int i, j;
int n = source.length;
for (i = 0; i < n; i++) {
for (j = 0; j < n - i - 1; j++) {
if (source[j] > source[j + 1]) {
swap(source, j, j + 1);
}
}
}
}
// 选择排序:每次在未排序的部分中选择一个最小的,放到已排序部分的末尾
// 不稳定(选择完成,交换时可能造成顺序改变),时间复杂度都是O(n^2),空间复杂度O(1)
public static void selectSort(int[] source) {
int i, j, min;
int n = source.length;
for (i = 0; i < n - 1; i++) {
min = i;
for (j = i + 1; j < n; j++) {
if (source[min] > source[j]) {
min = j;
}
}
if (min != i) {
swap(source, i, min);
}
}
}
// 插入排序:每次从未排序区取第一个数据,然后往前插入到排序区的合适位置
// 稳定,最好时间复杂度O(n),最坏时间复杂度O(n^2),平均时间复杂度O(n^2),空间复杂度O(1)
public static void insertSort(int[] source) {
int i, j, temp;
int n = source.length;
for (i = 1; i < n; i++) {
temp = source[i];
j = i - 1;
while (j >= 0 && temp < source[j]) {
source[j + 1] = source[j];
j--;
}
source[j + 1] = temp;
}
}
// Shell排序:改进的插入排序方法,对插入排序再加一个步长的循环就是希尔排序,适用于n较大时
// 步长序列应该1.保证最终步长为1。2.尽量避免序列中的值互为倍数(尤其是相邻的值)
// 利用了:1.n值较小时,直接插入排序的最好最坏时间复杂度相差不大。2.当数据基本有序时,直接插入排序的时间复杂度较小
// 不稳定,时间复杂度取决于步长序列,空间复杂度O(1)
public static void shellSort(int[] source) {
int[] stepSeq = {5, 3, 2, 1};
int i, j, k, temp, step;
int n = source.length;
for (k = 0; k < stepSeq.length; k++) {
step = stepSeq[k];
for (i = step; i < n; i++) {
temp = source[i];
j = i - step;
while (j >= 0 && temp < source[j]) {
source[j + step] = source[j];
j = j - step;
}
source[j + step] = temp;
}
}
}
// 快速排序:分治法递归求解
// 每次要找到一个中间位置,使得该点左边所有数值均比其小,右边均比其大,然后左右区间重复上述过程,直到所有子集只剩下一个元素为止
// 不稳定,最坏时间复杂度O(n^2)(发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候)
// 最好时间复杂度O(nlogn)(每次区间都是等分),平均时间复杂度O(nlogn)
// 空间复杂度,主要是由于递归造成了栈空间的使用,一般而言,最好和平均为O(logn),最差为O(n)
public static void quickSort(int[] source, int low, int high) {
int middle;
if (low < high) {
middle = partition(source, low, high);
quickSort(source, low, middle - 1);
quickSort(source, middle + 1, high);
}
}
// 快速排序划分算法:区间第一个记录作为基准,从区间两端交替向中间扫描,直至i=j为止
public static int partition(int[] source, int i, int j) {
int point = source[i];
while (i < j) {
while (i < j && source[j] >= point) {
j--;
}
if (i < j) {
swap(source, i++, j);
}
while (i < j && source[i] <= point) {
i++;
}
if (i < j) {
swap(source, i, j--);
}
}
return i;
}
// 归并排序:分治法递归求解,分为分割和合并两个部分
// 将序列递归分割(二分或四分或。。)直至每个子序列只有一个值,然后相邻的子序列再递归合并,
// 在合并的过程中完成对每个子序列的排序,即排好序的相邻子序列再次进行合并排序
// 稳定,最好,最坏,平均时间复杂度都是O(nlogn)
// 空间复杂度:使用了额外的空间,O(n)
public static void mergeSort(int[] source, int low, int high) {
if (low < high) {
int mid = (high + low) / 2;
// 两路归并,合并一次;如果是多路归并,同样是按照分割为几组,便合并几减一次。
mergeSort(source, low, mid);
mergeSort(source, mid + 1, high);
merge(source, low, mid, mid + 1, high);
}
}
public static void merge(int[] source, int lowA, int highA, int lowB,
int highB) {
int i = lowA;
int j = lowB;
// 需要一个数组来存放merge结果
int k = 0;
int[] temp = new int[highB - lowA + 1];
for (; i <= highA; i++) {
for (; j <= highB; j++) {
if (source[j] < source[i]) {
temp[k++] = source[j];
} else {
break;
}
}
temp[k++] = source[i];
}
// 只复制k个值,若第二段存在比第一段所有数都大的数,要将其及其后面部分在source中位置不变
System.arraycopy(temp, 0, source, lowA, k);
}
}