rust容器

标准库提供了常见的容器。包括向量 ( Vector )、映射( HashMap )、集合( HashSet )。

一、向量Vector

数组有一个缺点,就是它的长度在编译时就确定了,一旦确定就永不可更改。

向量是一个长度可变的数组。向量的存储在堆上,因此长度可变。

Rust在标准库中定义了结构体Vec用于表示向量。

(一)定义向量

一维向量

1.new()创建一个空向量

语法格式

let mut instance_name: Vec<T> = Vec::new();
例子
let v1: Vec<i32> = Vec::new(); // 创建类型为i32的空向量

2.vec!()宏创建向量

这种方式的创建方法类似于数组的语法。

它也有3种创建方式。

(1)创建空向量。需要指定类型。

let mut vec_marco: Vec<i32> = vec![];

(2)指定所有元素。可以省略类型。

let mut vec_marco = vec![1, 2, 3, 4, 5];

(3)指定初始值和长度。可以省略类型。

let mut vec_marco = vec![0; 5];     // 长度为5,元素初始化为0

注意,长度可以是变量,这点与数组不同。

例子

let len = 10;
let zero_vec = vec![0; len];

3.从数组创建向量

let arr = [1, 2, 3, 4, 5];
let v = arr.to_vec();

二维向量

1.使用new()创建空向量。需要指定类型。

let mut instance_name: Vec<Vec<T>> = Vec::new();
例子
let v1: Vec<Vec<i32>> = Vec::new();

2.使用vec!()宏创建向量

(1)创建空向量。需要指定类型。

let mut vec_marco: Vec<Vec<i32>> = vec![];

(2)指定所有元素。可以省略类型。

let mut vec_marco = vec![vec![1, 2, 3, 4, 5], ...];

(3)指定初始值和长度。可以省略类型。

let mut vec_marco = vec![vec![0; 5]; 10];
例子
let width = 4;
let height = 4;
let mut array = vec![vec![0; width]; height];

3.从二维数组创建二维向量

例如

let s = [
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
];
let s: Vec<_> = s.iter().map(|&e| e.to_vec()).collect();

(二)使用向量

1.获取长度

len()方法

例子

fn main() {
    let v = vec![1, 2, 3];
    println!("{}", v.len());
    let width = 4;
    let height = 4;
    let array = vec![vec![0; width]; height];
    println!("{} {}", array.len(), array[0].len());
}
运行结果如下
3
4 4

2.添加元素

使用push方法来追加单个元素

实例

fn main() {
    let mut vector = vec![1, 2, 4, 8];
    vector.push(16);
    vector.push(32);
    vector.push(64);
    println!("{:?}", vector);
    let mut arr: Vec<Vec<i32>> = Vec::new();
    arr.push(Vec::new());
    arr.push(vec![]);
    arr[0].push(1);
    println!("{:?}", arr);
}
运行结果:
[1, 2, 4, 8, 16, 32, 64]
[[1], []]

使用append方法用于将一个向量拼接到另一个向量的尾部

实例

fn main() {
    let mut v1: Vec<i32> = vec![1, 2, 4, 8];
    let mut v2: Vec<i32> = vec![16, 32, 64];
    v1.append(&mut v2);
    println!("{:?}", v1);
}
运行结果:
[1, 2, 4, 8, 16, 32, 64]

2.删除元素

使用remove()删除元素

remove() 方法移除并返回向量中指定的下标索引处的元素,将其后面的所有元素移到向左移动一位。

fn main() {
    let mut v = vec![10,20,30];
    v.remove(1);
    println!("{:?}",v);
}
运行结果如下
[10, 30]

clear

删除所有元素

let mut v = vec![10,20,30];
v.clear();
println!("{:?}",v);

3.获取元素

因为向量实现了Deref Target=[T],所以向量自动实现了切片的所有方法。

(1)使用get方法

get方法根据索引返回对元素或子切片的引用。

如果给定位置,则返回该位置上的元素的引用,如果越界则返回None。

如果给定范围,则返回对应于该范围的子切片,如果越界则返回None。

例子

let v = vec![10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));

(2)get_mut

