【Rust】枚举类型创建单链表以及常见的链表操作方法

news2024/9/25 15:23:33

目录

单链表

用枚举表达链表

枚举enum

Box容器

创建节点

1. 创建并打印

2. match 匹配

3. 节点初始化

4.节点嵌套

追加节点

1. 尾插法

2. 链表追加方法

3. 头插法

4. 改写成单链表方法

遍历链表

1. 递归法

2. 递推法

3. 改写成单链表方法 

自定义Display trait

创建链表

1. 递归法

2. 递推法

3. 改写成单链表方法 

链表长度

翻转链表

1. 递归法

2. 递推法

3. 改写成单链表关联函数和方法

删除尾节点

汇总小结

相关方法

自定义trait

完整代码

真题实战

合并两个有序链表 Mmerge-two-sorted-lists


20210817204340750.png

单链表

单链表(Linked List)是一种线性数据结构,由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。单链表的特点是每个节点只能指向一个下一个节点,没有指向上一个节点的指针。

单链表的基本操作包括插入、删除、查找等。插入操作需要在指定位置插入一个新节点,删除操作需要删除指定位置的节点,查找操作需要找到指定值的节点位置。

单链表的优势是插入和删除操作相对简单,不需要移动大量元素,时间复杂度为O(1)。但单链表在查找操作上的时间复杂度是O(n),因为需要从头节点开始逐个比较直到找到目标节点。

用枚举表达链表

enum List {
    None,
    Node(i32, Box<List>),
}

枚举成员: List::None 、 List::Node(i32, Box<List>)

枚举enum

Rust 是一种编程语言,支持多种类型的的数据,其中之一就是枚举类型(Enum)。枚举类型是一种特殊的数据类型,它定义了一组可能的值。每个值都有一个特定的类型,并且可以用来表示不同的含义。

Rust 中的枚举类型通常使用关键字 enum 来定义,后接名称;枚举有多个成员(variant),每个成员是该 enum 类型的一个可能值。

例如,定义一个表示颜色类型的的枚举:

enum Color { Red, Green, Blue, }

这个 Color 类型有三种可能的值:RedGreen 和 Blue,使用这些值来存储不同颜色的值。

枚举类型的一个重要作用是使得代码更具可读性和可维护性。例如,如果使用一个 String 类型的颜色值,必须要确保该字符串始终有效,否则程序可能会崩溃。而使用枚举类型,可以明确指定可能的值,从而减少了此类错误的发生。

另外,Rust 还支持模式匹配,可以方便地检查一个枚举类型的值是哪个模式,这使得代码更加简洁和可读。例如:

let c = Color::Red;  
match c {  
    Color::Red => println!("It's red!"),  
    Color::Green => println!("It's green!"),  
    Color::Blue => println!("It's blue!"),  
};

在这个例子中,使用 match 表达式来检查 c 的值是哪个模式。根据不同的模式,可以执行不同的代码。

Box容器

Rust中的Box是一种通用容器,可以存储任意类型的数据。它类似于C++中的unique_ptr,但还提供了一些额外的功能。

通过使用Box,您可以在堆上分配内存,而不需要手动管理内存的分配和释放。这使得使用Box成为一种方便的方式来存储和管理动态分配的内存。

Box还提供了一些优势,例如能够解决递归类型的大小问题。在Rust中,基本类型无法实现递归,但可以使用Box将递归类型的大小固定下来。

以下是一个使用Box的简单示例:

use std::boxed::Box;  
  
fn main() {  
    let ibox = Box::new(5);  
    println!("{}", ibox); 
    println!("{}", *ibox);
    println!("{}", ibox.as_ref());
}

这个程序创建了一个Box容器,输出结果为3个5,但有不同的含义:

println!("{}", ibox);
这行代码使用 println! 宏打印一个 Box 对象 ibox 的值。{} 是一个占位符,表示将对象的值插入到此处。在这种情况下,ibox 的值将被打印出来,因为 Box 类型实现了 Display trait,可以将其值转换为字符串形式。

println!("{}", *ibox);
这行代码使用 println! 宏打印 ibox 解引用后的值。在 Rust 中,* 运算符用于解引用指针,即获取指针指向的实际值。在这种情况下,ibox 是一个 Box 对象,存储了一个整数值。通过解引用操作,我们获取到这个整数值并打印出来。

