auto commit

This commit is contained in:
CyC2018 2018-07-12 00:01:21 +08:00
parent e6e95ab78c
commit c9718335fa
2 changed files with 31 additions and 27 deletions

View File

@ -147,7 +147,7 @@ Google 开源项目的代码风格规范。
**授权相关**
虽然没有加开源协议,但是默认允许非商业使用。
虽然没有加开源协议,但是允许非商业使用。
转载使用请注明出处,谢谢!
@ -157,7 +157,7 @@ Google 开源项目的代码风格规范。
进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。
这里提供了笔者实现的 GFM 文档转换工具的下载[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
这里提供了笔者实现的 GFM 文档转换工具的链接[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
**排版指南**
@ -165,7 +165,7 @@ Google 开源项目的代码风格规范。
笔记不使用 `![]()` 这种方式来引用图片,而是用 `<img>` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 GFM 不支持 `<center> ![]() </center>` 让图片居中显示,只能使用 `<div align="center"> <img src=""/> </div>` 达到居中的效果。
这里提供了笔者实现的中英混排文档在线排版工具:[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting)。
这里提供了笔者实现的中英混排文档在线排版工具的链接[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting)。
**声明**

View File

@ -24,8 +24,7 @@
* [堆排序](#堆排序)
* [小结](#小结)
* [六、查找](#六查找)
* [链表实现无序符号表](#链表实现无序符号表)
* [二分查找实现有序符号表](#二分查找实现有序符号表)
* [初级实现](#初级实现)
* [二叉查找树](#二叉查找树)
* [2-3 查找树](#2-3-查找树)
* [红黑树](#红黑树)
@ -1178,7 +1177,9 @@ public interface OrderedST<Key extends Comparable<Key>, Value> {
}
```
## 链表实现无序符号表
## 初级实现
### 1. 链表实现无序符号表
```java
public class ListUnorderedST<Key, Value> implements UnorderedST<Key, Value> {
@ -1253,7 +1254,7 @@ public class ListUnorderedST<Key, Value> implements UnorderedST<Key, Value> {
}
```
## 二分查找实现有序符号表
### 2. 二分查找实现有序符号表
使用一对平行数组,一个存储键一个存储值。
@ -1308,7 +1309,7 @@ public class BinarySearchOrderedST<Key extends Comparable<Key>, Value> implement
@Override
public void put(Key key, Value value) {
int index = rank(key);
// 如果找到已经存在的节点键 key就更新这个节点的值为 value
// 如果找到已经存在的节点键 key就更新这个节点的值为 value
if (index < N && keys[index].compareTo(key) == 0) {
values[index] = value;
return;
@ -1391,14 +1392,14 @@ public class BST<Key extends Comparable<Key>, Value> implements OrderedST<Key, V
return 0;
return x.N;
}
protected void recalculateSize(Node x) {
x.N = size(x.left) + size(x.right) + 1;
}
}
```
(为了方便绘图,二叉树的空链接不画出来。)
(为了方便绘图,下文中二叉树的空链接不画出来。)
### 1. get()
@ -1427,7 +1428,7 @@ private Value get(Node x, Key key) {
### 2. put()
当插入的键不存在于树中,需要创建一个新节点,并且更新上层节点的链接使得该节点正确链接到树中。
当插入的键不存在于树中,需要创建一个新节点,并且更新上层节点的链接指向该节点,使得该节点正确链接到树中。
<div align="center"> <img src="../pics//107a6a2b-f15b-4cad-bced-b7fb95258c9c.png" width="200"/> </div><br>
@ -1454,7 +1455,9 @@ private Node put(Node x, Key key, Value value) {
### 3. 分析
二叉查找树的算法运行时间取决于树的形状,而树的形状又取决于键被插入的先后顺序。最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 logN。
二叉查找树的算法运行时间取决于树的形状,而树的形状又取决于键被插入的先后顺序。
最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 logN。
<div align="center"> <img src="../pics//4d741402-344d-4b7c-be01-e57184bcad0e.png" width="200"/> </div><br>
@ -1467,8 +1470,7 @@ private Node put(Node x, Key key, Value value) {
floor(key):小于等于键的最大键
- 如果键小于根节点的键,那么 floor(key) 一定在左子树中;
- 如果键大于根节点的键,需要先判断右子树中是否存在 floor(key),如果存在就找到,否则根节点就是 floor(key)。
- 如果键大于根节点的键,需要先判断右子树中是否存在 floor(key),如果存在就返回,否则根节点就是 floor(key)。
```java
public Key floor(Key key) {
@ -1497,7 +1499,7 @@ rank(key) 返回 key 的排名。
- 如果键和根节点的键相等,返回左子树的节点数;
- 如果小于,递归计算在左子树中的排名;
- 如果大于,递归计算在右子树中的排名,加上左子树的节点数,再加上 1根节点
- 如果大于,递归计算在右子树中的排名,加上左子树的节点数,再加上 1根节点
```java
@Override
@ -1793,15 +1795,15 @@ private Node put(Node x, Key key, Value value) {
- 一致性:相等的键应当有相等的 hash 值,两个键相等表示调用 equals() 返回的值相等。
- 高效性:计算应当简便,有必要的话可以把 hash 值缓存起来,在调用 hash 函数时直接返回。
- 均匀性:所有键的 hash 值应当均匀地分布到 [0, M-1] 之间,这个条件至关重要,直接影响到散列表的性能
- 均匀性:所有键的 hash 值应当均匀地分布到 [0, M-1] 之间,如果不能满足这个条件,有可能产生很多冲突,从而导致散列表的性能下降
除留余数法可以将整数散列到 [0, M-1] 之间,例如一个正整数 k计算 k%M 既可得到一个 [0, M-1] 之间的 hash 值。注意 M 必须是一个素数,否则无法利用键包含的所有信息。例如 M 为 10<sup>k</sup>,那么只能利用键的后 k 位。
对于其它数,可以将其转换成整数的形式,然后利用除留余数法。例如对于浮点数,可以将其表示成二进制形式,然后使用二进制形式的整数值进行除留余数法
对于其它数,可以将其转换成整数的形式,然后利用除留余数法。例如对于浮点数,可以将其的二进制形式转换成整数
对于有多部分组合的键,每部分都需要计算 hash 值,并且最后合并时需要让每部分 hash 值都具有同等重要的地位。可以将该键看成 R 进制的整数,键中每部分都具有不同的权值。
对于多部分组合的类型,每个部分都需要计算 hash 值,这些 hash 值都具有同等重要的地位。为了达到这个目的,可以将该类型看成 R 进制的整数,每个部分都具有不同的权值。
例如,字符串的散列函数实现如下
例如,字符串的散列函数实现如下
```java
int hash = 0;
@ -1823,7 +1825,7 @@ Java 中的 hashCode() 实现了 hash 函数,但是默认使用对象的内存
int hash = (x.hashCode() & 0x7fffffff) % M;
```
使用 Java 自带的 HashMap 等自带的哈希表实现时,只需要去实现 Key 类型的 hashCode() 函数即可。Java 规定 hashCode() 能够将键均匀分布于所有的 32 位整数Java 中的 String、Integer 等对象的 hashCode() 都能实现这一点。以下展示了自定义类型如何实现 hashCode()
使用 Java 自带的 HashMap 等自带的哈希表实现时,只需要去实现 Key 类型的 hashCode() 函数即可。Java 规定 hashCode() 能够将键均匀分布于所有的 32 位整数Java 中的 String、Integer 等对象的 hashCode() 都能实现这一点。以下展示了自定义类型如何实现 hashCode()
```java
public class Transaction {
@ -1850,15 +1852,19 @@ public class Transaction {
### 2. 基于拉链法的散列表
拉链法使用链表来存储 hash 值相同的键,从而解决冲突。此时查找需要分两步,首先查找 Key 所在的链表,然后在链表中顺序查找。
拉链法使用链表来存储 hash 值相同的键,从而解决冲突。
查找需要分两步,首先查找 Key 所在的链表,然后在链表中顺序查找。
对于 N 个键M 条链表 (N>M),如果 hash 函数能够满足均匀性的条件,每条链表的大小趋向于 N/M因此未命中的查找和插入操作所需要的比较次数为 \~N/M。
<div align="center"> <img src="../pics//b4252c85-6fb0-4995-9a68-a1a5925fbdb1.png" width="300"/> </div><br>
对于 N 个键M 条链表 (N>M),如果哈希函数能够满足均匀性的条件,每条链表的大小趋向于 N/M因此未命中的查找和插入操作所需要的比较次数为 \~N/M。
### 3. 基于线性探测法的散列表
线性探测法使用空位来解决冲突,当冲突发生时,向前探测一个空位来存储冲突的键。使用线性探测法,数组的大小 M 应当大于键的个数 NM>N)。
线性探测法使用空位来解决冲突,当冲突发生时,向前探测一个空位来存储冲突的键。
使用线性探测法,数组的大小 M 应当大于键的个数 NM>N)。
<div align="center"> <img src="../pics//dbb8516d-37ba-4e2c-b26b-eefd7de21b45.png" width="400"/> </div><br>
@ -1962,9 +1968,7 @@ public void delete(Key key) {
<div align="center"> <img src="../pics//386cd64f-7a9d-40e6-8c55-22b90ee2d258.png" width="400"/> </div><br>
α = N/Mα 称为利用率。理论证明,当 α 小于 1/2 时探测的预计次数只在 1.5 到 2.5 之间。
为了保证散列表的性能,应当调整数组的大小,使得 α 在 [1/4, 1/2] 之间。
α = N/Mα 称为使用率。理论证明,当 α 小于 1/2 时探测的预计次数只在 1.5 到 2.5 之间。为了保证散列表的性能,应当调整数组的大小,使得 α 在 [1/4, 1/2] 之间。
```java
private void resize() {