get_mut方法根据索引返回对元素或子切片的可变引用

如果给定位置,则返回该位置上的元素的可变引用,如果越界则返回None。

如果给定范围,则返回对应于该范围的可变子切片,如果越界则返回None。

例子

let mut x = vec![0, 1, 2];
if let Some(elem) = x.get_mut(1) {
    *elem = 42;
}
assert_eq!(x, &[0, 42, 2]);

(3)使用[]

实例

fn main() {
    let v = vec![1, 2, 4, 8];
    println!("{}", v[1]);
}
运行结果:
2

二维向量

array[2][2] = 5;
println!("{:?}", array);

例子

use std::io;
fn main(){
    let width = 4;
    let height = 4;
    let mut array = vec![vec![0; width]; height];
    for i in 0..4 {
         let mut buf = String::from("");
         io::stdin().read_line(&mut buf).unwrap();
         array[i] = buf.split_whitespace().map(|s| s.parse().unwrap()).collect();
    }
    println!("{:?}", array);
}

4.遍历向量

(1)使用索引

fn main() {
    let v = vec![100, 32, 57];
    for i in 0..v.len() {
            println!("{}", v[i]);
    }
}

(2)使用向量的引用

实例

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
            println!("{}", i);
    }
}
运行结果:
100
32
57

实例

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
    println!("{:?}", v);
}

(3)使用迭代器

iter()返回一个只读迭代器

for num in nums1.iter() {
     print!("{} ", num);
}
println!();

iter_mut()返回一个可写迭代器

let mut nums1 = [1; 5];
let mut i = 0;
for num in nums1.iter_mut() {
     *num = i;
     i += 1;
}
println!("{:?}", nums1);

into_iter()返回一个迭代器,但是转让所有权

let mut nums1 = [1; 5];
for num in nums1.into_iter() {
    print!("{} ", num);
}
println!();

for num in nums1.into_iter()

实际上等价于

for num in nums1

(4)使用迭代器的enumerate

let mut nums1 = [1; 5];
for (pos, v) in nums1.iter().enumerate() {
    println!("nums[{}]={}", pos, v);
}
println!("{:?}", nums1);
for (pos, v) in nums1.iter_mut().enumerate() {
    *v=pos;
    println!("nums[{}]={}", pos, v);
}
println!("{:?}", nums1);

二维向量

(1)使用索引

let mut v = vec![vec![1, 2, 3, 4, 5], vec![3, 9, 8]];
for i in 0..v.len() {
    for j in 0..v[i].len() {
         println!("{}", v[i][j]);
    }
}

(2)使用引用

例子

let s = [
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
];
let mut s: Vec<_> = s.iter().map(|&e| e.to_vec()).collect();
for row in &s{
    for col in row{
         print!("{} ", col);
    }
    println!();
}
for row in &mut s {
    for col in row {
         *col += 1;
         print!("{} ", col);
    }
    println!();
}

(3)使用向量的迭代器

let mut grid = [[0; 5]; 5];
for row in grid.iter() {
    for col in row.iter() {
         print!("{} ", col);
    }
    println!();
}
let mut i = 0;
for row in grid.iter_mut(){
    for col in row.iter_mut() {
         *col = i;
         i += 1;
         print!("{} ", col);
    }
    println!();
}

(4)使用迭代器的enumerate

let mut grid = [[0; 5]; 5];
for (i, row) in grid.iter().enumerate() {
    for (j, col) in row.iter().enumerate() {
         print!("{}", col);
    }
    println!()
}
for (i, row) in grid.iter_mut().enumerate() {
    for (j, col) in row.iter_mut().enumerate() {
         *col = 1;
    }
}

6.使用contains() 判断向量是否包含某个元素

如果值在向量中存在则返回 true ,否则返回 false 。

fn main() {
     let v = vec![10,20,30];
     if v.contains(&10) {
         println!("found 10");
     }
     println!("{:?}",v);
}
运行结果如下
found 10
[10, 20, 30]

7.逆转向量

reverse
适当地反转切片中元素的顺序。
例子
let mut v = [1, 2, 3];
v.reverse();
assert!(v == [3, 2, 1]);

二、映射HashMap