println!("{}", ibox.as_ref());
这行代码使用 println! 宏打印 ibox 的引用。as_ref() 方法返回一个引用,可以用于访问 Box 对象中的数据。在这种情况下,我们将 ibox 转换为引用,并通过引用访问其值并打印出来。

通过使用Box,可以方便地在Rust中管理和访问动态分配的内存,而不需要手动管理内存的分配和释放。

创建节点

1. 创建并打印

创建单个节点,并使用 #[derive(Debug)] 及 println! 打印输出:

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn main() {
    let head = List::Node(1, Box::new(List::None));
    println!("{:?}", head);
    let head = List::Node(2, Box::new(List::None));
    println!("{:?}", head);
}

输出: 

Node(1, None)
Node(2, None)

2. match 匹配

创建节点,并使用match表达式匹配枚举成员:

enum List {
    None,
    Node(i32, Box<List>),
}

fn main() {
    let list1 = List::None;
    let list2 = List::Node(1, Box::new(List::None));

    match list1 {
        List::None => println!("List::None"),
        List::Node(_, _) => println!("List::Node"),
    }

    match list2 {
        List::None => println!("List::None"),
        List::Node(value, _) => println!("List::Node({})", value),
    }
}

输出:

List::None
List::Node(1)

3. 节点初始化

new()初始化函数:fn new(value: i32)

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn new(value: i32) -> Self {
        List::Node(value, Box::new(List::None))
    }
}

fn main() {
    let head = List::new(1);
    println!("{:?}", head);
    let head = List::new(2);
    println!("{:?}", head); 
    let head = List::new(3);
    println!("{:?}", head); 
}

输出: 

Node(1, None)
Node(2, None)
Node(3, None)

4.节点嵌套

通过嵌套多个节点形成单链表:

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn main() {
    let head = List::Node(
        1, Box::new(List::Node(
            2, Box::new(List::Node(
                3, Box::new(List::Node(
                    4, Box::new(List::None),
                )),
            )),
        )),
    );
    println!("{:?}", head);
}

输出: 

Node(1, Node(2, Node(3, Node(4, None)))) 


通过枚举类型表达成一个单链表,同样,这种方法甚至还能表达一棵二叉树

#[derive(Debug)]
enum Tree {  
    None,  
    Node(i32, Box<Tree>, Box<Tree>),  
} 

fn main() { 
    let tree = Tree::Node(  
        1,  
        Box::new(Tree::Node(2, Box::new(Tree::None), Box::new(Tree::None))),  
        Box::new(Tree::Node(
            3,
            Box::new(Tree::Node(4, Box::new(Tree::None), Box::new(Tree::None))),
            Box::new(Tree::Node(5, Box::new(Tree::None), Box::new(Tree::None))),
            ),
        ),  
    );   
    println!("{:?}", tree);
}

输出: 

Node(1, Node(2, None, None), Node(3, Node(4, None, None), Node(5, None, None)))

二叉树相对单链表要复杂,有空再研究;还是继续探究单链表的其它操作吧。


追加节点

1. 尾插法

函数 append() 在链表尾部追加节点:

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn append(list: &mut List, value: i32) {
    match list {
        List::None => {
            *list = List::Node(value, Box::new(List::None));
        }
        List::Node(_, next) => {
            append(next, value);
        }
    }
}

fn main() {
    let mut head = List::Node(
        1, Box::new(List::Node(
            2, Box::new(List::Node(
                3, Box::new(List::Node(
                    4, Box::new(List::None),
                )),
            )),
        )),
    );
    println!("{:?}", head);

    append(&mut head, 5);
    println!("{:?}", head);
}

输出: 

Node(1, Node(2, Node(3, Node(4, None))))
Node(1, Node(2, Node(3, Node(4, Node(5, None)))))

2. 链表追加方法

把append()函数改造成链表方法:

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn new(value: i32) -> Self {
        List::Node(value, Box::new(List::None))
    }

    fn append(self, value: i32) -> Self {
        match self {
            List::None => List::Node(value, Box::new(List::None)),
            List::Node(v, next) => List::Node(v, Box::new(next.append(value))),
        }
    }
}

fn main() {
    let head = List::new(1);
    println!("{:?}", head);

    let head = head.append(2);
    println!("{:?}", head);

    let head = head.append(3);
    println!("{:?}", head);
}

输出: 

Node(1, None)
Node(1, Node(2, None))
Node(1, Node(2, Node(3, None))) 

3. 头插法

