-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9fefa78
commit 7505665
Showing
18 changed files
with
582 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "chapter09-hashmap" | ||
version.workspace = true | ||
edition.workspace = true | ||
authors.workspace = true | ||
|
||
[[bin]] | ||
name = "hash1" | ||
path = "src/hash1-cap.rs" | ||
|
||
|
||
[[bin]] | ||
name = "hash2" | ||
path = "src/hash2-hashset.rs" | ||
|
||
|
||
[[bin]] | ||
name = "hash3" | ||
path = "src/hash3-btreemap.rs" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# hash | ||
|
||
## hashMap | ||
|
||
### 结构 | ||
|
||
```rust | ||
pub struct HashMap<K, V, S = DefaultHashBuilder, A: Allocator = Global> { | ||
pub(crate) hash_builder: S, | ||
pub(crate) table: RawTable<(K, V), A>, | ||
} | ||
``` | ||
|
||
```rust | ||
pub struct RawTable<T, A: Allocator = Global> { | ||
table: RawTableInner, | ||
alloc: A, | ||
// Tell dropck that we own instances of T. | ||
marker: PhantomData<T>, | ||
} | ||
|
||
/// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless | ||
/// of how many different key-value types are used. | ||
struct RawTableInner { | ||
// 哈希表中哈希桶的数量减一 | ||
bucket_mask: usize, | ||
|
||
// [Padding], T1, T2, ..., Tlast, C1, C2, ... | ||
// ^ points here | ||
// 指向堆内存哈希表末端的 ctrl 区 | ||
ctrl: NonNull<u8>, | ||
|
||
// Number of elements that can be inserted before we need to grow the table | ||
growth_left: usize, | ||
|
||
// Number of elements in the table, only really used by len() | ||
items: usize, | ||
} | ||
``` | ||
|
||
### 扩容和缩容 | ||
|
||
当 HashMap::new() 时,它并没有分配空间,容量为零,随着哈希表不断插入数据,它会以 2 的幂减一的方式增长,最小是3。 | ||
|
||
以 2 的 n 次幂的方式进行扩容,0,3 (22 - 1),7 (23 - 1),14 (24 - 24 * 12.5%),28 (25 - 25 * 12.5%) | ||
|
||
```rust | ||
pub struct HashMap<K, V, S = RandomState> { | ||
base: base::HashMap<K, V, S>, | ||
} | ||
|
||
impl<K, V, S> HashMap<K, V, S> | ||
where | ||
K: Eq + Hash, | ||
S: BuildHasher, | ||
{ | ||
pub fn insert(&mut self, k: K, v: V) -> Option<V> { | ||
self.base.insert(k, v) | ||
} | ||
} | ||
``` | ||
|
||
```rust | ||
impl<K, V, S, A> HashMap<K, V, S, A> | ||
where | ||
K: Eq + Hash, | ||
S: BuildHasher, | ||
A: Allocator, | ||
{ | ||
pub fn insert(&mut self, k: K, v: V) -> Option<V> { | ||
// 哈希,得到一个哈希值 hash | ||
let hash = make_hash::<K, S>(&self.hash_builder, &k); | ||
let hasher = make_hasher::<_, V, S>(&self.hash_builder); | ||
match self | ||
.table | ||
.find_or_find_insert_slot(hash, equivalent_key(&k), hasher) | ||
{ | ||
Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), | ||
Err(slot) => { | ||
unsafe { | ||
self.table.insert_in_slot(hash, slot, (k, v)); | ||
} | ||
None | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
当删除表中的数据时,原有的表大小不变,只有显式地调用 shrink_to_fit,才会让哈希表变小。 | ||
|
||
## HashSet | ||
|
||
```rust | ||
pub struct HashSet<T, S = DefaultHashBuilder, A: Allocator = Global> { | ||
pub(crate) map: HashMap<T, (), S, A>, | ||
} | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use std::collections::HashMap; | ||
|
||
fn main() { | ||
let mut map = HashMap::new(); | ||
explain("empty", &map); | ||
|
||
map.insert("a", 1); | ||
explain("added 1", &map); | ||
|
||
map.insert("b", 2); | ||
map.insert("c", 3); | ||
explain("added 3", &map); | ||
|
||
map.insert("d", 4); | ||
explain("added 4", &map); | ||
|
||
// assert_eq!(map.get("a"), Some(1).as_ref()); | ||
assert_eq!(map.get(&"a"), Some(&1)); | ||
assert_eq!(map.get_key_value(&"b"), Some((&"b", &2))); | ||
|
||
map.remove(&"a"); // 删除后就找不到了 | ||
assert_eq!(map.contains_key(&"a"), false); | ||
assert_eq!(map.get(&"a"), None); | ||
explain("removed", &map); | ||
|
||
// shrink 后哈希表变小 | ||
map.shrink_to_fit(); | ||
explain("shrinked", &map); | ||
} | ||
|
||
fn explain<K, V>(name: &str, map: &HashMap<K, V>) { | ||
println!("{}:len:{},cap:{}", name, map.len(), map.capacity()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
use std::collections::HashSet; | ||
|
||
fn main() { | ||
let mut a: HashSet<i32> = vec![1i32, 2, 3].into_iter().collect(); | ||
let mut b: HashSet<i32> = vec![2i32, 3, 4].into_iter().collect(); | ||
|
||
assert!(a.insert(4)); | ||
assert!(a.contains(&4)); | ||
|
||
// 如果值已经存在,那么 `HashSet::insert()` 返回 false。 | ||
assert!(b.insert(4), "Value 4 is already in set B!"); | ||
// 改正 ^ 将此行注释掉。 | ||
|
||
b.insert(5); | ||
|
||
// 若一个集合(collection)的元素类型实现了 `Debug`,那么该集合也就实现了 `Debug`。 | ||
// 这通常将元素打印成这样的格式 `[elem1, elem2, ...] | ||
println!("A: {:?}", a); | ||
println!("B: {:?}", b); | ||
|
||
// 乱序打印 [1, 2, 3, 4, 5]。 | ||
println!("Union: {:?}", a.union(&b).collect::<Vec<&i32>>()); | ||
|
||
// 这将会打印出 [1] | ||
println!("Difference: {:?}", a.difference(&b).collect::<Vec<&i32>>()); | ||
|
||
// 乱序打印 [2, 3, 4]。 | ||
println!( | ||
"Intersection: {:?}", | ||
a.intersection(&b).collect::<Vec<&i32>>() | ||
); | ||
|
||
// 打印 [1, 5] | ||
println!( | ||
"Symmetric Difference: {:?}", | ||
a.symmetric_difference(&b).collect::<Vec<&i32>>() | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use std::collections::BTreeMap; | ||
|
||
fn main() { | ||
let map = BTreeMap::new(); | ||
let mut map = explain("empty", map); | ||
|
||
for i in 0..16usize { | ||
map.insert(format!("Danny {}", i), i); | ||
} | ||
|
||
let mut map = explain("added", map); | ||
|
||
map.remove("Danny 1"); | ||
|
||
let map = explain("remove 1", map); | ||
|
||
for item in map.iter() { | ||
println!("{:?}", item); | ||
} | ||
} | ||
|
||
// BTreeMap 结构有 height,node 和 length | ||
// 我们 transmute 打印之后,再 transmute 回去 | ||
fn explain<K, V>(name: &str, map: BTreeMap<K, V>) -> BTreeMap<K, V> { | ||
let arr: [usize; 3] = unsafe { std::mem::transmute(map) }; | ||
println!( | ||
"{}: height: {}, root node: 0x{:x}, len: 0x{:x}", | ||
name, arr[0], arr[1], arr[2] | ||
); | ||
unsafe { std::mem::transmute(arr) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "chapter10-error" | ||
version.workspace = true | ||
edition.workspace = true | ||
authors.workspace = true | ||
|
||
[dependencies] | ||
thiserror = "1.0" | ||
|
||
|
||
[[bin]] | ||
name = "error1" | ||
path = "src/error1-transfer.rs" | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.