auto commit
This commit is contained in:
parent
0fb30502e0
commit
6478389db1
86
notes/算法.md
86
notes/算法.md
|
@ -347,25 +347,32 @@ public class Insertion<T extends Comparable<T>> extends Sort<T> {
|
||||||
|
|
||||||
希尔排序使用插入排序对间隔 h 的序列进行排序。通过不断减小 h,最后令 h=1,就可以使得整个数组是有序的。
|
希尔排序使用插入排序对间隔 h 的序列进行排序。通过不断减小 h,最后令 h=1,就可以使得整个数组是有序的。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//cdbe1d12-5ad9-4acb-a717-bbc822c2acf3.png" width="500"/> </div><br>
|
<div align="center"> <img src="../pics//0157d362-98dd-4e51-ac26-00ecb76beb3e.png" width="500"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Shell<T extends Comparable<T>> extends Sort<T> {
|
public class Shell<T extends Comparable<T>> extends Sort<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sort(T[] nums) {
|
public void sort(T[] nums) {
|
||||||
|
|
||||||
int N = nums.length;
|
int N = nums.length;
|
||||||
int h = 1;
|
int h = 1;
|
||||||
while (h < N / 3)
|
|
||||||
|
while (h < N / 3) {
|
||||||
h = 3 * h + 1; // 1, 4, 13, 40, ...
|
h = 3 * h + 1; // 1, 4, 13, 40, ...
|
||||||
|
}
|
||||||
|
|
||||||
while (h >= 1) {
|
while (h >= 1) {
|
||||||
for (int i = h; i < N; i++)
|
for (int i = h; i < N; i++) {
|
||||||
for (int j = i; j >= h && less(nums[j], nums[j - h]); j -= h)
|
for (int j = i; j >= h && less(nums[j], nums[j - h]); j -= h) {
|
||||||
swap(nums, j, j - h);
|
swap(nums, j, j - h);
|
||||||
|
}
|
||||||
|
}
|
||||||
h = h / 3;
|
h = h / 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
希尔排序的运行时间达不到平方级别,使用递增序列 1, 4, 13, 40, ... 的希尔排序所需要的比较次数不会超过 N 的若干倍乘于递增序列的长度。后面介绍的高级排序算法只会比希尔排序快两倍左右。
|
希尔排序的运行时间达不到平方级别,使用递增序列 1, 4, 13, 40, ... 的希尔排序所需要的比较次数不会超过 N 的若干倍乘于递增序列的长度。后面介绍的高级排序算法只会比希尔排序快两倍左右。
|
||||||
|
@ -374,7 +381,7 @@ public class Shell<T extends Comparable<T>> extends Sort<T> {
|
||||||
|
|
||||||
归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。
|
归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//8dfb4cc9-26da-45e7-b820-4576fa1cbb0e.png" width="350"/> </div><br>
|
<div align="center"> <img src="../pics//220790c6-4377-4a2e-8686-58398afc8a18.png" width="350"/> </div><br>
|
||||||
|
|
||||||
### 1. 归并方法
|
### 1. 归并方法
|
||||||
|
|
||||||
|
@ -385,32 +392,42 @@ public abstract class MergeSort<T extends Comparable<T>> extends Sort<T> {
|
||||||
|
|
||||||
protected T[] aux;
|
protected T[] aux;
|
||||||
|
|
||||||
|
|
||||||
protected void merge(T[] nums, int l, int m, int h) {
|
protected void merge(T[] nums, int l, int m, int h) {
|
||||||
|
|
||||||
int i = l, j = m + 1;
|
int i = l, j = m + 1;
|
||||||
|
|
||||||
for (int k = l; k <= h; k++)
|
for (int k = l; k <= h; k++) {
|
||||||
aux[k] = nums[k]; // 将数据复制到辅助数组
|
aux[k] = nums[k]; // 将数据复制到辅助数组
|
||||||
|
}
|
||||||
|
|
||||||
for (int k = l; k <= h; k++) {
|
for (int k = l; k <= h; k++) {
|
||||||
if (i > m)
|
if (i > m) {
|
||||||
nums[k] = aux[j++];
|
nums[k] = aux[j++];
|
||||||
else if (j > h)
|
|
||||||
|
} else if (j > h) {
|
||||||
nums[k] = aux[i++];
|
nums[k] = aux[i++];
|
||||||
else if (aux[i].compareTo(nums[j]) <= 0)
|
|
||||||
|
} else if (aux[i].compareTo(nums[j]) <= 0) {
|
||||||
nums[k] = aux[i++]; // 先进行这一步,保证稳定性
|
nums[k] = aux[i++]; // 先进行这一步,保证稳定性
|
||||||
else
|
|
||||||
|
} else {
|
||||||
nums[k] = aux[j++];
|
nums[k] = aux[j++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 自顶向下归并排序
|
### 2. 自顶向下归并排序
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//0c55e11c-d3ce-4cd8-b139-028aea6f40e3.png" width="450"/> </div><br>
|
将一个大数组分成两个小数组去求解。
|
||||||
|
|
||||||
|
因为每次都将问题对半分成两个子问题,而这种对半分的算法复杂度一般为 O(NlogN),因此该归并排序方法的时间复杂度也为 O(NlogN)。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sort(T[] nums) {
|
public void sort(T[] nums) {
|
||||||
aux = (T[]) new Comparable[nums.length];
|
aux = (T[]) new Comparable[nums.length];
|
||||||
|
@ -418,8 +435,9 @@ public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sort(T[] nums, int l, int h) {
|
private void sort(T[] nums, int l, int h) {
|
||||||
if (h <= l)
|
if (h <= l) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
int mid = l + (h - l) / 2;
|
int mid = l + (h - l) / 2;
|
||||||
sort(nums, l, mid);
|
sort(nums, l, mid);
|
||||||
sort(nums, mid + 1, h);
|
sort(nums, mid + 1, h);
|
||||||
|
@ -428,23 +446,27 @@ public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
因为每次都将问题对半分成两个子问题,而这种对半分的算法复杂度一般为 O(NlogN),因此该归并排序方法的时间复杂度也为 O(NlogN)。
|
|
||||||
|
|
||||||
### 3. 自底向上归并排序
|
### 3. 自底向上归并排序
|
||||||
|
|
||||||
先归并那些微型数组,然后成对归并得到的微型数组。
|
先归并那些微型数组,然后成对归并得到的微型数组。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Down2UpMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
public class Down2UpMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sort(T[] nums) {
|
public void sort(T[] nums) {
|
||||||
|
|
||||||
int N = nums.length;
|
int N = nums.length;
|
||||||
aux = (T[]) new Comparable[N];
|
aux = (T[]) new Comparable[N];
|
||||||
for (int sz = 1; sz < N; sz += sz)
|
|
||||||
for (int lo = 0; lo < N - sz; lo += sz + sz)
|
for (int sz = 1; sz < N; sz += sz) {
|
||||||
|
for (int lo = 0; lo < N - sz; lo += sz + sz) {
|
||||||
merge(nums, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, N - 1));
|
merge(nums, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, N - 1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 快速排序
|
## 快速排序
|
||||||
|
@ -454,10 +476,11 @@ public class Down2UpMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||||
- 归并排序将数组分为两个子数组分别排序,并将有序的子数组归并使得整个数组排序;
|
- 归并排序将数组分为两个子数组分别排序,并将有序的子数组归并使得整个数组排序;
|
||||||
- 快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。
|
- 快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//ab77240d-7338-4547-9183-00215e7220ec.png" width="500"/> </div><br>
|
<div align="center"> <img src="../pics//f8047846-efd4-42be-b6b7-27a7c4998b51.png" width="500"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class QuickSort<T extends Comparable<T>> extends Sort<T> {
|
public class QuickSort<T extends Comparable<T>> extends Sort<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sort(T[] nums) {
|
public void sort(T[] nums) {
|
||||||
shuffle(nums);
|
shuffle(nums);
|
||||||
|
@ -482,9 +505,9 @@ public class QuickSort<T extends Comparable<T>> extends Sort<T> {
|
||||||
|
|
||||||
### 2. 切分
|
### 2. 切分
|
||||||
|
|
||||||
取 a[lo] 作为切分元素,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于等于它的元素,交换这两个元素,并不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[lo] 和 a[j] 交换位置。
|
取 a[l] 作为切分元素,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于等于它的元素,交换这两个元素。不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[l] 和 a[j] 交换位置。
|
||||||
|
|
||||||
<div align="center"> <img src="../pics//5aac64d3-2c7b-4f32-9e9a-1df2186f588b.png" width="300"/> </div><br>
|
<div align="center"> <img src="../pics//864bfa7d-1149-420c-a752-f9b3d4e782ec.png" width="400"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
private int partition(T[] nums, int l, int h) {
|
private int partition(T[] nums, int l, int h) {
|
||||||
|
@ -528,21 +551,24 @@ private int partition(T[] nums, int l, int h) {
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class ThreeWayQuickSort<T extends Comparable<T>> extends QuickSort<T> {
|
public class ThreeWayQuickSort<T extends Comparable<T>> extends QuickSort<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void sort(T[] nums, int l, int h) {
|
protected void sort(T[] nums, int l, int h) {
|
||||||
if (h <= l)
|
if (h <= l) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
int lt = l, i = l + 1, gt = h;
|
int lt = l, i = l + 1, gt = h;
|
||||||
T v = nums[l];
|
T v = nums[l];
|
||||||
while (i <= gt) {
|
while (i <= gt) {
|
||||||
int cmp = nums[i].compareTo(v);
|
int cmp = nums[i].compareTo(v);
|
||||||
if (cmp < 0)
|
if (cmp < 0) {
|
||||||
swap(nums, lt++, i++);
|
swap(nums, lt++, i++);
|
||||||
else if (cmp > 0)
|
} else if (cmp > 0) {
|
||||||
swap(nums, i, gt--);
|
swap(nums, i, gt--);
|
||||||
else
|
} else {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sort(nums, l, lt - 1);
|
sort(nums, l, lt - 1);
|
||||||
sort(nums, gt + 1, h);
|
sort(nums, gt + 1, h);
|
||||||
}
|
}
|
||||||
|
@ -555,24 +581,28 @@ public class ThreeWayQuickSort<T extends Comparable<T>> extends QuickSort<T> {
|
||||||
|
|
||||||
可以利用这个特性找出数组的第 k 个元素。
|
可以利用这个特性找出数组的第 k 个元素。
|
||||||
|
|
||||||
|
该算法是线性级别的,因为每次能将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public T select(T[] nums, int k) {
|
public T select(T[] nums, int k) {
|
||||||
int l = 0, h = nums.length - 1;
|
int l = 0, h = nums.length - 1;
|
||||||
while (h > l) {
|
while (h > l) {
|
||||||
int j = partition(nums, l, h);
|
int j = partition(nums, l, h);
|
||||||
if (j == k)
|
|
||||||
|
if (j == k) {
|
||||||
return nums[k];
|
return nums[k];
|
||||||
else if (j > k)
|
|
||||||
|
} else if (j > k) {
|
||||||
h = j - 1;
|
h = j - 1;
|
||||||
else
|
|
||||||
|
} else {
|
||||||
l = j + 1;
|
l = j + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nums[k];
|
return nums[k];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
该算法是线性级别的。因为每次能将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。
|
|
||||||
|
|
||||||
## 堆排序
|
## 堆排序
|
||||||
|
|
||||||
### 1. 堆
|
### 1. 堆
|
||||||
|
|
BIN
pics/0157d362-98dd-4e51-ac26-00ecb76beb3e.png
Normal file
BIN
pics/0157d362-98dd-4e51-ac26-00ecb76beb3e.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
pics/220790c6-4377-4a2e-8686-58398afc8a18.png
Normal file
BIN
pics/220790c6-4377-4a2e-8686-58398afc8a18.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
BIN
pics/864bfa7d-1149-420c-a752-f9b3d4e782ec.png
Normal file
BIN
pics/864bfa7d-1149-420c-a752-f9b3d4e782ec.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
pics/f8047846-efd4-42be-b6b7-27a7c4998b51.png
Normal file
BIN
pics/f8047846-efd4-42be-b6b7-27a7c4998b51.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Loading…
Reference in New Issue
Block a user