除了尾部追加,也能在头部插入: 

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn main() {
    let mut head = List::Node(1, Box::new(List::None));
    head = List::Node(2, Box::new(head));
    head = List::Node(3, Box::new(head));
    head = List::Node(4, Box::new(head));
    println!("{:?}", head);
}

输出: 

Node(4, Node(3, Node(2, Node(1, None)))) 

头插法得到一个反序的单链表:

4. 改写成单链表方法

对比append()和.push_back()不同之处:

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn new(value: Option<i32>) -> Self {
        match value {
            Some(value) => List::Node(value, Box::new(List::None)),
            None => List::None,
        }
    }

    fn append(self, value: i32) -> Self {
        match self {
            List::None => List::new(Some(value)),
            List::Node(v, next) => List::Node(v, Box::new(next.append(value))),
        }
    }
    
    fn push_back(&mut self, value: i32) {
        match self {
            List::None => {
                *self = List::new(Some(value));
            }
            List::Node(_, next) => {
                next.push_back(value);
            }
        }
    }
}

fn main() {
    let head = List::new(None);
    println!("{:?}", head);
    let head = head.append(1);
    let head = head.append(2);
    println!("{:?}", head);
    println!();

    let mut head = List::new(Some(1));
    println!("{:?}", head);
    for value in 2..5 {
        head.push_back(value);
    }
    println!("{:?}", head);
}

输出: 

None
Node(1, Node(2, None))

Node(1, None)
Node(1, Node(2, Node(3, Node(4, None))))

push_back()推荐使用递归法,代码比较精炼;递推迭代法如下:

    fn push_back(&mut self, value: i32) {
        match self {
            List::None => {
                *self = List::new(Some(value));
            }
            List::Node(_, next) => {
                if let List::None = &**next {
                    *next = Box::new(List::new(Some(value)));
                } else {
                    let mut curr = next;
                    while let List::Node(_, ref mut next) = **curr {
                        curr = next;
                    }
                    *curr = Box::new(List::new(Some(value)));
                }
            }
        }
    }

遍历链表

1. 递归法

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn traverse(list: &List) {
    match list {
        List::None => println!("nil"),
        List::Node(value, next) => {
            print!("{}->", value);
            traverse(next);
        }
    }
}

fn main() {
    let head = List::Node(
        1,
        Box::new(List::Node(
            2,
            Box::new(List::Node(
                3,
                Box::new(List::None),
            )),
        )),
    );

    println!("{:?}", head);
    traverse(&head);
}

输出:

Node(1, Node(2, Node(3, None)))
1->2->3->nil

2. 递推法

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn traverse(head: &List) {
    let mut cur = head;
    while let List::Node(value, next) = cur {
        print!("{}->", value);
        cur = next;
    }
    println!("nil");
}

fn main() {
    let head = List::Node(
        1,
        Box::new(List::Node(
            2,
            Box::new(List::Node(
                3,
                Box::new(List::None),
            )),
        )),
    );

    println!("{:?}", head);
    traverse(&head);
}

输出:

Node(1, Node(2, Node(3, None)))
1->2->3->nil

while let 语句比较简洁,相当于loop+if let:

fn traverse(head: &List) {
    let mut cur = head;
    loop {
        if let List::Node(value, next) = cur {
            print!("{}->", value);
            cur = next;
        } else {
            println!("nil");
            break;
        }
    }
}

使用 loop+match 也能遍历:

fn traverse(head: &List) {
    let mut cur = head;
    loop {
        match cur {
            List::None => {
                println!("nil");
                break;
            }
            List::Node(value, next) => {
                print!("{}->", value);
                cur = next;
            }
        }
    }
}

3. 改写成单链表方法 

enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn traverse(&self) {
        let mut curr = self;
        while let List::Node(value, next) = curr {
            print!("{}->", value);
            curr = next;
        }
        println!("nil");
    }
}

fn main() {
    let head = List::Node(
        1, Box::new(List::Node(
            2, Box::new(List::Node(
                3, Box::new(List::None),
            )),
        )),
    );
    head.traverse();
}

输出:

1->2->3->nil


自定义Display trait

为与遍历函数区分,在trait输出时用“Nil”标记

use std::fmt;

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            List::None => write!(f, "Nil"),
            List::Node(value, next) => {
                write!(f, "{}->", value)?;
                write!(f, "{}", *next)?;
                Ok(())
            }
        }
    }
}

fn traverse(head: &List) {
    let mut cur = head;
    while let List::Node(value, next) = cur {
        print!("{}->", value);
        cur = next;
    }
    println!("nil");
}

