简体   繁体   English

递归中的可变引用 function

[英]Mutable references in recursive function

I have a vector of character stacks called crates.我有一个称为板条箱的字符堆栈向量。 Those stacks are represented using VecDeque<char> and thus the vector of those is a Vec<VecDeque<char>> .这些堆栈使用VecDeque<char>表示,因此这些堆栈的向量是Vec<VecDeque<char>> This data structure isn't really a stack but I'd like to use it as if it were one and just iterate through them from back to front and add elements to the back.这个数据结构并不是真正的堆栈,但我想像使用它一样使用它,只是从后到前遍历它们并在后面添加元素。

I want to move k last chars of a stack to another, but I want to keep them in order.我想将堆栈的最后 k 个字符移动到另一个,但我想让它们保持有序。

Example:例子:

stack_a = [ 1 <- 2 <- 3 <- 4 ]
stack_b = [ 5 <- 6 ]

# movement from a to b with k=3
stack_b = [ 5 <- 6 <- 2 <- 3 <- 4 ]

You can notice that this is not something very easy to do with a stack.您会注意到这不是用堆栈很容易做到的事情。 It would be easy if you had the right to change the order of elements added to the other stack because you could just repeat k times: push(stack_b, pop(stack_a))如果您有权更改添加到另一个堆栈的元素的顺序,那将很容易,因为您可以重复 k 次: push(stack_b, pop(stack_a))

But here we need to reorder the calls, to pop k times, keep the k values in memory and then push them.但是这里我们需要重新排序调用,弹出k次,将k个值保留在memory中,然后再push。 This can easily be expressed with a recursive function.这可以很容易地用递归 function 表示。

This is what my code looks like:这是我的代码的样子:

// I'm extracting my stack ids from a regex capture
let source_id = usize::from_str(&cap[2]).unwrap() - 1;
let target_id = usize::from_str(&cap[3]).unwrap() - 1;
// My simple function
fn move_crates_simultaneously(
    amount: usize,
    source: Rev<Iter<char>>,
    target: &mut VecDeque<char>,
) {
    if amount == 0 {
        return;
    }
    let value = source.next();
    move_crates_simultaneously(amount - 1, source, target);
    target.push_back(*(value.unwrap()));
}
// My function call
move_crates_simultaneously(
    usize::from_str(&cap[1]).unwrap(),
    crates[source_id].iter().rev(),
    &crates[target_id],
);

But there is a problem: &crates[target_id] is &VecDeque<char, Global> while the function needs a &mut VecDeque<char, Global> .但是有一个问题: &crates[target_id]&VecDeque<char, Global>而 function 需要一个&mut VecDeque<char, Global> From my understanding it doesn't seem to be possible to find a solution because there is now way for the compiler to know that my source and my target are not the same stack and thus to let me create my mutable ref for target.根据我的理解,似乎不可能找到解决方案,因为编译器现在有办法知道我的源和目标不是同一个堆栈,从而让我为目标创建可变引用。 Does that mean it is not possible to solve this kind of problem that way in Rust?那是不是就不能用Rust那样解决这种问题?

You write that what you want to do isn't easily done with stacks.你写道,你想做的事用堆栈不容易完成。

I'll give you a hint that lets you avoid the problem, given that I assume you already solved part 1 of day 5 of the 2022 advent of code challenge:p我会给你一个提示,让你避免这个问题,因为我假设你已经解决了 2022 年代码挑战的第 5 天的第 1 部分:p

In part 1, you grab an element via pop and put it on the other stack via push .在第 1 部分中,您通过pop获取一个元素并通过push将其放入另一个堆栈。 Then you do that num times.然后你这样做了num次。 Easy enough.很容易。

Now for part 2, you need the order of the popped elements to be reversed.现在对于第 2 部分,您需要颠倒弹出元素的顺序。 So why not use another stack to keep track of them?那么为什么不使用另一个堆栈来跟踪它们呢? To move elements from one stack A to stack B while maintaining order, you can first move them from stack A to stack C with the simple "pop-push" algo from part 1, and then move them from stack C to stack B again with the simple pop-push algo:要在保持顺序的同时将元素从一个堆栈 A 移动到堆栈 B,您可以先使用第 1 部分中的简单“pop-push”算法将它们从堆栈 A 移动到堆栈 C,然后再次将它们从堆栈 C 移动到堆栈 B简单的 pop-push 算法:

Stack A: 1 2 3 4
Stack B: 
Stack C:

do the pop-push 4 times

Stack A:
Stack B:
Stack C: 4 3 2 1

do the pop-push 4 times

Stack A:
Stack B: 1 2 3 4
Stack C

This avoids the "double mutable reference" issue, because you don't need to have two mutable references to the VecDequeue alive at the same time.这避免了“双重可变引用”问题,因为您不需要同时对 VecDequeue 有两个可变引用。

EDIT: As an aside: When dealing with recursion and running into issues, the issues can often be avoided by explicitly creating and managing a stack.编辑:顺便说一句:在处理递归和遇到问题时,通常可以通过显式创建和管理堆栈来避免这些问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM