hashset

hashset说明

天然去除重复元素

创建和初始化

new

use std::collections::HashSet;

fn main() {
    let mut set = HashSet::new();
}

查看容量和长度

use std::collections::HashSet;

fn main() {
    let mut set: HashSet<i32> = HashSet::new();
    println!("初始容量: {}", set.capacity());
    println!("长度: {}", set.len());
    println!("是否为空: {}", set.is_empty());
    
    // 添加一些元素后再看容量
    set.insert(1);
    println!("插入1个元素后的容量: {}", set.capacity());
    
    set.insert(2);
    set.insert(3);
    println!("插入3个元素后的容量: {}", set.capacity());
    println!("长度: {}", set.len());
}
初始容量: 0
长度: 0
是否为空: true
插入1个元素后的容量: 3
插入3个元素后的容量: 3
长度: 3

with_capacity

使用with_capacity预分配容量(性能优化)

use std::collections::HashSet;

fn main() {
    let mut set = HashSet::with_capacity(10);
}

请求容量测试

use std::collections::HashSet;

fn main() {
    for requested in [1, 5, 10, 16, 20, 32] {
        let s: HashSet<i32> = HashSet::with_capacity(requested);
        println!("请求: {}, 实际: {}", requested, s.capacity());
    }
}
请求: 1, 实际: 3
请求: 5, 实际: 7
请求: 10, 实际: 14
请求: 16, 实际: 28
请求: 20, 实际: 28
请求: 32, 实际: 56

数组/vec创建

use std::collections::HashSet;

fn main() {
    // 方式一: 使用from创建
    let set = HashSet::from([1, 2, 3]);

    // 方式二: 使用数组字面量创建
    let set: HashSet<_> = [1, 2, 3, 4].iter().cloned().collect();


    // Vec创建
    let v = vec![1, 2, 3];
    let set = HashSet::from(v); // v因为所有权已被转移
}

元组创建

需要展开为数组

use std::collections::HashSet;

fn main() {
    let t = (1, 2, 3);
    // 方式一
    let set: HashSet<i32> = [t.0, t.1, t.2].iter().cloned().collect();

    // 方式二
    let set: HashSet<i32> = HashSet::from([t.0, t.1, t.2]);
}

切片创建

use std::collections::HashSet;

fn main() {
    let slice: &[i32] = &[1, 2, 3, 4];
    let set: HashSet<i32> = slice.iter().cloned().collect();
    println!("{:?}", set)
}

操作元素

添加元素

insert会返回bool值,如果元素已经存在则返回false(添加失败)

use std::collections::HashSet;

fn main() {
    let mut s = HashSet::new();

    let is_add = s.insert("a");

    println!("is_add: {}", is_add);

    println!("s: {:?}", s);
}
is_add: true
s: {"a"}

批量添加

s.extend(iter), 就地修改s集合,不创建新集合

use std::collections::HashSet;

fn main() {
    let mut s = HashSet::new();
    s.extend(["a", "b", "c"]);

    s.extend(["a", "b", "2222"]); // a和b存在,就不会添加,之后添加2222

    println!("{:?}", s);
}
{"a", "b", "c", "2222"}

删除元素

s.remove(&value)返回bool值,如果元素不存在则返回false(删除失败)

use std::collections::HashSet;

fn main() {
    let mut s1 = HashSet::from([1,2,3,4]);

    let is_del = s1.remove(&23); // 删除23失败,不存在
    println!("{}", is_del);
    println!("{:?}", s1);
}
false
{1, 3, 2, 4}

条件删除

s.retain(|x| x % 2 == 0): 保留偶数

use std::collections::HashSet;

fn main() {
    let mut s1 = HashSet::from([1,2,3,4]);
    
    s1.retain(|&x| x % 2 == 0);

    println!("{:?}", s1)
}
{4, 2}

消费元素

s.take(&value): 删除并返回元素,返回Option<T>

use std::collections::HashSet;

fn main() {
    let mut s = HashSet::from([1,2,3,4]);

    let v1 = s.take(&2);
    println!("v1: {:?}", v1);
    println!("s: {:?}", s);


    let v2 = s.take(&22);
    println!("v2: {:?}", v2);
}
v1: Some(2)
s: {1, 3, 4}
v2: None

查询

查询元素是否存在

set.contains(&value): 需要引用值

use std::collections::HashSet;

fn main() {
    let s = HashSet::from([1,2,3,4]);

    let exists1 = s.contains(&2);

    println!("exists[2]: {}", exists1);

    let exists2 = s.contains(&0);
    println!("exists[0]: {}", exists2);
}
exists[2]: true
exists[0]: false

获取元素

set.get(&value): 需要引用值,返回一个Option<&T>

use std::collections::HashSet;

fn main() {
    let mut s = HashSet::from([1,2,3,4]);

    let v1 = s.get(&2);

    println!("v1: {:?}", v1);
    println!("s: {:?}", s);


    let v2 = s.get(&22);

    println!("v2: {:?}", v2);
}
v1: Some(2)
s: {3, 1, 2, 4}
v2: None

元素数量

set.len()

use std::collections::HashSet;

fn main() {
    let s1 = HashSet::from([1,2,3,4]);
    println!("s1: {}", s1.len());


    let s2:HashSet<i32> = HashSet::new();
    println!("s2: {}", s2.len());
}
s1: 4
s2: 0

set是否为空