fn main() {  
    let head = List::Node(
        1, Box::new(List::Node(
            2, Box::new(List::Node(
                3, Box::new(List::None),
            )),
        )),
    );
  
    println!("{}", head);
    traverse(&head);
}

输出:

1->2->3->Nil
1->2->3->nil


创建链表

直接把动态数组Vec创建成单链表。

1. 递归法

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn traverse(head: &List) {
    let mut cur = head;
    while let List::Node(value, next) = cur {
        print!("{}->", value);
        cur = next;
    }
    println!("nil");
}

fn create(values: Vec<i32>) -> List {
    fn _helper(values: &Vec<i32>, index: usize) -> List {
        if index < values.len() {
            let value = values[index];
            let next = Box::new(_helper(values, index + 1));
            List::Node(value, next)
        } else {
            List::None
        }
    }
    _helper(&values, 0)
}

fn main() {
    let values = vec![1, 2, 3, 4, 5];
    let head = create(values.clone());
    println!("{:?}", head);
    traverse(&head);
}

输出:

Node(1, Node(2, Node(3, Node(4, Node(5, None)))))
1->2->3->4->5->nil

2. 递推法

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn traverse(head: &List) {
    let mut cur = head;
    while let List::Node(value, next) = cur {
        print!("{}->", value);
        cur = next;
    }
    println!("nil");
}

fn create(values: Vec<i32>) -> List {
    let mut list = List::None;
    for &value in values.iter().rev() {
        list = List::Node(value, Box::new(list));
    }
    list
}

fn main() {
    let values = vec![1, 2, 3, 4, 5];
    let head = create(values.clone());
    println!("{:?}", head);
    traverse(&head);
}

输出:

Node(1, Node(2, Node(3, Node(4, Node(5, None)))))
1->2->3->4->5->nil

3. 改写成单链表方法 

enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn traverse(&self) {
        let mut curr = self;
        while let List::Node(value, next) = curr {
            print!("{}->", value);
            curr = next;
        }
        println!("nil");
    }

    fn create(values: Vec<i32>) -> List {
        let mut list = List::None;
        for &value in values.iter().rev() {
            list = List::Node(value, Box::new(list));
        }
        list
    }
}

fn main() {
    let head = List::create(vec!(1,2,3,4,5));
    head.traverse();
}

输出:

1->2->3->4->5->nil


链表长度

遍历链表时改打印为计数即可:

enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn create(values: Vec<i32>) -> List {
        let mut list = List::None;
        for &value in values.iter().rev() {
            list = List::Node(value, Box::new(list));
        }
        list
    }

    fn traverse(&self) {
        let mut curr = self;
        while let List::Node(value, next) = curr {
            print!("{}->", value);
            curr = next;
        }
        println!("nil");
    }

    fn get_size(&self) -> usize {
        let mut length = 0;
        let mut curr = self;
        while let List::Node(_, next) = curr {
            length += 1;
            curr = next;
        }
        length
    }
}

fn main() {
    let head = List::create(vec![1, 2, 3]);
    head.traverse();
    let length = head.get_size();
    println!("Length of list: {}", length);

    let head = List::create(vec![1, 2, 3, 4, 5]);
    head.traverse();
    let length = head.get_size();
    println!("Length of list: {}", length);
}

输出:

1->2->3->nil
Length of list: 3
1->2->3->4->5->nil
Length of list: 5


翻转链表

把单链表翻转,即头尾反向。

1. 递归法

#[derive(Debug)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn traverse(head: &List) {
    let mut cur = head;
    while let List::Node(value, next) = cur {
        print!("{}->", value);
        cur = next;
    }
    println!("nil");
}

fn create(values: Vec<i32>) -> List {
    let mut list = List::None;
    for &value in values.iter().rev() {
        list = List::Node(value, Box::new(list));
    }
    list
}

fn reversed(list: &List) -> List {
    fn _helper(list: &List, prev: List) -> List {
        match list {
            List::None => prev,
            List::Node(value, next) => {
                _helper(next, List::Node(*value, Box::new(prev)))
            },
        }
    }
    _helper(list, List::None)
}

fn main() {
    let values = vec![1, 2, 3, 4, 5];
    let head = create(values);
    traverse(&head);
    let head = reversed(&head);
    traverse(&head);
}

输出:

1->2->3->4->5->nil
5->4->3->2->1->nil

2. 递推法

