[Rust学习:四] Vec和栈
[Rust学习:四] Vec和栈
- 一、前言
- 二、阅读Vec源码尝试常用接口。
- 1. 创建Vec
- 2. 在尾部添加push\extend\append
- 3. 任意位置添加insert
- 4. 在尾部删除pop/split_off
- 5. 在任意部位删除remove/swap_remove
- 三、练习栈
- 1. 习题 1106. 解析布尔表达式
- 2. 题解
- 3. 代码实现
- 四、练习swap_remove(其实pop+替换更好)
- 1. 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
- 2. 题解
- 3. 代码实现
- 六、参考链接
一、前言
- 本文练习了栈的用法,顺便练习了match,还顺便练习了loop{break i}操作。
- 学习了一波Vec的接口。
- match写法:
match c{'f' => nums.push(0),'t' => nums.push(1),'(' => nums.push(-1),_ => (), // 注意,必须写未匹配的部分,否则会报错。}
- 另外注意,Vec的pop操作返回的是Some类型,要么用Some包一下,要么直接unwrap(),才能用。
- 找了一圈,标准库里并没有
栈
这个玩意,但是好在我们可以用Vec或者VecDeque模拟。
二、阅读Vec源码尝试常用接口。
1. 创建Vec
let mut vec = Vec::new(); // 创建一个无类型的vec,当第一次push后类型才会被推断出来,因此直接print会报错let mut vec = vec![1,2,3]; // 创建一个i32的vec:[1,2,3]let mut vec = vec![1;5]; // 创建一个长度为5的i32的vec:[1,1,1,1,1]// vec还可以从各种集合类型里转换而来assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); // "vec_from_array", since = "1.44.0"assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); // "rust1", since = "1.0.0"let o: Cow<[i32]> = Cow::Owned(vec![1, 2, 3]);let b: Cow<[i32]> = Cow::Borrowed(&[1, 2, 3]); assert_eq!(Vec::from(o), Vec::from(b)); // "vec_from_cow_slice", since = "1.14.0"assert_eq!(Vec::from("123"), vec![b'1', b'2', b'3']); // "rust1", since = "1.0.0")let b: Box<[i32]> = vec![1, 2, 3].into_boxed_slice();assert_eq!(Vec::from(b), vec![1, 2, 3]); // "vec_from_box", since = "1.18.0"assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); // "vec_from_mut", since = "1.19.0")
2. 在尾部添加push\extend\append
let mut vec1 = vec![1,2,3]; // 创建一个i32的vec:[1,2,3]vec1.push(4); // [1,2,3,4]vec1.pop(); // [1,2,3]let mut vec2 = Vec::from(vec1.clone()); // [1, 2, 3] 注意如果不clone会使vec1失效// vec1.extend(vec2); // vec1:[1, 2, 3, 1, 2, 3] ,注意 本操作会导致vec2失效.since = "1.6.0"// vec1.append(&mut vec2); // vec1:[1, 2, 3, 1, 2, 3] vec2:[];注意实参&mut,会把vec2的所有数据倒进vec1。内部调用了一个append)elements方法。 since = "1.4.0"
3. 任意位置添加insert
这个操作很明显是O(n)的,慎用。
let mut vec1 = vec![1,2,3]; // 创建一个i32的vec:[1,2,3]vec1.insert(1,5); // [1, 5, 2, 3]
4. 在尾部删除pop/split_off
// 在尾部删除 pop/split_offlet mut vec1 = vec![1,2,3]; // 创建一个i32的vec:[1,2,3]let p = vec1.pop(); // vec1:[1, 2], p = Some(3)let p = vec1.pop().unwrap(); // vec1:[1], p = 2let mut vec1 = vec![1,2,3]; // 创建一个i32的vec:[1,2,3]let vec2 = vec1.split_off(1); // vec1:[1] vec2:[2,3],从下标1把vec1切开,返回尾巴
5. 在任意部位删除remove/swap_remove
- swap_remove其实是一个不常用的随机集合删除优化,当不需要保持元素顺序,但又想随机化访问列表中的元素时,可以使用本方法,即我们删除一个元素时,把数组尾巴拿过来替换这个位置,实际删除尾巴,这样可以把复杂度降低到O(1)。
- 应用:假设要设计一个随机元素访问的集合,但又要支持O(1)的删除/添加操作,就可以用这个方法。例题381. O(1) 时间插入、删除和获取随机元素 - 允许重复
// 在任意位置删除 remove/swap_removelet mut vec1 = vec![1,2,3,4]; // 创建一个i32的vec:[1,2,3,4]let p = vec1.remove(1); // 删除下标1的元素:vec:[1,3,4],p=2let p = vec1.swap_remove(0); // 删除下标0的元素且用4替换这个位置:vec:[4,3],p=1
三、练习栈
1. 习题 1106. 解析布尔表达式
- 1106. 解析布尔表达式
2. 题解
- 运算表达式的题,通常可以用双栈(数字栈和运算符栈)来方便地解决。
- 本题是这类题中较简单的一题,只有三个运算符,分类讨论即可。
- 当遇到’f\t’时,数字栈中入栈0或1。
- 特别的,当遇到左括号’('时,数字栈入一个-1,来标志这一段结束了。
- 当遇到运算符时,入运算符栈。
- 当遇到右括号’)',代表该运算了,这里分类讨论即可。
3. 代码实现
impl Solution {pub fn parse_bool_expr(expression: String) -> bool {let mut nums = vec![0;0]; // 数字栈 let mut ops:Vec<char> = vec![]; // 运算符栈for c in expression.chars(){match c{'f' => nums.push(0),'t' => nums.push(1),'(' => nums.push(-1),'&'|'|'|'!' => {ops.push(c)},')' =>{// let op = ops.pop().unwrap();match ops.pop().unwrap() {'!'=> {let p = nums.pop().unwrap();nums.pop();nums.push(p^1); },'&'=>{let mut p = 1;let ans = loop{let top = nums.pop().unwrap();if top == -1{break p;}p &= top;};nums.push(ans);},'|' => {let mut p = 0;let ans = loop{let top = nums.pop().unwrap();if top == -1{break p ;}p |= top;};nums.push(ans);},_ =>(),}},_ => (),}}return nums[0] == 1;}
}
四、练习swap_remove(其实pop+替换更好)
1. 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
- 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
2. 题解
- 这是一道业务实现题。
- 由于需要随机化获取一个值,为了保证概率相同,需要所有数据放到vec中,随机产生一个范围内下标即可。
- 那如何才能实现O(1)的删除呢,就用到了swap_remove这个技巧,由于元素顺序不重要,因此删除一个元素时,把末位数字替换过来,实际删除尾巴即可实现O(1)操作。
- 其余的部分就是需要哈希表实现O(1)的查找、插入,记录每个元素对应的所有下标即可。
3. 代码实现
use std::collections::*;
use rand::Rng;
struct RandomizedCollection {d: HashMap<i32,HashSet<usize>>,v: Vec<i32>,
}/*** `&self` means the method takes an immutable reference.* If you need a mutable reference, change it to `&mut self` instead.*/
impl RandomizedCollection {fn new() -> Self {Self{d:HashMap::new(),v:Vec::new(),} }fn insert(&mut self, val: i32) -> bool {self.v.push(val); // 插入if !self.d.contains_key(&val) {self.d.insert(val,HashSet::new());}let mut p = self.d.get_mut(&val).unwrap();p.insert(self.v.len()-1);// println!("{:?}",p);p.len() == 1}fn remove(&mut self, val: i32) -> bool {if !self.d.contains_key(&val){return false;}let mut p = self.d.get_mut(&val).unwrap();if p.len() == 0 {return false;}let &pos = p.iter().next().unwrap();p.remove(&pos); // 如果是最后一个,直接移除即可if pos == self.v.len()-1{self.v.pop(); }else { // 否则要把最后一个值的下标修改一下 let v = self.v.last().unwrap();let mut pp = self.d.get_mut(&v).unwrap();pp.remove(&(self.v.len()-1)); pp.insert(pos);self.v.swap_remove(pos); }return true;}fn get_random(&self) -> i32 {return self.v[rand::thread_rng().gen_range(0, self.v.len())]}
}/*** Your RandomizedCollection object will be instantiated and called as such:* let obj = RandomizedCollection::new();* let ret_1: bool = obj.insert(val);* let ret_2: bool = obj.remove(val);* let ret_3: i32 = obj.get_random();*/
六、参考链接
- Rust标准库中的集合介绍
[Rust学习:四] Vec和栈相关推荐
- Rust学习四 rust的函数、注释与控制流
函数.注释与控制流 一 函数 rust以fn为关键字声明一个函数.函数命名规范为全小写,以下划线为分隔的单词. fn main() {} 带参数的函数 多个参数以逗号分隔,函数参数必须指定数据类型 f ...
- RUST 学习日记 第13课 ——字符串(一)
RUST 学习日记 第13课 --字符串(一) 0x00 回顾与开篇 上节课讲解了切片(Slice).数组(Array).向量(Vector)的区别.看到好多同学给我反馈,说可能有点儿晦涩难懂.那我在 ...
- Docker学习四:Docker 网络
前言 本次学习来自于datawhale组队学习: 教程地址为: https://github.com/datawhalechina/team-learning-program/tree/master/ ...
- Rust学习日记番外篇——代码写诗
Rust学习日记番外篇--代码写诗 中秋节即将来临啦~~提前祝大家月饼节快乐.今天看到了掘金的文章,有个代码写诗的活动,那我就小露一手了. 0x01 选定诗句 在掘金有下面几句诗可选. 举头望明月,低 ...
- Rust学习教程10 - 所有权
本文节选自<<Rust语言圣经>>一书 欢迎大家加入Rust编程学院,一起学习交流: QQ群:1009730433 所有权 所有的程序都必须和计算机内存打交道,如何从内存中申请 ...
- Rust学习:5_所有权与借用
Rust学习:5_所有权与借用 前言 为了学习Rust,阅读了github上的Rust By Practice电子书,本文章只是用来记录自己的学习过程,感兴趣的可以阅读原书,希望大家都能掌握Rust! ...
- C#多线程学习(四) 多线程的自动管理(线程池) (转载系列)——继续搜索引擎研究...
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- C语言数据结构(大话数据结构——笔记2)第四章:栈与队列
文章目录 第四章:栈与队列(115) 栈顶与栈底,空栈,后进先出 Last in first out(LIFO结构)(117) 进栈.压栈.入栈:栈的插入操作:出栈.弹栈:栈的删除操作(118) pu ...
- python学习四(处理数据)
python学习四(处理数据) head first python中的一个数据处理的例子 有四个U10选手的600米成绩,请取出每个选手跑的最快的3个时间.以下是四位选手的9次成绩 James 2-3 ...
最新文章
- “一网打尽”Deepfake等换脸图像,微软提出升级版鉴别技术Face X-Ray​
- 模糊综合评价法用什么软件实现_基于建管养一体化模式的钢桥面铺装方案综合评价分析...
- 7、Power Query-合并查询
- 菜鸟学ASP.NET MVC4入门笔记
- 年度回顾 | 2019 年的 Apache Flink
- AWT_事件监听(Java)
- python入门教程(非常详细)-Python入门教程:超详细1小时学会Python
- 学python需要什么基础-0基础学Python 需要些什么?
- linux docker 安装sql,CentOS7使用Docker安装SQL Server 2017
- 简单使用Spring Boot+JpaRepository+hibernate搭建项目
- r430服务器如何用u盘做系统,DELL R430服务器U盘安装操作系统指南.docx
- 缠中说禅形态挖掘之五笔形态
- 大数据处理技术-头歌平台-答案
- 安装ssd后不识别网卡_安装固态硬盘后读不出来,怎么解决?
- 矩阵理论——内积空间
- python实现链表(一)
- 1024_回首2022我做了啥
- decompose transformation matrix
- 【51单片机Task】:led十六进制控制led灯详解、按键控制流水灯、跑马灯等任务
- rndis wlan折腾记
热门文章
- 快站模板 连接mysql_建站实操:如何用CMS快速建站
- 助手的反叛——全面分析浏览器劫持的情况(转)
- 从三个产业侧影,打开万物智能的应用之匙
- 安卓开发学习日记第一天(笑)_Android Studio3.6安装_莫韵乐的快乐笔记
- Linux下安装SAProuter
- 科目二 坡道定点停车和起步 流程记录 LTS
- 糖尿病的治疗效果分析
- windows使用linux终端模拟器,程序员必备之终端模拟器,让你的终端世界多一抹“颜色”...
- Linux项目组编程规范
- Unicode码转UTF8