auto commit
This commit is contained in:
parent
06a8653f87
commit
bee8913883
50
notes/算法.md
50
notes/算法.md
|
@ -74,18 +74,18 @@
|
||||||
* [5. 删除最小键](#5-删除最小键)
|
* [5. 删除最小键](#5-删除最小键)
|
||||||
* [6. 分析](#6-分析)
|
* [6. 分析](#6-分析)
|
||||||
* [散列表](#散列表)
|
* [散列表](#散列表)
|
||||||
* [散列函数](#散列函数)
|
* [1. 散列函数](#1-散列函数)
|
||||||
* [基于拉链法的散列表](#基于拉链法的散列表)
|
* [2. 基于拉链法的散列表](#2-基于拉链法的散列表)
|
||||||
* [基于线性探测法的散列表](#基于线性探测法的散列表)
|
* [3. 基于线性探测法的散列表](#3-基于线性探测法的散列表)
|
||||||
* [查找](#查找)
|
* [3.1 查找](#31-查找)
|
||||||
* [插入](#插入)
|
* [3.2 插入](#32-插入)
|
||||||
* [删除](#删除)
|
* [3.3 删除](#33-删除)
|
||||||
* [调整数组大小](#调整数组大小)
|
* [3.4 调整数组大小](#34-调整数组大小)
|
||||||
* [应用](#应用)
|
* [应用](#应用)
|
||||||
* [各种符号表实现的比较](#各种符号表实现的比较)
|
* [1. 各种符号表实现的比较](#1-各种符号表实现的比较)
|
||||||
* [Java 的符号表实现](#java-的符号表实现)
|
* [2. Java 的符号表实现](#2-java-的符号表实现)
|
||||||
* [集合类型](#集合类型)
|
* [3. 集合类型](#3-集合类型)
|
||||||
* [稀疏向量乘法](#稀疏向量乘法)
|
* [4. 稀疏向量乘法](#4-稀疏向量乘法)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
# 基础
|
# 基础
|
||||||
|
@ -1363,7 +1363,7 @@ private Node put(Node x, Key key, Value val) {
|
||||||
|
|
||||||
#### 5. 删除最小键
|
#### 5. 删除最小键
|
||||||
|
|
||||||
如果最小键在一个 2- 节点中,那么删除该键会留下一个空链接,就破坏了平衡性,因此要确保最小键不在 2- 节点中。将 2- 节点转换成 3- 节点或者 4- 节点有两种方法,一种是向上层节点拿一个 key,或者向兄弟节点拿一个 key。如果上层节点是 2- 节点,那么就没办法从上层节点拿 key 了,因此要保证删除路径上的所有节点都不是 2- 节点。在向下删除的过程中,保证以下情况之一发生:
|
如果最小键在一个 2- 节点中,那么删除该键会留下一个空链接,就破坏了平衡性,因此要确保最小键不在 2- 节点中。将 2- 节点转换成 3- 节点或者 4- 节点有两种方法,一种是向上层节点拿一个 key,一种是向兄弟节点拿一个 key。如果上层节点是 2- 节点,那么就没办法从上层节点拿 key 了,因此要保证删除路径上的所有节点都不是 2- 节点。在向下删除的过程中,保证以下情况之一发生:
|
||||||
|
|
||||||
1. 如果当前节点的左子节点不是 2- 节点,完成;
|
1. 如果当前节点的左子节点不是 2- 节点,完成;
|
||||||
2. 如果当前节点的左子节点是 2- 节点而它的兄弟节点不是 2- 节点,向兄弟节点拿一个 key 过来;
|
2. 如果当前节点的左子节点是 2- 节点而它的兄弟节点不是 2- 节点,向兄弟节点拿一个 key 过来;
|
||||||
|
@ -1387,7 +1387,7 @@ private Node put(Node x, Key key, Value val) {
|
||||||
|
|
||||||
由于无法通过散列值知道键的大小关系,因此散列表无法实现有序性操作。
|
由于无法通过散列值知道键的大小关系,因此散列表无法实现有序性操作。
|
||||||
|
|
||||||
### 散列函数
|
### 1. 散列函数
|
||||||
|
|
||||||
对于一个大小为 M 的散列表,散列函数能够把任意键转换为 [0, M-1] 内的正整数,该正整数即为 hash 值。
|
对于一个大小为 M 的散列表,散列函数能够把任意键转换为 [0, M-1] 内的正整数,该正整数即为 hash 值。
|
||||||
|
|
||||||
|
@ -1427,7 +1427,7 @@ Java
|
||||||
int hash = (x.hashCode() & 0x7fffffff) % M;
|
int hash = (x.hashCode() & 0x7fffffff) % M;
|
||||||
```
|
```
|
||||||
|
|
||||||
使用 Java 自带的 HashMap 等自带的哈希表实现时,只需要去实现 Key 类型的 hashCode() 函数即可,因此也就不需要考虑 M 的大小等。Java 规定 hashCode() 能够将键均匀分布于所有的 32 位整数,Java 中的 String、Integer 等对象的 hashCode() 都能实现这一点。以下展示了自定义类型如何实现 hashCode()。
|
使用 Java 自带的 HashMap 等自带的哈希表实现时,只需要去实现 Key 类型的 hashCode() 函数即可。Java 规定 hashCode() 能够将键均匀分布于所有的 32 位整数,Java 中的 String、Integer 等对象的 hashCode() 都能实现这一点。以下展示了自定义类型如何实现 hashCode()。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Transaction{
|
public class Transaction{
|
||||||
|
@ -1445,7 +1445,7 @@ public class Transaction{
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 基于拉链法的散列表
|
### 2. 基于拉链法的散列表
|
||||||
|
|
||||||
拉链法使用链表来存储 hash 值相同的键,从而解决冲突。此时查找需要分两步,首先查找 Key 所在的链表,然后在链表中顺序查找。
|
拉链法使用链表来存储 hash 值相同的键,从而解决冲突。此时查找需要分两步,首先查找 Key 所在的链表,然后在链表中顺序查找。
|
||||||
|
|
||||||
|
@ -1453,7 +1453,7 @@ public class Transaction{
|
||||||
|
|
||||||
对于 N 个键,M 条链表 (N>M),如果哈希函数能够满足均匀性的条件,每条链表的大小趋向于 N/M,因此未命中的查找和插入操作所需要的比较次数为 \~N/M。
|
对于 N 个键,M 条链表 (N>M),如果哈希函数能够满足均匀性的条件,每条链表的大小趋向于 N/M,因此未命中的查找和插入操作所需要的比较次数为 \~N/M。
|
||||||
|
|
||||||
### 基于线性探测法的散列表
|
### 3. 基于线性探测法的散列表
|
||||||
|
|
||||||
线性探测法使用空位来解决冲突,当冲突发生时,向前探测一个空位来存储冲突的键。使用线程探测法,数组的大小 M 应当大于键的个数 N(M>N)。
|
线性探测法使用空位来解决冲突,当冲突发生时,向前探测一个空位来存储冲突的键。使用线程探测法,数组的大小 M 应当大于键的个数 N(M>N)。
|
||||||
|
|
||||||
|
@ -1486,7 +1486,7 @@ public class LinearProbingHashST<Key, Value> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 查找
|
#### 3.1 查找
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public Value get(Key key) {
|
public Value get(Key key) {
|
||||||
|
@ -1499,7 +1499,7 @@ public Value get(Key key) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 插入
|
#### 3.2 插入
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public void put(Key key, Value val) {
|
public void put(Key key, Value val) {
|
||||||
|
@ -1517,7 +1517,7 @@ public void put(Key key, Value val) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 删除
|
#### 3.3 删除
|
||||||
|
|
||||||
删除操作应当将右侧所有相邻的键值重新插入散列表中。
|
删除操作应当将右侧所有相邻的键值重新插入散列表中。
|
||||||
|
|
||||||
|
@ -1545,7 +1545,7 @@ public void delete(Key key) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 调整数组大小
|
#### 3.4 调整数组大小
|
||||||
|
|
||||||
线性探测法的成本取决于连续条目的长度,连续条目也叫聚簇。当聚簇很长时,在查找和插入时也需要进行很多次探测。
|
线性探测法的成本取决于连续条目的长度,连续条目也叫聚簇。当聚簇很长时,在查找和插入时也需要进行很多次探测。
|
||||||
|
|
||||||
|
@ -1580,23 +1580,23 @@ private void resize(int cap) {
|
||||||
|
|
||||||
## 应用
|
## 应用
|
||||||
|
|
||||||
### 各种符号表实现的比较
|
### 1. 各种符号表实现的比较
|
||||||
|
|
||||||
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9ee83c8c-1165-476c-85a6-e6e434e5307a.jpg)
|
![](https://github.com/CyC2018/InterviewNotes/blob/master/pics/9ee83c8c-1165-476c-85a6-e6e434e5307a.jpg)
|
||||||
|
|
||||||
应当优先考虑散列表,当需要有序性操作时使用红黑树。
|
应当优先考虑散列表,当需要有序性操作时使用红黑树。
|
||||||
|
|
||||||
### Java 的符号表实现
|
### 2. Java 的符号表实现
|
||||||
|
|
||||||
Java 的 java.util.TreeMap 和 java.util.HashMap 分别是基于红黑树和拉链法的散列表的符号表实现。
|
Java 的 java.util.TreeMap 和 java.util.HashMap 分别是基于红黑树和拉链法的散列表的符号表实现。
|
||||||
|
|
||||||
### 集合类型
|
### 3. 集合类型
|
||||||
|
|
||||||
除了符号表,集合类型也经常使用,它只有键没有值,可以用集合类型来存储一系列的键然后判断一个键是否在集合中。
|
除了符号表,集合类型也经常使用,它只有键没有值,可以用集合类型来存储一系列的键然后判断一个键是否在集合中。
|
||||||
|
|
||||||
### 稀疏向量乘法
|
### 4. 稀疏向量乘法
|
||||||
|
|
||||||
向量运算涉及到 N 次乘法,当向量为稀疏向量时,可以使用符号表来存储向量中的非 0 索引和值,使得乘法运算只需要对那些非 0 元素进行即可。
|
当向量为稀疏向量时,可以使用符号表来存储向量中的非 0 索引和值,使得乘法运算只需要对那些非 0 元素进行即可。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user