enum List {
    None,
    Node(i32, Box<List>),
}

fn traverse(head: &List) {
    let mut curr = head;
    while let List::Node(value, next) = curr {
        print!("{}->", value);
        curr = next;
    }
    println!("nil");
}

fn create(values: Vec<i32>) -> List {
    let mut list = List::None;
    for &value in values.iter().rev() {
        list = List::Node(value, Box::new(list));
    }
    list
}

fn reversed(head: &List) -> List {
    let mut list = List::None;
    let mut curr = head;
    while let List::Node(value, next) = curr {
        list = List::Node(*value, Box::new(list));
        curr = next;
    }
    list
}

fn main() {
    let values = vec![1, 2, 3, 4, 5];
    let head = create(values);
    traverse(&head);
    let head = reversed(&head);
    traverse(&head);
}

输出:

1->2->3->4->5->nil
5->4->3->2->1->nil

3. 改写成单链表关联函数和方法

对比关联函数reversed()和方法.reverse()不同之处:

enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn new(value: Option<i32>) -> Self {
        match value {
            Some(value) => List::Node(value, Box::new(List::None)),
            None => List::None,
        }
    }

    fn traverse(&self) {
        let mut curr = self;
        while let List::Node(value, next) = curr {
            print!("{}->", value);
            curr = next;
        }
        println!("nil");
    }

    fn create(values: Vec<i32>) -> List {
        let mut list = List::None;
        for &value in values.iter().rev() {
            list = List::Node(value, Box::new(list));
        }
        list
    }

    fn reversed(&self) -> Self {
        let mut list = List::new(None);
        let mut curr = self;
        while let List::Node(value, next) = curr {
            list = List::Node(*value, Box::new(list));
            curr = next;
        }
        list
    }

    fn reverse(&mut self) {
        let mut tail = List::new(None);
        let mut curr = std::mem::replace(self, List::None);
        while let List::Node(value, next) = std::mem::replace(&mut curr, List::None) {
            let node = List::Node(value, Box::new(tail));
            (tail, curr) = (node, *next);
        }
        std::mem::swap(self, &mut tail);
    }
}

fn main() {
    let values = vec![1, 2, 3, 4, 5];
    let mut head = List::create(values);
    head.traverse();
    head.reverse();
    head.traverse();
    head = List::reversed(&head);
    head.traverse();
}

输出:

1->2->3->4->5->nil
5->4->3->2->1->nil
1->2->3->4->5->nil


删除尾节点

删除链表尾节点pop(),并返回尾节点的值

#![allow(dead_code)]

enum List {
    None,
    Node(i32, Box<List>),
}

impl List {
    fn new(value: Option<i32>) -> Self {
        match value {
            Some(value) => List::Node(value, Box::new(List::None)),
            None => List::None,
        }
    }

    fn create(values: Vec<i32>) -> List {
        let mut list = List::None;
        for &value in values.iter().rev() {
            list = List::Node(value, Box::new(list));
        }
        list
    }

    fn traverse(&self) {
        let mut curr = self;
        while let List::Node(value, next) = curr {
            print!("{}->", value);
            curr = next;
        }
        println!("nil");
    }

    fn pop(&mut self) -> Option<i32> {
        match self {
            List::None => None,
            List::Node(value, next) => {
                if let List::None = **next {
                    let popped_value = *value;
                    *self = List::None;
                    Some(popped_value)
                } else {
                    next.pop()
                }
            }
        }
    }
}

fn main() {
    let values = vec![1, 2, 3, 4, 5];
    let mut head = List::create(values);
    head.traverse();
    for _ in 1..=6 {
        if let Some(value) = head.pop() {
            println!("Popped value: {}", value);
        } else {
            println!("List is empty");
        }
        head.traverse();
    }
}

输出:

1->2->3->4->5->nil
Popped value: 5
1->2->3->4->nil
Popped value: 4
1->2->3->nil
Popped value: 3
1->2->nil
Popped value: 2
1->nil
Popped value: 1
nil
List is empty
nil


汇总小结

List 枚举定义了链表的两种可能状态:None 和 Node。

其中,Node 表示链表节点,包含一个整数值和一个指向下一个节点的 Box<List>。

相关方法

相关的方法或关联函数,归纳如下:

new:创建一个新的链表节点或空链表。
append:在链表尾部添加一个节点,并返回添加后的链表。
push_back:在链表尾部添加一个节点,将链表修改为添加后的结果。
create:根据给定的数组构建一个链表。
reversed:反转链表,返回一个反转后的链表。
reverse:反转链表,将链表修改为反转后的结果。
traverse:遍历并打印链表中的节点值。
get_size:遍历出链表的节点数,返回链表长度。
pop:删除链表尾节点,并返回尾节点的值。

自定义trait

自定义trait Display,使链表的输出不依赖trait Debug:

```Rust
impl std::fmt::Display for List {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            List::None => write!(f, "nil"),
            List::Node(value, next) => {
                write!(f, "{}->", value)?;
                write!(f, "{}", *next)?;
                write!(f, "")
            }
        }
    }
}
```

完整代码

InsCode - 让你的灵感立刻落地

https://inscode.csdn.net/@boysoft2002/RustEnumList

#![allow(dead_code)]

enum List {
    None,
    Node(i32, Box<List>),
}

impl std::fmt::Display for List {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            List::None => write!(f, "nil"),
            List::Node(value, next) => {
                write!(f, "{}->", value)?;
                write!(f, "{}", *next)?;
                Ok(())
            }
        }
    }
}

impl List {
    fn new(value: Option<i32>) -> Self {
        match value {
            Some(value) => List::Node(value, Box::new(List::None)),
            None => List::None,
        }
    }

    fn append(self, value: i32) -> Self {
        match self {
            List::None => List::new(Some(value)),
            List::Node(v, next) => List::Node(v, Box::new(next.append(value))),
        }
    }

    fn push_back(&mut self, value: i32) {
        match self {
            List::None => {
                *self = List::new(Some(value));
            }
            List::Node(_, next) => {
                next.push_back(value);
            }
        }
    }

    fn create(values: Vec<i32>) -> Self {
        let mut list = List::new(None);
        for &value in values.iter().rev() {
            list = List::Node(value, Box::new(list));
        }
        list
    }

    fn get_size(&self) -> usize {
        let mut length = 0;
        let mut curr = self;
        while let List::Node(_, next) = curr {
            length += 1;
            curr = next;
        }
        length
    }

    fn reversed(&self) -> Self {
        let mut list = List::new(None);
        let mut curr = self;
        while let List::Node(value, next) = curr {
            list = List::Node(*value, Box::new(list));
            curr = next;
        }
        list
    }

    fn reverse(&mut self) {
        let mut tail = List::new(None);
        let mut curr = std::mem::replace(self, List::None);
        while let List::Node(value, next) = std::mem::replace(&mut curr, List::None) {
            let node = List::Node(value, Box::new(tail));
            (tail, curr) = (node, *next);
        }
        std::mem::swap(self, &mut tail);
    }

    fn pop(&mut self) -> Option<i32> {
        match self {
            List::None => None,
            List::Node(value, next) => {
                if let List::None = **next {
                    let popped_value = *value;
                    *self = List::None;
                    Some(popped_value)
                } else {
                    next.pop()
                }
            }
        }
    }

    fn traverse(self: &Self) {
        let mut curr = self;
        while let List::Node(value, next) = curr {
            print!("{}->", value);
            curr = next;
        }
        println!("nil");
    }
}  

fn main() {  
    let head = List::new(None);
    head.traverse();
    let head = head.append(1);
    let head = head.append(2);
    head.traverse();
    println!();

    let mut head = List::new(Some(1));
    head.traverse();
    for value in 2..5 {
        head.push_back(value);
    }
    head.traverse();
    println!();

    let values = vec![1, 2, 3, 4, 5];
    head = List::create(values);
    head.traverse();
    head = head.reversed();
    println!("{}", head);
    head.reverse();
    println!("{}", head);
    let length = head.get_size();
    println!("Length of list: {}", length);
    println!();

    if let Some(value) = head.pop() {
        println!("Popped value: {}", value);
    } else {
        println!("List is empty");
    }
    head.traverse();
    println!("Length of list: {}", head.get_size());
}

输出:

nil
1->2->nil

1->nil
1->2->3->4->nil

1->2->3->4->5->nil
5->4->3->2->1->nil
1->2->3->4->5->nil
Length of list: 5

Popped value: 5
1->2->3->4->nil
Length of list: 4


真题实战

合并两个有序链表 Mmerge-two-sorted-lists

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

d661704fd7a9313cfefde8cc55ef4666.jpg

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

代码:

#[derive(Clone)]
enum List {
    None,
    Node(i32, Box<List>),
}

