队列将插入到后面并从前面移除。但是,队列的前端位于堆栈的底部。
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。
如果您了解foo_1 中的局部函数变量top 不受对foo_2 的调用的影响,那么您已经了解局部函数变量驻留在特定于对foo_1 的调用的保护区中.这个保护区有时被称为激活记录。对foo_1 的调用会为该调用创建一个激活记录以保存本地函数状态(如变量、返回值、当前正在运行的代码行等),如果foo_1 调用另一个函数,则一个新的激活被推到当前激活的顶部以处理该函数调用的本地函数状态。当该函数调用返回时,它的激活记录被弹出,并且当前激活记录返回到调用者的,foo_1。由于函数调用的激活记录的推送,以及函数调用返回时激活记录的弹出,激活记录的结构称为call stack(而激活记录也称为@987654322 @)。
递归调用的唯一技巧是函数调用自身。但是,就像常规函数调用一样,新的激活记录会被推送到调用堆栈中。
作为一个简单的说明,假设队列具有三个元素,1、2、3,其中1 位于队列的前面。所以递归remove到达底部后的激活记录如下:
top: 1
----
top: 2
result: ? (waiting for result of remove())
----
top: 3
result: ? (waiting for result of remove())
----
在调用堆栈的顶部,queue 使用的stack 现在为空,因此返回了1,因此激活记录堆栈发生了变化:
top: 2
result: 1
----
top: 3
result: ? (waiting for result of remove())
----
在此激活记录中,2 被推回stack,并返回result,因此激活记录堆栈发生变化:
top: 3
result: 1
----
在此激活记录中,3 被推回stack,并返回result,相对于对remove 的初始调用,激活记录堆栈现在为空。