[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和栈相关推荐

  1. Rust学习四 rust的函数、注释与控制流

    函数.注释与控制流 一 函数 rust以fn为关键字声明一个函数.函数命名规范为全小写,以下划线为分隔的单词. fn main() {} 带参数的函数 多个参数以逗号分隔,函数参数必须指定数据类型 f ...

  2. RUST 学习日记 第13课 ——字符串(一)

    RUST 学习日记 第13课 --字符串(一) 0x00 回顾与开篇 上节课讲解了切片(Slice).数组(Array).向量(Vector)的区别.看到好多同学给我反馈,说可能有点儿晦涩难懂.那我在 ...

  3. Docker学习四:Docker 网络

    前言 本次学习来自于datawhale组队学习: 教程地址为: https://github.com/datawhalechina/team-learning-program/tree/master/ ...

  4. Rust学习日记番外篇——代码写诗

    Rust学习日记番外篇--代码写诗 中秋节即将来临啦~~提前祝大家月饼节快乐.今天看到了掘金的文章,有个代码写诗的活动,那我就小露一手了. 0x01 选定诗句 在掘金有下面几句诗可选. 举头望明月,低 ...

  5. Rust学习教程10 - 所有权

    本文节选自<<Rust语言圣经>>一书 欢迎大家加入Rust编程学院,一起学习交流: QQ群:1009730433 所有权 所有的程序都必须和计算机内存打交道,如何从内存中申请 ...

  6. Rust学习:5_所有权与借用

    Rust学习:5_所有权与借用 前言 为了学习Rust,阅读了github上的Rust By Practice电子书,本文章只是用来记录自己的学习过程,感兴趣的可以阅读原书,希望大家都能掌握Rust! ...

  7. C#多线程学习(四) 多线程的自动管理(线程池) (转载系列)——继续搜索引擎研究...

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  8. C语言数据结构(大话数据结构——笔记2)第四章:栈与队列

    文章目录 第四章:栈与队列(115) 栈顶与栈底,空栈,后进先出 Last in first out(LIFO结构)(117) 进栈.压栈.入栈:栈的插入操作:出栈.弹栈:栈的删除操作(118) pu ...

  9. python学习四(处理数据)

    python学习四(处理数据) head first python中的一个数据处理的例子 有四个U10选手的600米成绩,请取出每个选手跑的最快的3个时间.以下是四位选手的9次成绩 James 2-3 ...

最新文章

  1. “一网打尽”Deepfake等换脸图像,微软提出升级版鉴别技术Face X-Ray​
  2. 模糊综合评价法用什么软件实现_基于建管养一体化模式的钢桥面铺装方案综合评价分析...
  3. 7、Power Query-合并查询
  4. 菜鸟学ASP.NET MVC4入门笔记
  5. 年度回顾 | 2019 年的 Apache Flink
  6. AWT_事件监听(Java)
  7. python入门教程(非常详细)-Python入门教程:超详细1小时学会Python
  8. 学python需要什么基础-0基础学Python 需要些什么?
  9. linux docker 安装sql,CentOS7使用Docker安装SQL Server 2017
  10. 简单使用Spring Boot+JpaRepository+hibernate搭建项目
  11. r430服务器如何用u盘做系统,DELL R430服务器U盘安装操作系统指南.docx
  12. 缠中说禅形态挖掘之五笔形态
  13. 大数据处理技术-头歌平台-答案
  14. 安装ssd后不识别网卡_安装固态硬盘后读不出来,怎么解决?
  15. 矩阵理论——内积空间
  16. python实现链表(一)
  17. 1024_回首2022我做了啥
  18. decompose transformation matrix
  19. 【51单片机Task】:led十六进制控制led灯详解、按键控制流水灯、跑马灯等任务
  20. rndis wlan折腾记

热门文章

  1. 快站模板 连接mysql_建站实操:如何用CMS快速建站
  2. 助手的反叛——全面分析浏览器劫持的情况(转)
  3. 从三个产业侧影,打开万物智能的应用之匙
  4. 安卓开发学习日记第一天(笑)_Android Studio3.6安装_莫韵乐的快乐笔记
  5. Linux下安装SAProuter
  6. 科目二 坡道定点停车和起步 流程记录 LTS
  7. 糖尿病的治疗效果分析
  8. windows使用linux终端模拟器,程序员必备之终端模拟器,让你的终端世界多一抹“颜色”...
  9. Linux项目组编程规范
  10. Unicode码转UTF8