fn create(values: Vec<i32>) -> List {
    let mut list = List::None;
    for &value in values.iter().rev() {
        list = List::Node(value, Box::new(list));
    }
    list
}

fn traverse(head: &List) {
    let mut cur = head;
    while let List::Node(value, next) = cur {
        print!("{}->", value);
        cur = next;
    }
    println!("nil");
}

fn merge_lists(l1: List, l2: List) -> List {
    match (l1.clone(), l2.clone()) {
        (List::None, _) => l2,
        (_, List::None) => l1,
        (List::Node(x, box1), List::Node(y, box2)) => {
            if x < y {
                List::Node(x, Box::new(merge_lists(*box1, l2)))
            } else {
                List::Node(y, Box::new(merge_lists(l1, *box2)))
            }
        }
    }
}

fn main() {
    let nums1 = vec![1, 2, 4];
    let nums2 = vec![1, 2, 3];
    let list1 = create(nums1);
    let list2 = create(nums2);
    traverse(&list1);
    traverse(&list2);
    let merged = merge_lists(list1, list2);
    traverse(&merged);
}

输出:

1->2->4->nil
1->2->3->nil
1->1->2->2->3->4->nil

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/805794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8. Vmvare中重新分配Linux系统的分区空间大小

1. 说明 一般情况下&#xff0c;在使用Vmvare虚拟机创建配置Linux系统时&#xff0c;默认将系统的内存设置为4GB&#xff0c;硬盘大小设置为40GB&#xff0c;但随着空间利用的越来越多&#xff0c;内存会出现不够使用的情况&#xff0c;此时需要重新分配空间大小&#xff0c;具…

go 查询采购单设备事项[小示例]

一、项目背景 1.1需求&#xff1a; 项目实施过程中存在多次下采购单的事项&#xff0c;如果查询过去采购单中下了哪些设备&#xff0c;数量以及相应信息&#xff0c;如何处理呢? 备注&#xff0c;价格等都是修改了&#xff0c;不是原始内容&#xff0c;只是参考 1.2实现步骤…

transformer代码注解