映射表(Map)在其他语言中广泛存在。其中应用最普遍的就是散列映射表(Hash Map)。

HashMap就是 键值对 的集合。映射表中不允许有重复的键,但允许不同的键有相同的值。

Rust语言定义了HashMap结构体来表示映射表。

HashMap结构体定义在std::collections模块中,使用之前需要导入std::collections模块。

(一)定义映射表

1.使用new创建空映射表

语法格式如下

let mut instance_name: HashMap<type1, type2> = HashMap::new();

实例

use std::collections::HashMap;
let mut map: HashMap<&str, i32> = HashMap::new();
let mut map = HashMap::new();//可以省略类型

2.可以从数组初始化HashMap

例子

use std::collections::HashMap;
let solar_distance = HashMap::from([
("Mercury", 0.4),
("Venus", 0.7),
("Earth", 1.0),
("Mars", 1.5),
]);

(二)使用映射表

1.使用len()获取键值对的个数

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     println!("size of map is {}",stateCodes.len());
}
编译运行结果如下
size of map is 2

2.添加键值对

使用insert()方法用于插入或更新一个键值对

如果键已经存在,则更新为新的值,并则返回旧的值。

如果键不存在则执行插入操作并返回None 。

例子

fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", "10 m^2");
    println!("{}", map.get("color").unwrap());
}
运行结果:
red

3.删除指定键值对

remove()用于从映射表中删除指定的键值对。

如果键值对存在则返回删除的键值对,返回的数据格式为 (&'a K, &'a V) 。

如果键值对不存在则返回None

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     stateCodes.insert("slogn","简单教程,简单编程");
     println!("length of the hashmap {}",stateCodes.len());
     stateCodes.remove(&"site");
     println!("length of the hashmap after remove() {}",stateCodes.len());
}
编译运行结果如下
length of the hashmap 3
length of the hashmap after remove() 2

clear

清除map,删除所有键值对。

例子

use std::collections::HashMap;
let mut a = HashMap::new();
a.insert(1, "a");
a.clear();
assert!(a.is_empty());

4.根据键获取相应的值

使用get()方法获取键相应的值。

如果值不存在,则返回None 。

如果值存在,则返回值的一个引用。

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     println!("size of map is {}",stateCodes.len());
     println!("{:?}",stateCodes);
     match stateCodes.get(&"name") {
         Some(value)=> {
             println!("Value for key name is {}",value);
          }
          None => {
              println!("nothing found");
          }
     }
}
编译运行结果如下
size of map is 2
{"name": "简单教程", "site": "https://www.twle.cn"}
Value for key name is简单教程

get_mut

实例

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert(1, "a");
    if let Some(x) = map.get_mut(&1) {
        *x = "b";
    }
}

get_key_value

例子

use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(1, "a");
assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
assert_eq!(map.get_key_value(&2), None);

5.遍历映射表

(1)使用引用

for (book, review) in &book_reviews {
     println!("{book}: \"{review}\"");
}

for (book, review) in &mut book_reviews {
    *review = 0;
     println!("{book}: \"{review}\"");
}

(2)使用迭代器

iter()方法会返回映射表中 键值对的引用组成的无序迭代器。

迭代器元素的类型为 (&'a K, &'a V) 。

实例

use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert("color", "red");
    map.insert("size", "10 m^2");
    for p in map.iter() {
        println!("{:?}", p);
    }
}
运行结果:
("color", "red")
("size", "10 m^2")
迭代元素是表示键值对的元组。

iter_mut

例子

use std::collections::HashMap;
let mut map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
// 更新所有值
for (_, val) in map.iter_mut() {
     *val *= 2;
}

6.是否包含指定的键

contains_key()方法用于判断映射表中是否包含指定的键值对。

如果包含指定的键,那么会返回相应的值的引用,否则返回None 。

例子

use std::collections::HashMap;
fn main() {
     let mut stateCodes = HashMap::new();
     stateCodes.insert("name","简单教程");
     stateCodes.insert("site","https://www.twle.cn");
     stateCodes.insert("slogn","简单教程,简单编程");
     if stateCodes.contains_key(&"name") {
         println!("found key");
     }
}
编译运行结果如下
found key