set.is_empty()

use std::collections::HashSet;

fn main() {
    let s1 = HashSet::from([1,2,3,4]);
    println!("s1: {}", s1.is_empty());


    let s2:HashSet<i32> = HashSet::new();
    println!("s2: {}", s2.is_empty());
}
s1: false
s2: true

迭代

HashSet的迭代顺序是不确定的

迭代所有元素

use std::collections::HashSet;

fn main() {
    let mut s = HashSet::from([1,2,3,4]);
    // for i in &s
    // i是&i32类型
    for i in s.iter() {
        println!("{}", i);
    };

    print!("{:?}", s)
}
1
3
4
2
{1, 3, 4, 2}%

获取所有权

use std::collections::HashSet;

fn main() {
    let mut s = HashSet::from([1,2,3,4]);
    // i是i32类型
    for i in s.into_iter() {
        println!("{}", i);
    };

    // print!("{:?}", s) // 不能再使用了,s已经被消费了
}
1
3
4
2

集合运算

unionintersectiondifferencesymmetric_difference,不会获取所有权.
它们接受引用参数&self&other_set

交集

a.intersection(&b)表示a在b中的元素

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1,2,3]);
    let b = HashSet::from([2,3,4]);

    // 返回Intersection迭代器
    let c = a.intersection(&b);
    println!("{:?}", c);
    
    // 迭代器转为集合
    let c_set:HashSet<i32> = c.cloned().collect();
    println!("{:?}", c_set);
}
[3, 2]
{2, 3}

并集

a.union(&b)表示ab一起合并去重所有元素

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1,2,3]);
    let b = HashSet::from([2,3,4]);

    // 返回Union迭代器
    let c = a.union(&b);
    println!("{:?}", c);
    
    // 迭代器转为集合
    let c_set:HashSet<i32> = c.cloned().collect();
    println!("{:?}", c_set);
}
[3, 1, 2, 4]
{2, 1, 3, 4}

差集

a.difference(&b)过滤出a没有在b中的元素

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1,2,3]);
    let b = HashSet::from([2,3,4]);

    // 返回Difference迭代器
    let c = a.difference(&b);
    println!("{:?}", c);
    
    // 迭代器转为集合
    let c_set:HashSet<i32> = c.cloned().collect();
    println!("{:?}", c_set)
}
[1]
{1}

对称差集

a.symmetric_difference(&b)过滤出a和b中不重复的所有元素(包括b)

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1,2,3]);
    let b = HashSet::from([2,3,4]);

    // 返回SymmetricDifference迭代器
    let c = a.symmetric_difference(&b);
    println!("{:?}", c);
    
    // 迭代器转为集合
    let c_set:HashSet<i32> = c.cloned().collect();
    println!("{:?}", c_set)
}
[1, 4]
{1, 4}

集合关系

子集

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1, 2, 3, 4, 5]);
    let b = HashSet::from([2, 3, 4]);

    // 返回bool迭代器
    let s = b.is_subset(&a);
    println!("b是a的子集: {}", s)
}
b是a的子集: true

超集

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1, 2, 3, 4, 5]);
    let b = HashSet::from([2, 3, 4]);

    // 返回bool迭代器
    let s = a.is_superset(&b);
    println!("a是b的超集: {}", s)
}
a是b的超集: true

不相交关系

两个集合没有公共元素

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1, 2, 3, 4, 5]);
    let b = HashSet::from([21, 31, 41]);

    // 返回bool迭代器
    let s = a.is_disjoint(&b);
    println!("a和b不相交: {}", s)
}
a和b不相交: true

相等

use std::collections::HashSet;

fn main() {
    let a = HashSet::from([1, 2, 3, 4, 5]);
    let b = HashSet::from([1, 2, 3, 4, 5]);

    println!("a和b相等: {}",  a == b);
}
a和b相等: true

自定义数据实现hash

HashSet需要元素实现

  • Hash - 计算哈希值,快速定位桶位置
  • PartialEq - 解决哈希冲突时比较是否真正相等
  • Eq - 标记 trait,保证相等关系的数学性质
use std::hash::{Hash, Hasher};
use std::collections::HashSet;

#[derive(Debug)]
struct Key {
    id: u32,
    name: String,
}

// 必须实现 Hash
impl Hash for Key {
    fn hash<H: Hasher>(&self, state: &mut H) {
        println!("  Hash::hash called for {:?}", self);
        self.id.hash(state);
        self.name.hash(state);
    }
}

// 必须实现 PartialEq
impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        println!("  PartialEq::eq called: {:?} vs {:?}", self, other);
        self.id == other.id && self.name == other.name
    }
}

// 必须实现 Eq(标记 trait)
impl Eq for Key {}

fn main() {
    let mut map = HashSet::new();
    
    println!("Inserting first key:");
    let key1 = Key { id: 1, name: "Alice".to_string() };
    map.insert(key1);
    
    let key2 = Key { id: 1, name: "Alice Modified".to_string() };
    map.insert(key2);
    
    println!("set: {:?}", map);
}
Inserting first key:
  Hash::hash called for Key { id: 1, name: "Alice" }
  Hash::hash called for Key { id: 1, name: "Alice Modified" }
set: {Key { id: 1, name: "Alice Modified" }, Key { id: 1, name: "Alice" }}
posted @ 2026-04-14 02:09  lxd670  阅读(8)  评论(0)    收藏  举报