【问题标题】:Recursion: Implement least recently used algorithm using a stack递归:使用堆栈实现最近最少使用的算法
【发布时间】:2016-07-15 01:45:50
【问题描述】:

我需要一些关于如何解决这个问题的一般建议,而不会使问题变得过于复杂:

使用数组(而不是链表),编写 StackType 类的成员函数,该函数在引用页面时更新堆栈。假设一个堆栈可以容纳 5 个值,并且引用的下一页是 7,那么:

  • 函数在堆栈中搜索第 7 页
  • 如果找到 7,则将其从堆栈中删除并放在顶部
  • 如果 is 在列表中没有找到 7,则在堆栈中引用的最后一页被删除,并在堆栈顶部放置 7 个位置

使用以下驱动函数:

void updateRecursive(StackType<Type>& s, Type t);

调用递归函数

bool updateRecursiveDo(StackType<Type>& s, Type t);

到目前为止我所做的,我只会包括相关的功能:

  1. 我使用 LRU 算法的概念来理解这里要问的内容。

  2. 我知道我真正可以使用的唯一工具是推送和弹出。

RE:驱动函数的概念,我一直把它理解为我的 main() 程序。即调用函数的程序通常在测试的情况下完成,但根据他们提供给我的内容,我在教科书中查找了这个细节,发现公共驱动程序函数将用于调用私有递归函数以保持不。公共函数中的参数数量降至最低。

class StackType {
public: 
    void updateRecursive(StackType<Type>& s, Type t);
private:
    bool updateRecursiveDo(StackType<Type>& s, Type t);
}

template <class Type>
bool StackType<Type>::updateRecursiveDo(StackType<Type>& s, Type t) {
    if (isEmptyStack())
        return 0;
    else if(s.top() == t) {
        return 1;
    }
    else {
        s.pop();
        updateRecursiveDo(s,t);
    }
}

template <class Type>
void StackType<Type>::updateRecursive(StackType<Type>& s, Type t) {
    updateRecursiveDo(s,t);
}

所以这很好,我在 main 中调用函数如下,我搜索了 7 并找到了它:

firstStack.updateRecursive(firstStack, 7);

现在我正在做的是过度思考如何将数字替换回堆栈:

  1. 将我弹出的每个项目存储到一个数组中并遍历每个项目,然后在每个实例中将它们推回堆栈

  2. 手动将项目推回堆栈,但如果列表中不存在 7,这将不起作用

我不确定当堆栈是数组时是否有更简单的方法来处理搜索和替换?

【问题讨论】:

  • 您应该在updateRecursiveDo 方法的else 块中添加一个return 语句。

标签: c++ arrays stack


【解决方案1】:

updateRecursiveDo() 视为一种从堆栈中删除元素的方法。如果未找到该元素,则删除最后一个。

退出后,将t推到顶部。

您不是替换 t 而是删除它,然后再次添加它。

使用每个递归帧将弹出的值临时存储在内部变量中,即:

伪代码:

updateRecursiveDo(stackt stack, page t){
   x=stack.pop();
   if (x==t) return;
   if (stack.empty()) return;
   updateRecursiveDo(stack,t);
   stack.push(x);
 }

【讨论】:

  • 感谢您的回复。通过这样做,虽然我将每个元素从堆栈中弹出,最终如果我确实找到它并将其放回顶部,我弹出的所有其他元素将不再存在?这就是为什么我要寻找一种不会丢失这些元素的方法(如果不将它们弹出并将它们推回堆栈,这似乎是不可能的?)
  • 用例子更新,你是对的,这就是堆栈的工作方式。非递归替代方案是使用辅助堆栈。
  • 谢谢。有两件事。 1) 我无法将 s.pop() 分配给变量。我知道从我的研究中这是不可能的。我能做的最好的就是分配 s.top()。 2)如果我在每次递归调用之前不弹出()堆栈,我会收到错误“程序收到信号 SIGSEVG,分段错误”,据我了解,这是由于我的程序试图写入内存而不应该写入内存。所以我的意思是如果我不弹出()堆栈递归调用将永远不会结束?
  • 而且当我开始时,堆栈被初始化为最大 5 个值,所以为了推进更多(除了结束递归调用的条件),为了更确定地推进,我需要pop() 每次重复?
  • 每次调用递归时都会删除一个元素,因此您将退出 max-1 个元素。
【解决方案2】:

几个问题:

  1. 我认为您的updateRecursiveDo() 没有任何理由返回任何内容,无论是bool 还是其他任何内容。当我阅读您的问题时,updateRecursiveDo() 的目的实际上是从您的堆栈中删除t(如果存在)。它是否存在,以及此函数是否将其删除,此时不再重要,因为剩下要做的唯一步骤是将t 值推送到重建堆栈的顶部。

无论在堆栈中是否找到t,都会发生该步骤,因此返回bool 指示符是无关紧要的。

此外,在第三种情况下,您的实现未能返回 bool 值,因此无论如何这都行不通。

  1. 您的updateRecursiveDo() 版本没有正确执行此操作。让我们explain what your function does to your rubber duck

    • 如果堆栈为空,则不执行任何操作。

    • 如果栈顶的值为t,则什么也不做。

    • 否则从栈顶移除该值,然后重试。

对此,你的橡皮鸭会问以下合乎逻辑的问题:“你为什么要删除堆栈上的所有内容,直到达到值 t,这是你想要做的吗?”

当然不是,根据您对问题的描述。我对您问题中三个要点的解释是,只有值 t 应该从堆栈中删除,而不是值 t 和堆栈末尾之间的每个值。如果它不包含值 t!

,它可能是整个堆栈

现在,不如你试着向你的橡皮鸭解释以下内容:

  • 如果堆栈为空,则什么也不做。

  • 从栈顶移除值。

  • 如果值为t,则什么也不做。

  • 递归调用自身,当递归调用返回时,将值推回当前栈顶。

翻译成代码,应该是:

template <class Type>
void StackType<Type>::updateRecursiveDo(StackType<Type>& s, Type t)
{
    if (isEmptyStack())    
        return;

    auto v=s.top();

    if (v == t)
        return;

    updateRecursiveDo(s, t);

    s.push(v);
    return;
}

template <class Type>
void StackType<Type>::updateRecursive(StackType<Type>& s, Type t)
{
    updateRecursiveDo(s, t);
    s.push(t);
}

【讨论】:

  • 谢谢!最有见地,橡皮鸭调试很有意义。
猜你喜欢
  • 1970-01-01
  • 2020-04-09
  • 1970-01-01
  • 2012-10-20
  • 2016-08-20
  • 2017-04-09
  • 2018-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多