auto commit
This commit is contained in:
27
notes/算法.md
27
notes/算法.md
@ -305,7 +305,7 @@ public class ArrayStack<Item> implements MyStack<Item> {
|
||||
|
||||
### 2. 链表实现
|
||||
|
||||
需要使用链表的头插法来实现,因为头插法中最后压入栈的元素在链表的开头,它的 next 指针指向前一个压入栈的元素,在弹出元素使就可以通过 next 指针遍历到前一个压入栈的元素从而让这个元素称为新的栈顶元素。
|
||||
需要使用链表的头插法来实现,因为头插法中最后压入栈的元素在链表的开头,它的 next 指针指向前一个压入栈的元素,在弹出元素时就可以通过 next 指针遍历到前一个压入栈的元素从而让这个元素称为新的栈顶元素。
|
||||
|
||||
```java
|
||||
public class ListStack<Item> implements MyStack<Item> {
|
||||
@ -671,9 +671,9 @@ public class Selection<T extends Comparable<T>> extends Sort<T> {
|
||||
|
||||
## 冒泡排序
|
||||
|
||||
通过从左到右不断交换相邻逆序的相邻元素,在一轮的交换之后,可以让未排序的元素上浮到最右侧,是的右侧是已排序的。
|
||||
通过从左到右不断交换相邻逆序的相邻元素,在一轮的交换之后,可以让未排序的元素上浮到右侧。
|
||||
|
||||
在一轮交换中,如果没有发生交换,就说明数组已经是有序的,此时可以直接退出。
|
||||
在一轮循环中,如果没有发生交换,就说明数组已经是有序的,此时可以直接退出。
|
||||
|
||||
```java
|
||||
public class Bubble<T extends Comparable<T>> extends Sort<T> {
|
||||
@ -739,7 +739,7 @@ public class Shell<T extends Comparable<T>> extends Sort<T> {
|
||||
int N = nums.length;
|
||||
int h = 1;
|
||||
while (h < N / 3)
|
||||
h = 3 * h + 1; // 1, 4, 13, 40, ...
|
||||
h = 3 * h + 1; // 1, 4, 13, 40, ...
|
||||
|
||||
while (h >= 1) {
|
||||
for (int i = h; i < N; i++)
|
||||
@ -772,7 +772,7 @@ public abstract class MergeSort<T extends Comparable<T>> extends Sort<T> {
|
||||
int i = l, j = m + 1;
|
||||
|
||||
for (int k = l; k <= h; k++)
|
||||
aux[k] = nums[k]; // 将数据复制到辅助数组
|
||||
aux[k] = nums[k]; // 将数据复制到辅助数组
|
||||
|
||||
for (int k = l; k <= h; k++) {
|
||||
if (i > m)
|
||||
@ -780,7 +780,7 @@ public abstract class MergeSort<T extends Comparable<T>> extends Sort<T> {
|
||||
else if (j > h)
|
||||
nums[k] = aux[i++];
|
||||
else if (aux[i].compareTo(nums[j]) <= 0)
|
||||
nums[k] = aux[i++]; // 先进行这一步,保证稳定性
|
||||
nums[k] = aux[i++]; // 先进行这一步,保证稳定性
|
||||
else
|
||||
nums[k] = aux[j++];
|
||||
}
|
||||
@ -792,7 +792,6 @@ public abstract class MergeSort<T extends Comparable<T>> extends Sort<T> {
|
||||
|
||||
<div align="center"> <img src="../pics//0c55e11c-d3ce-4cd8-b139-028aea6f40e3.png" width="450"/> </div><br>
|
||||
|
||||
|
||||
```java
|
||||
public class Up2DownMergeSort<T extends Comparable<T>> extends MergeSort<T> {
|
||||
@Override
|
||||
@ -955,7 +954,7 @@ public T select(T[] nums, int k) {
|
||||
}
|
||||
```
|
||||
|
||||
该算法是线性级别的,因为每次正好将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。
|
||||
该算法是线性级别的。因为每次能将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。
|
||||
|
||||
## 堆排序
|
||||
|
||||
@ -963,7 +962,7 @@ public T select(T[] nums, int k) {
|
||||
|
||||
堆的某个节点的值总是大于等于子节点的值,并且堆是一颗完全二叉树。
|
||||
|
||||
堆可以用数组来表示,因为堆是一种完全二叉树,而完全二叉树很容易就存储在数组中。位置 k 的节点的父节点位置为 k/2,而它的两个子节点的位置分别为 2k 和 2k+1。这里不使用数组索引为 0 的位置,是为了更清晰地描述节点的位置关系。
|
||||
堆可以用数组来表示,因为堆是完全二叉树,而完全二叉树很容易就存储在数组中。位置 k 的节点的父节点位置为 k/2,而它的两个子节点的位置分别为 2k 和 2k+1。这里不使用数组索引为 0 的位置,是为了更清晰地描述节点的位置关系。
|
||||
|
||||
<div align="center"> <img src="../pics//f3080f83-6239-459b-8e9c-03b6641f7815.png" width="200"/> </div><br>
|
||||
|
||||
@ -1012,7 +1011,7 @@ private void swim(int k) {
|
||||
}
|
||||
```
|
||||
|
||||
类似地,当一个节点比子节点来得小,也需要不断地向下进行比较和交换操作,把这种操作称为下沉。一个节点有两个子节点,应当与两个子节点中最大那么节点进行交换。
|
||||
类似地,当一个节点比子节点来得小,也需要不断地向下进行比较和交换操作,把这种操作称为下沉。一个节点如果有两个子节点,应当与两个子节点中最大那么节点进行交换。
|
||||
|
||||
<div align="center"> <img src="../pics//72f0ff69-138d-4e54-b7ac-ebe025d978dc.png" width="400"/> </div><br>
|
||||
|
||||
@ -1057,11 +1056,11 @@ public T delMax() {
|
||||
|
||||
### 5. 堆排序
|
||||
|
||||
由于堆可以很容易得到最大的元素并删除它,不断地进行这种操作可以得到一个递减序列。如果把最大元素和当前堆中数组的最后一个元素交换位置,并且不删除它,那么就可以得到一个从尾到头的递减序列,从正向来看就是一个递增序列。因此很容易使用堆来进行排序,并且堆排序是原地排序,不占用额外空间。
|
||||
由于堆可以很容易得到最大的元素并删除它,不断地进行这种操作可以得到一个递减序列。如果把最大元素和当前堆中数组的最后一个元素交换位置,并且不删除它,那么就可以得到一个从尾到头的递减序列,从正向来看就是一个递增序列。因此很容易使用堆来进行排序。并且堆排序是原地排序,不占用额外空间。
|
||||
|
||||
(一)构建堆
|
||||
|
||||
无序数组建立堆最直接的方法是从左到右遍历数组,然后进行上浮操作。一个更高效的方法是从右至左进行下沉操作,如果一个节点的两个节点都已经是堆有序,那么进行下沉操作可以使得这个节点为根节点的堆有序。叶子节点不需要进行下沉操作,因此可以忽略叶子节点的元素,因此只需要遍历一半的元素即可。
|
||||
无序数组建立堆最直接的方法是从左到右遍历数组,然后进行上浮操作。一个更高效的方法是从右至左进行下沉操作,如果一个节点的两个节点都已经是堆有序,那么进行下沉操作可以使得这个节点为根节点的堆有序。叶子节点不需要进行下沉操作,可以忽略叶子节点的元素,因此只需要遍历一半的元素即可。
|
||||
|
||||
<div align="center"> <img src="../pics//b84ba6fb-312b-4e69-8c77-fb6eb6fb38d4.png" width="300"/> </div><br>
|
||||
|
||||
@ -1071,7 +1070,7 @@ public T delMax() {
|
||||
|
||||
<div align="center"> <img src="../pics//51fb761d-8ce0-4472-92ff-2f227ac7888a.png" width="270"/> </div><br>
|
||||
|
||||
<div align="center"> <img src="../pics//1f039a45-6b91-4f31-a2c2-6c63eb8bdb56.png" width="300"/> </div><br>
|
||||
<div align="center"> <img src="../pics//b20a3466-44b4-445e-87c7-dd4fb9ef44b2.png" width="350"/> </div><br>
|
||||
|
||||
```java
|
||||
public class HeapSort<T extends Comparable<T>> extends Sort<T> {
|
||||
@ -1116,7 +1115,7 @@ public class HeapSort<T extends Comparable<T>> extends Sort<T> {
|
||||
|
||||
堆排序时一种原地排序,没有利用额外的空间。
|
||||
|
||||
现代操作系统很少使用堆排序,因为它无法利用缓存,也就是数组元素很少和相邻的元素进行比较。
|
||||
现代操作系统很少使用堆排序,因为它无法利用局部性原理进行缓存,也就是数组元素很少和相邻的元素进行比较。
|
||||
|
||||
## 小结
|
||||
|
||||
|
Reference in New Issue
Block a user