其中代码均来自李沐老师的动手学pytorch中。 class PositionWiseFFN(nn.Module):ffn_num_inputs 4ffn_num_hiddens 4ffn_num_outputs 8def __init__(self,ffn_num_inputs,ffn_num_hiddens,ffn_num_outputs):super(PositionWiseFFN,self).__init__()self.dense1 nn.Linear(ffn…

3ds MAX绘制简单动画

建立一个长方体和茶壶&#xff1a; 在界面右下角点击时间配置&#xff1a; 这是动画制作的必要步骤 选择【自动】&#xff0c;接下来&#xff0c;我们只要在对应的帧改变窗口中图形的位置&#xff0c;就能自动记录该时刻的模样 这就意味着&#xff0c;我们通过电脑记录某几个…

工业平板电脑优化汽车工厂的生产流程

汽车行业一直是自动化机器人系统的早期应用领域之一。通过使用具有高负载能力和远程作用的大型机械臂&#xff0c;汽车装配工厂可以实现点焊、安装挡风玻璃、安装车轮等工作&#xff0c;而较小的机械手则用于焊接和安装子组件。使用机器人系统不仅提高了生产效率&#xff0c;还…

工业智能化的关键之二:集成监控和分析能力

将监控和分析能力集成到工厂运营的日常中是工业智能化发展的关键步骤。随着科技的进步和数字化技术的广泛应用&#xff0c;工厂正在逐步实现从传统的人工操作到智能化的转变。这种转变不仅提高了工厂的生产效率和产品质量&#xff0c;还极大地提升了工厂的安全性和可靠性。 1.…

Flutter 调试工具篇 | 壹 - 使用 Flutter Inspector 分析界面

theme: cyanosis 1. 前言 很多朋友可能在布局过程中、或者组件使用过程中&#xff0c;会遇到诸如颜色、尺寸、约束、定位等问题&#xff0c;可能会让你抓耳挠腮。俗话说&#xff0c;磨刀不误砍柴工&#xff0c;会使用工具是非常重要的&#xff0c;其实 Flutter 提供了强大的调试…

axios使用异步方式无感刷新token,简单,太简单了

文章目录 &#x1f349; 废话在前&#x1f357; 接着踩坑&#x1f969; 解决思路&#x1f353; 完整代码 &#x1f349; 废话在前 写vue的或帮们无感刷新token相信大家都不陌生了吧&#xff0c;刚好&#xff0c;最近自己的一个项目中就需要用到这个需求&#xff0c;因为之前没…

Fluentbit

Fluent Bit&#xff08;常简称为Fluent-Bit 或 Fluentbit&#xff09;是一个开源的、轻量级的日志数据收集器&#xff08;log collector&#xff09;和 转发器&#xff08;log forwarder&#xff09;&#xff0c;旨在高效地收集、处理和转发日志数据。它是Fluentd项目的一个子项…

山东农业大学图书馆藏书《乡村振兴战略下传统村落文化旅游设计》

山东农业大学图书馆藏书《乡村振兴战略下传统村落文化旅游设计》

数字化时代,企业研发效能跃升之道丨IDCF

本文节选自新书《数字化时代研发效能跃升方法与实践》 作者&#xff1a;冬哥 研发效能是近年的热词&#xff0c;企业言必谈效能&#xff0c;但究竟什么是研发效能&#xff0c;落地具体应该如何进行&#xff0c;相信每个人都会有无数的问题浮现。 什么是效能&#xff1f; 效能…

Element-plus侧边栏踩坑

问题描述 el-menu直接嵌套el-menu-item菜单&#xff0c;折叠时不会出现文字显示和小箭头无法隐藏的问题&#xff0c;但是实际开发需求中难免需要把el-menu-item封装为组件 解决 vue3项目中嵌套两层template <template><template v-for"item in list" :k…

内网隧道代理技术(十三)之内网代理介绍

前言 什么?你问我内网隧道代理技术怎么突然就第十三篇了,第十二篇呢?这个,因为某些不可抗拒力量,第十二篇博客无法发表,如果想要查阅,请加内网渗透qq群:838076210 内网代理介绍 内网代理介绍 内网资产扫描这种场景一般是进行内网渗透才需要的代理技术,如果你不打内…

公共字段的填充

方式1&#xff0c;通过mybatis-plus提供的MetaObjectHandler进行填充 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;import com.sky.context.BaseContext; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import o…

【ROS第一讲】一、创建工作空间

【ROS第一讲】一、创建工作空间 一、工作空间1.src&#xff1a;2.build&#xff1a;3.devel&#xff1a;4.install: 二、创建工作空间1.工作空间的编译2.配置环境变量&#xff1a; 三、创建功能包 一、工作空间 1.src&#xff1a; 放置所有功能包源码的空间 2.build&#xf…

Unity XML3——XML序列化

一、XML 序列化 ​ 序列化&#xff1a;把对象转化为可传输的字节序列过程称为序列化&#xff0c;就是把想要存储的内容转换为字节序列用于存储或传递 ​ 反序列化&#xff1a;把字节序列还原为对象的过程称为反序列化&#xff0c;就是把存储或收到的字节序列信息解析读取出来…

再见 MyBatis-Plus !

一、Mybatis-Flex是什么&#xff1f; Mybatis-Flex 是一个优雅的 Mybatis 增强框架&#xff0c;它非常轻量、同时拥有极高的性能与灵活性。我们可以轻松的使用 Mybaits-Flex 链接任何数据库&#xff0c;其内置的 QueryWrapper^亮点 帮助我们极大的减少了 SQL 编写的工作的同时…

odoo16-domain

odoo16-domain 参考:https://blog.csdn.net/u013250491/article/details/86699928 domain的使用注意以下几点: 是在py文件中使用还是在xml中使用,py文件是在后端使用可以利用orm, 而xml是在前端渲染,使用的是js,没有办法使用orm如果在xml中使用,domain的格式建议为[[]], 二维…

LeetCode32.Longest-Valid-Parentheses<最长有效括号>

题目&#xff1a; 思路&#xff1a; 遍历括号.遇到右括号然后前一个是左括号 那就res2,然后重定位 i 的值 并且长度减少2; 但是问题在于无法判断最长的括号.只能得到string内的全部括号长度. 错误代码: 写过一题类似的,那题是找括号数.记得是使用的栈,但是死活写不出来. 看完…

【Visual Studio Code】加载saved_model.pb时报错缺失‘cudart64_110.dll‘等

如果报错Could not load dynamic library cudart64_110.dll; dlerror: cudart64_110.dll not found&#xff0c; 将对应的cudart64_110.dll复制到C:\Windows\System32下即可 如果VScode仍继续报错&#xff0c;重新启动软件即解决问题。 同理&#xff0c;若仍有相同报错 Cou…