7.entry

entry方法返回键值对

例子

use std::collections::HashMap;
let mut player_stats = HashMap::new();
fn random_stat_buff() -> u32 {
     42
}
player_stats.entry("health").or_insert(100);     // 没有就插入,有就跳过
player_stats.entry("defence").or_insert_with(random_stat_buff);     //没有就插入,有就跳过
let stat = player_stats.entry("attack").or_insert(100);     //没有就插入,返回值的引用
*stat += random_stat_buff();
player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100);     // 有就加200,没有就插入100
println!("{:?}", player_stats);

9.自定义键类型

派生Eq和Hash。 我们还必须导出PartialEq。

例子

use std::collections::HashMap;
#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
     name: String,
     country: String,
}
impl Viking {
     /// 创建一个新的Viking。
     fn new(name: &str, country: &str) -> Viking {
         Viking { name: name.to_string(), country: country.to_string() }
     }
}
// 使用HashMap存储Viking的健康点。
let vikings = HashMap::from([
(Viking::new("Einar", "Norway"), 25),
(Viking::new("Olaf", "Denmark"), 24),
(Viking::new("Harald", "Iceland"), 12),
]);
// 使用派生的实现来打印Viking的状态。
for (viking, health) in &vikings {
     println!("{viking:?} has {health} hp");
}

10.其他

keys

返回一个迭代器,以任意顺序访问所有键。 迭代器元素类型为 &'a K。

例子

use std::collections::HashMap;
let map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
for key in map.keys() {
     println!("{key}");
}

values

返回一个以任意顺序访问所有值的迭代器。 迭代器元素类型为 &'a V。

例子

use std::collections::HashMap;
let map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
for val in map.values() {
     println!("{val}");
}

is_empty

如果map不包含任何元素,则返回true。

例子

use std::collections::HashMap;
let mut a = HashMap::new();
assert!(a.is_empty());
a.insert(1, "a");
assert!(!a.is_empty());

三、集合HashSet

HashSet是没有重复值的相同数据类型的值的集合。

Rust语言标准库std::collections中定义了结构体HashSet用于描述集合。

(一)定义集合

1.new()创建一个空集合

语法格式如下

let mut hash_set_name = HashSet::new();

2.可以从数组初始化HashSet:

use std::collections::HashSet;
let viking_names = HashSet::from(["Einar", "Olaf", "Harald"]);

(二)使用集合

1.获取集合的长度len()

len() 方法用于获取集合的长度,也就是集合中元素的个数。

范例

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     println!("size of the set is {}",languages.len());
}
编译运行结果如下
size of the set is 4

2.添加元素

insert() 用于插入一个值到集合中,如果集合中已经存在指定的值,则返回 false ,否则返回 true 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     languages.insert("Rust"); // 插入失败但不会引发异常
     println!("{:?}",languages);
}
编译运行结果如下
{"Python", "PHP", "Rust", "Ruby"}

3.删除集合元素

remove() 方法用于从集合中删除指定的值。

删除之前如果值 value 存在于集合中则返回 true ,如果不存在则返回 false 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     println!("length of the Hashset: {}",languages.len());
     languages.remove(&"Kannan");
     println!("length of the Hashset after remove() : {}",languages.len());
}
编译运行结果如下
length of the Hashset: 3
length of the Hashset after remove() : 3

clear

删除所有值。

例子

use std::collections::HashSet;
let mut v = HashSet::new();
v.insert(1);
v.clear();
assert!(v.is_empty());

4.获取元素

get() 方法用于获取集合中指定值的一个引用。

如果值 value 存在于集合中则返回集合中的相应值的一个引用,否则返回 None 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     match languages.get(&"Rust"){
         Some(value)=>{
              println!("found {}",value);
          }
          None =>{
              println!("not found");
          }
     }
     println!("{:?}",languages);
}
编译运行结果如下
found Rust
{"Python", "Ruby", "PHP", "Rust"}

take

删除并返回集合中等于给定值的值 (如果有)。

该值可以是集合值类型的任何借用形式,但是借用形式上的Hash和Eq必须与值类型的那些匹配。

例子

use std::collections::HashSet;
let mut set = HashSet::from([1, 2, 3]);
assert_eq!(set.take(&2), Some(2));
assert_eq!(set.take(&2), None);

5.遍历集合

(1)使用引用

for book in &books {
     println!("{book}");
}

(2)使用迭代器

iter()方法用于返回集合中所有元素组成的无序迭代器。

迭代器元素的顺序是无序的,毫无规则的。而且每次调用iter() 返回的元素顺序都可能不一样。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     languages.insert("PHP");
     for language in languages.iter() {
         println!("{}",language);
     }
}
编译运行结果如下
PHP
Python
Rust
Ruby

6.判断集合是否包含某个值

contains() 方法用于判断集合是否包含指定的值。

如果值 value 存在于集合中则返回 true ,否则返回 false 。

例子

use std::collections::HashSet;
fn main() {
     let mut languages = HashSet::new();
     languages.insert("Python");
     languages.insert("Rust");
     languages.insert("Ruby");
     if languages.contains(&"Rust") {
         println!("found language");
     }
}
编译运行结果如下
found language

7.自定义类型

派生Eq和Hash。我们还必须导出PartialEq,这将在Eq中隐含在future中。

use std::collections::HashSet;
#[derive(Hash, Eq, PartialEq, Debug)]
struct Viking {
     name: String,
     power: usize,
}
let mut vikings = HashSet::new();
vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
vikings.insert(Viking { name: "Einar".to_string(), power: 9 });
vikings.insert(Viking { name: "Olaf".to_string(), power: 4 });
vikings.insert(Viking { name: "Harald".to_string(), power: 8 });
for x in &vikings {
     println!("{x:?}");
}

8.其他

is_empty

如果集合不包含任何元素,则返回true。

例子

use std::collections::HashSet;
let mut v = HashSet::new();
assert!(v.is_empty());
v.insert(1);
assert!(!v.is_empty());

union

访问表示并集的值,即self或other中的所有值,没有重复项。

例子

use std::collections::HashSet;
let a = HashSet::from([1, 2, 3]);
let b = HashSet::from([4, 2, 3, 4]);
// 以任意顺序打印1、2、3、4。
for x in a.union(&b) {
println!("{x}");
}
let union: HashSet<_> = a.union(&b).collect();
assert_eq!(union, [1, 2, 3, 4].iter().collect());

intersection

访问表示相交的值,即self和other中的值。

当self和other中存在相等的元素时,生成的Intersection可能会引用其中一个。 如果T包含未通过其Eq实现进行比较的字段,并且可能在两组T的两个相等副本之间保持不同的值,则这可能是相关的。

例子

use std::collections::HashSet;
let a = HashSet::from([1, 2, 3]);
let b = HashSet::from([4, 2, 3, 4]);
// 以任意顺序打印2,3。
for x in a.intersection(&b) {
println!("{x}");
}
let intersection: HashSet<_> = a.intersection(&b).collect();
assert_eq!(intersection, [2, 3].iter().collect());

is_subset

如果集合是另一个集合的子集,则返回true,即other至少包含self中的所有值。

例子

use std::collections::HashSet;
let sup = HashSet::from([1, 2, 3]);
let mut set = HashSet::new();
assert_eq!(set.is_subset(&sup), true);
set.insert(2);
assert_eq!(set.is_subset(&sup), true);
set.insert(4);
assert_eq!(set.is_subset(&sup), false);

is_superset

如果集合是另一个集合的超集,则返回true,即self至少包含other中的所有值。

例子

use std::collections::HashSet;
let sub = HashSet::from([1, 2]);
let mut set = HashSet::new();
assert_eq!(set.is_superset(&sub), false);
set.insert(0);
set.insert(1);
assert_eq!(set.is_superset(&sub), false);
set.insert(2);
assert_eq!(set.is_superset(&sub), true);
相关推荐
xiaoshiguang34 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
别NULL4 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇4 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
yuanbenshidiaos5 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习5 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA6 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo6 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc6 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
游是水里的游7 小时前
【算法day20】回溯:子集与全排列问题
算法