auto commit

This commit is contained in:
CyC2018 2018-08-15 22:16:30 +08:00
parent 0fb30502e0
commit 6478389db1
5 changed files with 61 additions and 31 deletions

View File

@ -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. 堆

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB