Skip to content

Commit 0e1b861

Browse files
committed
[U] 更新快速排序算法md内容;将文章O(N*)改为O(n*);
1 parent 44ab9f7 commit 0e1b861

10 files changed

Lines changed: 176 additions & 26 deletions

File tree

notes/algorithms/冒泡排序算法.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
![冒泡排序动态图](https://github.com/coderbruis/AlgorithmsInJava/blob/master/notes/pictures/bubbleSort.gif)
88

9-
- 时间复杂度:O(N^2)
9+
- 时间复杂度:O(n^2)
1010
- 空间复杂度:O(1)
1111
- 稳定性:稳定
1212

notes/algorithms/基础排序算法.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ public void sort(int[] nums) {
357357
| 基数排序 | O(d(n+r)) | O(M) | | | | 稳定 |
358358
| 桶排序 | | | | | | 稳定 |
359359
| 选择排序 | O(n^2) | O(1) | | | | 不稳定 |
360-
| 归并排序 | O(nlogn) | O(N) | | | | 稳定 |
360+
| 归并排序 | O(nlogn) | O(n) | | | | 稳定 |
361361
| 快速排序 | O(nlogn) | O(logn)~O(n) | | | | 不稳定 |
362362
| 希尔排序 | O(nlogn) | O(1) | | | | 不稳定 |
363363
| 堆排序 | O(nlogn) | O(1) | | | | 不稳定 |

notes/algorithms/堆排序算法.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
学完堆这种数据结构后,再来学堆排序,会简单的多。
88

9-
- 时间复杂度:O(NlogN)
9+
- 时间复杂度:O(nlogn)
1010
- 空间复杂度:O(1)
1111
- 稳定性:不稳定
1212

@@ -28,8 +28,8 @@
2828

2929
此种堆排序算法
3030

31-
- 平均时间复杂度为:O(NlogN)
32-
- 空间复杂度为:O(N)
31+
- 平均时间复杂度为:O(nlogn)
32+
- 空间复杂度为:O(n)
3333

3434
```
3535
import java.util.Random;
@@ -142,7 +142,7 @@ public class HeapSort01 {
142142

143143
此方式堆排序
144144

145-
- 平均时间复杂度为:O(NlogN)
145+
- 平均时间复杂度为:O(nlogn)
146146
- 空间复杂度为:O(1)
147147

148148
```
@@ -251,7 +251,7 @@ public class HeapSort02 {
251251
}
252252
```
253253

254-
- 平均时间复杂度:O(NlogN)
254+
- 平均时间复杂度:O(nlogn)
255255
- 空间复杂度:O(1)
256256

257257
## 参考

notes/algorithms/归并排序算法.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
- 自下而上的迭代;
99

1010

11-
归并排序算法是一个平均时间复杂度为O(NlogN)级别的算法,并且空间复杂度为O(N)级别。
11+
归并排序算法是一个平均时间复杂度为O(nlogn)级别的算法,并且空间复杂度为O(n)级别。
1212

1313
![归并过程动态图](https://github.com/coderbruis/AlgorithmsInJava/blob/master/notes/pictures/mergeSort.gif)
1414
![分治思想](https://github.com/coderbruis/AlgorithmsInJava/blob/master/notes/pictures/1557906108-5066-20161218163120151-452283750.png)
1515

16-
- 时间复杂度:O(NlogN)
17-
- 空间复杂度:O(N)
16+
- 时间复杂度:O(nlogn)
17+
- 空间复杂度:O(n)
1818
- 稳定性:不稳定
1919

2020
## 正文
@@ -29,10 +29,10 @@
2929

3030
自底向上的特点就是——迭代。
3131

32-
除此之外,自底向上排序的算法不需要额外的空间,空间复杂度为O(1)。自底向上有一个非常重要的作用,它可以通过O(NlogN)的
32+
除此之外,自底向上排序的算法不需要额外的空间,空间复杂度为O(1)。自底向上有一个非常重要的作用,它可以通过O(nlogn)的
3333
时间复杂度去对链表这种数据结构进行排序。
3434

35-
**对链表进行O(NlogN)级别的排序**
35+
**对链表进行O(nlogn)级别的排序**
3636

3737

3838

notes/algorithms/快速排序算法.md

Lines changed: 152 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
快速排序又是一种分而治之思想在排序算法上的典型应用。
44

5-
- 时间复杂度:O(NlogN)
6-
- 空间复杂度:O(N)
5+
- 时间复杂度:O(nlogn)
6+
- 空间复杂度:O(n)
77
- 稳定性:稳定
88

99
排序动画图:
@@ -76,19 +76,19 @@ public class QuickSort {
7676

7777
### 2. 快速排序算法的优化
7878

79-
快速排序的最坏运行情况是 O(N^2),比如说顺序数列的快排。但它的平摊期望时间是 O(NlogN),且 O(NlogN) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
79+
快速排序的最坏运行情况是 O(n^2),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
8080

8181
此处有两点可以进行优化。
8282

8383
1. 对于数组数小于15时,使用插入排序; 数据量较小时,插入排序效率跟高;
84-
2. 对于快速排序的基准值,取随机数,防止数组退化为顺序数组,即快速排序平均时间复杂度退化为O(N^2)
84+
2. 对于快速排序的基准值,取随机数,防止数组退化为顺序数组,即快速排序平均时间复杂度退化为O(n^2)
8585

8686
参考代码如下:
8787
```
8888
/**
8989
* 快速排序的优化
9090
*
91-
* 对于近乎有序的数组,快速排序会退化为O(N^2)。
91+
* 对于近乎有序的数组,快速排序会退化为O(n^2)。
9292
*
9393
* @author LuoHaiYang
9494
*/
@@ -107,7 +107,7 @@ public class QuickSort2 {
107107
108108
//int p = arr[left];
109109
// ===================================== 优化2 =====================================
110-
// 避免快排退化为O(N^2)
110+
// 避免快排退化为O(n^2)
111111
swap(arr, left, (int)Math.random()*(right - left + 1) + left);
112112
113113
int p = arr[left];
@@ -150,8 +150,152 @@ public class QuickSort2 {
150150
}
151151
```
152152

153-
### 3. 双路快排
153+
### 3. 双路(两路)快排
154154

155+
如果存在和 基准值p相等的值,则会出现不平衡的情况,而此时快速排序的平均时间复杂度会退化为O(n^2)。而双路(两路)快排就是为了解决这种情况。
155156

157+
下面直接展示实现代码:
158+
```
159+
/**
160+
*
161+
* 双路快排
162+
*
163+
* @author LuoHaiYang
164+
*/
165+
public class QuickSort2Ways {
166+
167+
private static int partition(int[] arr, int left, int right) {
168+
169+
swap(arr, left, (int)Math.random()*(right - left + 1) + left);
170+
171+
int p = arr[left], i = left + 1, j = right;
172+
173+
while(true) {
174+
175+
/**
176+
* 这里arr[i] < p 和 arr[j] > p 是为了避免出现 arr[i] == p 和 arr[j] == p的情况。
177+
* 如果arr[i] == p,则直接进行了i++了,则数组的p会变得极度不平衡,即 所有小于等于p的值都分在了左边,
178+
* 这种情况下,快速排序的平均时间复杂度会退化成:O(n^2)
179+
*
180+
*/
181+
182+
while(i <= right && arr[i] < p) {
183+
i++;
184+
}
185+
while(j >= 0 && arr[j] > p) {
186+
j--;
187+
}
188+
189+
if (i > j) {
190+
break;
191+
}
192+
193+
swap(arr, i++, j--);
194+
}
195+
swap(arr, left, j);
196+
return j;
197+
}
198+
199+
private static void sort(int[] arr, int left, int right) {
200+
if (right - left <= 15) {
201+
InsertionSort.sort(arr);
202+
return;
203+
}
204+
205+
int p = partition(arr, left, right);
206+
sort(arr, left, p - 1);
207+
sort(arr, p + 1, right);
208+
}
209+
210+
public static void sort(int[] arr) {
211+
int n = arr.length;
212+
sort(arr, 0, n - 1);
213+
}
214+
215+
public static void swap(int[] arr, int i, int j) {
216+
int tmp = arr[i];
217+
arr[i] = arr[j];
218+
arr[j] = tmp;
219+
}
220+
}
221+
```
222+
223+
这里需要注意一点,对于双路快排的小于基准值p和大于基准值p的判断,是不能用相等的,正如上述代码中while循环中的:
224+
```
225+
while(i <= right && arr[i] < p) {
226+
i++;
227+
}
228+
while(j >= 0 && arr[j] > p) {
229+
j--;
230+
}
231+
```
232+
这里就是为了避免出现极度不平衡的情况出现,上述代码注释以及解释了。
233+
234+
### 4. 三路快排
235+
236+
然而,对于大量重复值的情况,两路快排还有优化的空间。下面先看下三路快排的代码实现:
237+
238+
```
239+
/**
240+
*
241+
* 三路快排
242+
*
243+
* @author LuoHaiYang
244+
*/
245+
public class QuickSort3Ways {
246+
247+
private static void sort(int[] arr, int left, int right) {
248+
if (right - left <= 15) {
249+
InsertionSort.sort(arr);
250+
return;
251+
}
252+
// 增加随机值,防止快排退化为O(n^2)
253+
swap(arr,left, (int)Math.random()*(right - left - 1) + left);
254+
255+
int p = arr[left];
256+
257+
// [p...................................................right]
258+
// p
259+
// lt
260+
// i
261+
// gt
262+
// arr[left+1...lt] < p arr[lt+1...i) = p arr[gt...right] > p
263+
int lt = left, gt = right + 1, i = left + 1;
264+
265+
while ( i < gt) {
266+
if (arr[i] < p) {
267+
swap(arr, lt+1, i);
268+
i++;
269+
lt++;
270+
} else if (arr[i] > p) {
271+
swap(arr, i, gt-1);
272+
gt--;
273+
} else {// arr[i] == v
274+
i++;
275+
}
276+
}
277+
swap(arr, left, lt);
278+
// 继续对[left,lt]进行排序
279+
sort(arr, left, lt-1);
280+
// 继续对[gt, right]进行排序
281+
sort(arr, gt, right);
282+
}
283+
284+
public static void sort(int[] arr) {
285+
int n = arr.length;
286+
sort(arr, 0, n-1);
287+
}
288+
289+
private static void swap(int[] arr, int i, int j) {
290+
int tmp = arr[i];
291+
arr[i] = arr[j];
292+
arr[j] = tmp;
293+
}
294+
}
295+
```
296+
297+
三路快排相对于两路快排的优化之处在于,当出现大量重复元素时直接进行判断加速排序过程,直接进行lt++或者是gt--,这样避免了大量重复元素是的替换过程。
298+
299+
## 参考
156300

157-
## 参考
301+
- [动态图参考](https://www.runoob.com/w3cnote/bubble-sort.html)

notes/algorithms/插入排序算法.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
![插入排序动态图](https://github.com/coderbruis/AlgorithmsInJava/blob/master/notes/pictures/insertionSort.gif)
88

9-
- 时间复杂度:O(N^2)
9+
- 时间复杂度:O(n^2)
1010
- 空间复杂度:O(1)
1111
- 稳定性:稳定
1212

notes/algorithms/选择排序算法.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
![选择排序动态图](https://github.com/coderbruis/AlgorithmsInJava/blob/master/notes/pictures/selectionSort.gif)
88

9-
- 时间复杂度:O(N^2)
9+
- 时间复杂度:O(n^2)
1010
- 空间复杂度:O(1)
1111
- 稳定性:不稳定
1212

src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/**
44
* 快速排序的优化
55
*
6-
* 对于近乎有序的数组,快速排序会退化为O(N^2)。
6+
* 对于近乎有序的数组,快速排序会退化为O(n^2)。
77
*
88
* @author LuoHaiYang
99
*/
@@ -22,7 +22,7 @@ private static int partition(int[] arr, int left, int right) {
2222

2323
//int p = arr[left];
2424
// ===================================== 优化2 =====================================
25-
// 避免快排退化为O(N^2)
25+
// 避免快排退化为O(n^2)
2626
swap(arr, left, (int)Math.random()*(right - left + 1) + left);
2727

2828
int p = arr[left];

src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort2Ways.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@ private static int partition(int[] arr, int left, int right) {
1616

1717
while(true) {
1818

19+
/**
20+
* 这里arr[i] < p 和 arr[j] > p 是为了避免出现 arr[i] == p 和 arr[j] == p的情况。
21+
* 如果arr[i] == p,则直接进行了i++了,则数组的p会变得极度不平衡,即 所有小于等于p的值都分在了左边,
22+
* 这种情况下,快速排序的平均时间复杂度会退化成:O(n^2)
23+
*
24+
*/
25+
1926
while(i <= right && arr[i] < p) {
2027
i++;
2128
}
22-
2329
while(j >= 0 && arr[j] > p) {
2430
j--;
2531
}

src/main/java/com/bruis/algorithminjava/algorithm/sort/QuickSort3Ways.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ private static void sort(int[] arr, int left, int right) {
1313
InsertionSort.sort(arr);
1414
return;
1515
}
16-
// 增加随机值,防止快排退化为O(N^2)
16+
// 增加随机值,防止快排退化为O(n^2)
1717
swap(arr,left, (int)Math.random()*(right - left - 1) + left);
1818

1919
int p = arr[left];

0 commit comments

Comments
 (0)