From d8c6cfb89e576ff391a56767f76fe1013bcef2bf Mon Sep 17 00:00:00 2001 From: CyC2018 <1029579233@qq.com> Date: Wed, 6 Jun 2018 20:56:17 +0800 Subject: [PATCH] auto commit --- notes/算法.md | 338 +++++++++++++++++++++++++--------------------- notes/设计模式.md | 7 +- 2 files changed, 183 insertions(+), 162 deletions(-) diff --git a/notes/算法.md b/notes/算法.md index 58f49e4a..2744c56d 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -1,13 +1,20 @@ -* [一、算法分析](#一算法分析) +* [一、前言](#一前言) +* [二、算法分析](#二算法分析) * [数学模型](#数学模型) * [ThreeSum](#threesum) * [倍率实验](#倍率实验) * [注意事项](#注意事项) -* [二、栈和队列](#二栈和队列) +* [三、栈和队列](#三栈和队列) * [栈](#栈) * [队列](#队列) -* [三、排序](#三排序) +* [四、并查集](#四并查集) + * [quick-find](#quick-find) + * [quick-union](#quick-union) + * [加权 quick-union](#加权-quick-union) + * [路径压缩的加权 quick-union](#路径压缩的加权-quick-union) + * [各种 union-find 算法的比较](#各种-union-find-算法的比较) +* [五、排序](#五排序) * [选择排序](#选择排序) * [冒泡排序](#冒泡排序) * [插入排序](#插入排序) @@ -20,24 +27,22 @@ * [外部排序](#外部排序) * [排序算法的比较](#排序算法的比较) * [Java 的排序算法实现](#java-的排序算法实现) -* [四、查找](#四查找) +* [六、查找](#六查找) * [二分查找实现有序符号表](#二分查找实现有序符号表) * [二叉查找树](#二叉查找树) * [2-3 查找树](#2-3-查找树) * [红黑二叉查找树](#红黑二叉查找树) * [散列表](#散列表) * [应用](#应用) -* [五、union-find](#五union-find) - * [quick-find](#quick-find) - * [quick-union](#quick-union) - * [加权 quick-union](#加权-quick-union) - * [路径压缩的加权 quick-union](#路径压缩的加权-quick-union) - * [各种 union-find 算法的比较](#各种-union-find-算法的比较) * [参考资料](#参考资料) -# 一、算法分析 +# 一、前言 + +本文实现代码以及测试代码放在 [Algorithm](https://github.com/CyC2018/Algorithm) + +# 二、算法分析 ## 数学模型 @@ -199,7 +204,7 @@ public class StopWatch { 将所有操作的总成本除于操作总数来将成本均摊。例如对一个空栈进行 N 次连续的 push() 调用需要访问数组的元素为 N+4+8+16+...+2N=5N-4(N 是向数组写入元素,其余的都是调整数组大小时进行复制需要的访问数组操作),均摊后每次操作访问数组的平均次数为常数。 -# 二、栈和队列 +# 三、栈和队列 ## 栈 @@ -446,7 +451,169 @@ public class ListQueue implements MyQueue { } ``` -# 三、排序 +# 四、并查集 + +用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。 + +

+ +| 方法 | 描述 | +| :---: | :---: | +| UF(int N) | 构造一个大小为 N 的并查集 | +| void union(int p, int q) | 连接 p 和 q 节点 | +| int find(int p) | 查找 p 所在的连通分量 | +| boolean connected(int p, int q) | 判断 p 和 q 节点是否连通 | + +```java +public abstract class UF { + protected int[] id; + + public UF(int N) { + id = new int[N]; + for (int i = 0; i < N; i++) + id[i] = i; + } + + public boolean connected(int p, int q) { + return find(p) == find(q); + } + + public abstract int find(int p); + + public abstract void union(int p, int q); +} +``` + +## quick-find + +可以快速进行 find 操作,即可以快速判断两个节点是否连通。 + +同一连通分量的所有节点的 id 值相等。 + +但是 union 操作代价却很高,需要将其中一个连通分量中的所有节点 id 值都修改为另一个节点的 id 值。 + +

+ +```java +public class QuickFindUF extends UF { + public QuickFindUF(int N) { + super(N); + } + + @Override + public int find(int p) { + return id[p]; + } + + @Override + public void union(int p, int q) { + int pID = find(p); + int qID = find(q); + + if (pID == qID) + return; + + for (int i = 0; i < id.length; i++) + if (id[i] == pID) + id[i] = qID; + } +} + +``` + +## quick-union + +可以快速进行 union 操作,只需要修改一个节点的 id 值即可。 + +但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同,id 值只是用来指向另一个节点。因此需要一直向上查找操作,直到找到最上层的节点。 + +

+ +```java +public class QuickUnionUF extends UF { + public QuickUnionUF(int N) { + super(N); + } + + @Override + public int find(int p) { + while (p != id[p]) + p = id[p]; + return p; + } + + @Override + public void union(int p, int q) { + int pRoot = find(p); + int qRoot = find(q); + if (pRoot != qRoot) + id[pRoot] = qRoot; + } +} +``` + +这种方法可以快速进行 union 操作,但是 find 操作和树高成正比,最坏的情况下树的高度为触点的数目。 + +

+ +## 加权 quick-union + +为了解决 quick-union 的树通常会很高的问题,加权 quick-union 在 union 操作时会让较小的树连接较大的树上面。 + +理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。 + +

+ +```java +public class WeightedQuickUnionUF extends UF { + + // 保存节点的数量信息 + private int[] sz; + + public WeightedQuickUnionUF(int N) { + super(N); + this.sz = new int[N]; + for (int i = 0; i < N; i++) + this.sz[i] = 1; + } + + @Override + public int find(int p) { + while (p != id[p]) + p = id[p]; + return p; + } + + @Override + public void union(int p, int q) { + int i = find(p); + int j = find(q); + if (i == j) return; + if (sz[i] < sz[j]) { + id[i] = j; + sz[j] += sz[i]; + } else { + id[j] = i; + sz[i] += sz[j]; + } + } +} +``` + +## 路径压缩的加权 quick-union + +在检查节点的同时将它们直接链接到根节点,只需要在 find 中添加一个循环即可。 + +## 各种 union-find 算法的比较 + +| 算法 | union | find | +| :---: | :---: | :---: | +| quick-find | N | 1 | +| quick-union | 树高 | 树高 | +| 加权 quick-union | logN | logN | +| 路径压缩的加权 quick-union | 非常接近 1 | 非常接近 1 | + +# 五、排序 待排序的元素需要实现 Java 的 Comparable 接口,该接口有 compareTo() 方法,可以用它来判断两个元素的大小关系。 @@ -949,7 +1116,7 @@ public class HeapSort { Java 主要排序方法为 java.util.Arrays.sort(),对于原始数据类型使用三向切分的快速排序,对于引用类型使用归并排序。 -# 四、查找 +# 六、查找 符号表是一种存储键值对的数据结构,主要支持两种操作:插入一个新的键值对、根据给定键得到值。 @@ -1659,149 +1826,6 @@ public class SparseVector { } ``` -# 五、union-find - - -用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。 - -

- - -| 方法 | 描述 | -| :---: | :---: | -| UF(int N) | 构造一个大小为 N 的并查集 | -| void union(int p, int q) | 连接 p 和 q 节点 | -| int find(int p) | 查找 p 所在的连通分量 | -| boolean connected(int p, int q) | 判断 p 和 q 节点是否连通 | - -```java -public class UF { - private int[] id; - - public UF(int N) { - id = new int[N]; - for (int i = 0; i < N; i++) { - id[i] = i; - } - } - - public boolean connected(int p, int q) { - return find(p) == find(q); - } -} -``` - -## quick-find - -可以快速进行 find 操作,即可以快速判断两个节点是否连通。 - -同一连通分量的所有节点的 id 值相等。 - -但是 union 操作代价却很高,需要将其中一个连通分量中的所有节点 id 值都修改为另一个节点的 id 值。 - -

- -```java -public int find(int p) { - return id[p]; -} -public void union(int p, int q) { - int pID = find(p); - int qID = find(q); - - if (pID == qID) return; - for (int i = 0; i < id.length; i++) { - if (id[i] == pID) id[i] = qID; - } -} -``` - -## quick-union - -可以快速进行 union 操作,只需要修改一个节点的 id 值即可。 - -但是 find 操作开销很大,因为同一个连通分量的节点 id 值不同,id 值只是用来指向另一个节点。因此需要一直向上查找操作,直到找到最上层的节点。 - -

- -```java - public int find(int p) { - while (p != id[p]) p = id[p]; - return p; - } - - public void union(int p, int q) { - int pRoot = find(p); - int qRoot = find(q); - if (pRoot == qRoot) return; - id[pRoot] = qRoot; - } -``` - -这种方法可以快速进行 union 操作,但是 find 操作和树高成正比,最坏的情况下树的高度为触点的数目。 - -

- -## 加权 quick-union - -为了解决 quick-union 的树通常会很高的问题,加权 quick-union 在 union 操作时会让较小的树连接较大的树上面。 - -理论研究证明,加权 quick-union 算法构造的树深度最多不超过 logN。 - -

- -```java -public class WeightedQuickUnionUF { - private int[] id; - // 保存节点的数量信息 - private int[] sz; - - public WeightedQuickUnionUF(int N) { - id = new int[N]; - sz = new int[N]; - for (int i = 0; i < N; i++) { - id[i] = i; - sz[i] = 1; - } - } - - public boolean connected(int p, int q) { - return find(p) == find(q); - } - - public int find(int p) { - while (p != id[p]) p = id[p]; - return p; - } - - public void union(int p, int q) { - int i = find(p); - int j = find(q); - if (i == j) return; - if (sz[i] < sz[j]) { - id[i] = j; - sz[j] += sz[i]; - } else { - id[j] = i; - sz[i] += sz[j]; - } - } -} -``` - -## 路径压缩的加权 quick-union - -在检查节点的同时将它们直接链接到根节点,只需要在 find 中添加一个循环即可。 - -## 各种 union-find 算法的比较 - -| 算法 | union | find | -| :---: | :---: | :---: | -| quick-find | N | 1 | -| quick-union | 树高 | 树高 | -| 加权 quick-union | logN | logN | -| 路径压缩的加权 quick-union | 非常接近 1 | 非常接近 1 | - # 参考资料 - Sedgewick, Robert, and Kevin Wayne. _Algorithms_. Addison-Wesley Professional, 2011. diff --git a/notes/设计模式.md b/notes/设计模式.md index c863894d..11d23eff 100644 --- a/notes/设计模式.md +++ b/notes/设计模式.md @@ -1280,7 +1280,7 @@ public class CalculatorImp implements Calculator { ```java /** * Memento Interface to Originator - * + * * This interface allows the originator to restore its state */ public interface PreviousCalculationToOriginator { @@ -1359,7 +1359,7 @@ public class Client { // user hits CTRL + Z to undo last operation and see last result calculator.restorePreviousCalculation(memento); - // result restored + // result restored System.out.println(calculator.getCalculationResult()); } } @@ -2269,7 +2269,6 @@ public class Client { } ``` - # 四、结构型 ## 1. 适配器(Adapter) @@ -2582,7 +2581,6 @@ public class Leaf extends Component { System.out.println("left:" + name); } - @Override public void add(Component component) { throw new UnsupportedOperationException(); // 牺牲透明性换取单一职责原则,这样就不用考虑是叶子节点还是组合节点 @@ -2887,7 +2885,6 @@ Java 利用缓存来加速大量小对象的访问时间。 控制对其它对象的方法。 - ### 类图 代理有以下四类: