Rust中的容器(二)
前言
在Rust中的容器(一)中,列举了Rust中的容器以及详聊了vector和Hashmap,本章将展示后续提及的容器用法。
双端队列:VecDeque
链表:LinkedList
映射:BtreeMap
集合:HashSet,BtreeSet
其他:BinaryHeap
双端队列:VecDeque
Rust的VecDeque是使用可增长的ringbuffer实现的(即头尾相接的队列,首尾指针各自定位,可根据数据push的数量进行扩容)
使用方法:
- 可以使用数组转换成双端队列
use std::collections::VecDeque;
fn main() {
let deq = VecDeque::from([-1, 0, 1]);
println!("{:?}", deq);
}
- 双端队列使用方法集合:
use std::collections::VecDeque;
fn main() {
let mut deque: VecDeque<u32> = VecDeque::new(); //初始化
deque.push_back(1);
let mut buf: VecDeque<u32> = VecDeque::with_capacity(10); //初始化容量大小
buf.push_back(3);
buf.push_back(4);
buf.push_back(5);
buf.push_back(6);
assert_eq!(buf.get(1), Some(&4)); //可以通过index获取数据
if let Some(elem) = buf.get_mut(1) {
//可通过get_mut将内部数据更改
*elem = 7;
}
assert_eq!(buf[1], 7);
buf.swap(0, 2); //可通过swap根据index,交换数据
assert_eq!(buf, [5, 7, 3, 6]);
deque.reserve(10);
assert!(deque.capacity() >= 11);
let mut buf1 = VecDeque::new();
buf1.push_back(5);
buf1.push_back(3);
buf1.push_back(4);
let b: &[_] = &[&5, &3, &4];
let c: Vec<&i32> = buf1.iter().collect(); //iter迭代器,可转换到vector
assert_eq!(&c[..], b);
assert_eq!(buf1.len(), 3); //通过len获取长度
assert!(!buf1.is_empty());
let mut deque: VecDeque<_> = [1, 2, 3].into();
for v in deque.range_mut(..) {
//使用range mut可创建范围iter,并可更新其元素
*v *= 2;
}
assert_eq!(deque, [2, 4, 6]);
deque.clear(); //使用clear清空队列
assert!(deque.is_empty());
deque.push_back(1);
assert_eq!(deque.contains(&1), true); //contains查看是否包含某元素
deque.push_back(2);
assert_eq!(deque.front(), Some(&1)); //front 队头元素
deque.push_back(2);
assert_eq!(deque.back(), Some(&2)); //back队尾元素
assert_eq!(deque.pop_front(), Some(1)); //pop_front弹出队首元素
deque.push_back(3);
assert_eq!(deque.pop_back(), Some(3)); //pop_back弹出队尾元素
deque.push_front(2); //头插
assert_eq!(deque.front(), Some(&2));
deque.push_back(3); //尾插
assert_eq!(3, *deque.back().unwrap());
assert_eq!(deque.remove(1), Some(2)); //删除某元素,并返回所在index
let mut buf: VecDeque<_> = [1, 2].into();
let mut buf2: VecDeque<_> = [3, 4].into();
buf.append(&mut buf2); //将数组2追加到数组1的末尾。
assert_eq!(buf, [1, 2, 3, 4]);
}
ps: 例子来源于rust标准库,这里作收集整理。
链表 Linklist
It is almost always better to use Vec or VecDeque because array-based containers are generally faster, more memory efficient, and make better use of CPU cache.
使用动态数组和双端队列几乎总是最好的选择,他们通常更快,内存效率更高,更好的利用CPU缓存。
代码如下(示例):
fn main() {
let mut list1 = LinkedList::from(['q', 'w', 'e']); // 可以从数组初始化双向链表
list1.push_back('a'); //后插
println!("{:?}", list1);
assert!(!list1.is_empty()); //是否为空
println!("{:?}", list1.len()); //长度
list1.clear(); //清空
assert!(list1.is_empty());
list1.push_front('t');
list1.push_front('l');
list1.push_front('a'); //前插
assert!(list1.contains(&'a')); //是否包含某个元素
println!("{:?}", list1.front());
assert_eq!(list1.pop_front(), Some('a'));//弹出首部元素
assert_eq!(list1.pop_back(), Some('t')); //弹出尾部元素
}
B树map(BTreeMap)
代码示例:(示例来源rust标准库)
use std::collections::BTreeMap;
// type inference lets us omit an explicit type signature (which
// would be `BTreeMap<&str, &str>` in this example).
let mut movie_reviews = BTreeMap::new();
// review some movies.
movie_reviews.insert("Office Space", "Deals with real issues in the workplace.");
movie_reviews.insert("Pulp Fiction", "Masterpiece.");
movie_reviews.insert("The Godfather", "Very enjoyable.");
movie_reviews.insert("The Blues Brothers", "Eye lyked it a lot.");
// check for a specific one.
if !movie_reviews.contains_key("Les Misérables") {
println!("We've got {} reviews, but Les Misérables ain't one.",
movie_reviews.len());
}
// oops, this review has a lot of spelling mistakes, let's delete it.
movie_reviews.remove("The Blues Brothers");
// look up the values associated with some keys.
let to_find = ["Up!", "Office Space"];
for movie in &to_find {
match movie_reviews.get(movie) {
Some(review) => println!("{movie}: {review}"),
None => println!("{movie} is unreviewed.")
}
}
// Look up the value for a key (will panic if the key is not found).
println!("Movie review: {}", movie_reviews["Office Space"]);
// iterate over everything.
for (movie, review) in &movie_reviews {
println!("{movie}: \"{review}\"");
}
HashSet
hashset就是value为()的hashmap
代码示例:
use std::collections::HashSet;
// Type inference lets us omit an explicit type signature (which
// would be `HashSet<String>` in this example).
let mut books = HashSet::new();
// Add some books.
books.insert("A Dance With Dragons".to_string());
books.insert("To Kill a Mockingbird".to_string());
books.insert("The Odyssey".to_string());
books.insert("The Great Gatsby".to_string());
// Check for a specific one.
if !books.contains("The Winds of Winter") {
println!("We have {} books, but The Winds of Winter ain't one.",
books.len());
}
// Remove a book.
books.remove("The Odyssey");
// Iterate over everything.
for book in &books {
println!("{book}");
}
BtreeSet
btreeset 既使用btree实现的有序集合。
代码示例:
use std::collections::BTreeSet;
// Type inference lets us omit an explicit type signature (which
// would be `BTreeSet<&str>` in this example).
let mut books = BTreeSet::new();
// Add some books.
books.insert("A Dance With Dragons");
books.insert("To Kill a Mockingbird");
books.insert("The Odyssey");
books.insert("The Great Gatsby");
// Check for a specific one.
if !books.contains("The Winds of Winter") {
println!("We have {} books, but The Winds of Winter ain't one.",
books.len());
}
// Remove a book.
books.remove("The Odyssey");
// Iterate over everything.
for book in &books {
println!("{book}");
}
BinaryHeap
用二叉堆实现的优先队列
代码示例:
use std::collections::BinaryHeap;
// Type inference lets us omit an explicit type signature (which
// would be `BinaryHeap<i32>` in this example).
let mut heap = BinaryHeap::new();
// We can use peek to look at the next item in the heap. In this case,
// there's no items in there yet so we get None.
assert_eq!(heap.peek(), None);
// Let's add some scores...
heap.push(1);
heap.push(5);
heap.push(2);
// Now peek shows the most important item in the heap.
assert_eq!(heap.peek(), Some(&5));
// We can check the length of a heap.
assert_eq!(heap.len(), 3);
// We can iterate over the items in the heap, although they are returned in
// a random order.
for x in &heap {
println!("{x}");
}
// If we instead pop these scores, they should come back in order.
assert_eq!(heap.pop(), Some(5));
assert_eq!(heap.pop(), Some(2));
assert_eq!(heap.pop(), Some(1));
assert_eq!(heap.pop(), None);
// We can clear the heap of any remaining items.
heap.clear();
// The heap should now be empty.
assert!(heap.is_empty())
Ps:本文示例均来源于rust标准库,后续有计划分享内部实现细节。