我找到了下面的代码。我只是想知道remove函数中的“else”部分是如何工作的。如果有人可以为我详细说明这些步骤,我将非常感激。
insert(E value)
{
stack.push(value);
}
E remove()
{
E top = stack.pop();
if(stack.isEmpty())
return top;
else
{
E result = remove();
stack.push(top);
return result;
}
}
答案 0 :(得分:1)
队列将插入后面并从前面移除。但是,队列的前面位于堆栈的底部。
remove
算法递归迭代堆栈直到它到达底部,并作为删除的结果返回该元素。随着递归的展开,它弹出到底部的成员被推回到堆栈中。因此,队列的原始顺序将被恢复,减去队列的前面(这是堆栈的底部)。
在评论中,您写道:
我需要帮助来理解这些步骤,例如存储弹出元素的位置以及在递归过程中它们是如何被推送的,以及递归调用如何管理所有这些。
递归函数调用与常规函数调用没有任何根本区别。请考虑以下伪代码:
E foo_2 ()
{
return stack.pop();
}
E foo_1 ()
{
E top = stack.pop();
if(stack.isEmpty())
return top;
else
{
E result = foo_2();
stack.push(top);
return result;
}
}
因此,对foo_1
的调用会产生一个名为top
的函数局部变量,其结果为stack.pop()
。如果stack
现在为空,则返回top
。如果stack
尚未为空,则会将foo_2
的返回值保存在result
中,然后将top
推回stack
,然后返回已保存result
。
如果您了解top
中的本地函数变量foo_1
不受foo_2
调用的影响,那么您已经了解本地函数变量位于特定于的受保护区域中致foo_1
的电话。该保护区域有时被称为激活记录。对foo_1
的调用为该调用创建了一个激活记录,以保存本地函数状态(如变量,返回值,当前正在运行的代码行等),如果foo_1
调用另一个函数,在当前函数之上推送新的激活以处理该函数调用的本地函数状态。当该函数调用返回时,将弹出其激活记录,并且当前激活记录将返回到调用者foo_1
的激活记录。由于推送函数调用的激活记录,以及函数调用返回时弹出激活记录,激活记录的结构称为call stack(激活记录也称为stack frames)。
递归调用的唯一技巧是函数调用自身。但是,新的激活记录被推送到调用堆栈,就像常规函数调用一样。
就像快速说明一样,请考虑队列有三个元素1
,2
,3
,其中1
位于队列的前面。因此,递归remove
到达底部后的激活记录将如下所示:
top: 1
----
top: 2
result: ? (waiting for result of remove())
----
top: 3
result: ? (waiting for result of remove())
----
在调用堆栈的顶部,stack
使用的queue
现在为空,因此返回1
,因此激活记录堆栈发生了变化:
top: 2
result: 1
----
top: 3
result: ? (waiting for result of remove())
----
在此激活记录中,2
被推回到stack
,并返回result
,因此激活记录堆栈发生了变化:
top: 3
result: 1
----
在此激活记录中,3
被推回到stack
,并返回result
,并且激活记录堆栈现在相对于初始呼叫为空到remove
。