我知道队列/链接列表的典型实现中的push()和pop()方法是如何工作的,但我想知道的是你实际定义为push或pop的内容?什么时候可以命名方法push()/ pop()?是什么使得insert()/ add()方法在典型的Tree实现中不是push()?
我的理解是push()ing意味着把东西放到某个特殊指针所指向的位置,而pop()ping一个元素意味着把一些对象放在一些指针指向的位置,但它似乎不是明确规定。或者命名是否重要?
答案 0 :(得分:37)
当引用链接列表上的操作时,您可以将项目推送到列表以添加它们。然后,您可以从列表中弹出项目以将其删除。
如果您从添加它们的列表的同一端弹出项目,则表示已实现堆栈或后进先出(LIFO)数据结构:
如果您从对端弹出项目,那么您已经实现了一个队列 - 尽管术语通常是“入队”和“出队”。这是先进先出(FIFO)数据结构:
答案 1 :(得分:8)
术语推送和弹出通常用于stacks,而不是queues或linked lists。堆栈是后进先出(LIFO)数据结构;换句话说,要删除的第一件事是最近添加的项目。推送是指将新项目放入堆栈时,当您将其取下时弹出即可。
许多编程语言允许您以任何方式编写代码,包括使用名称push和pop来表示任何和所有数据结构,即使这不是您真正正在做的事情。但是,我不推荐它。使用其他人使用的术语要好得多,以便其他程序员可以读取您的代码。此外,使用错误的术语可能会使工作变得困难,并且如果您正在处理项目(工作或开源),将难以与其他程序员进行通信。
答案 2 :(得分:2)
推送表示将项目放入堆栈(数据结构),以便它成为堆栈的最顶层项目。 弹出表示从堆栈中删除最顶层的项目。 (你经常会听到第三个词,偷看,这意味着查看/阅读最顶层的项目。)
对于队列,您通常应该使用排队和出列这两个词,而前者意味着将项目附加到queue的“后端”,后者意味着从队列中删除“前端”的项目。
这些定义表明堆栈(如果您在脑中描绘它)在空间上是垂直的,而队列是水平的。另一个区别是堆栈上的操作总是发生在同一端,而队列上的操作发生在相反的两端。
当谈到链接列表和双端队列(deques)时,术语推送和 pop 也被使用,例如在C ++的STL中,您可以使用push_front
,push_back
,pop_front
和pop_back
等操作。这些只是暗示可以在两端附加或删除项目。
至于为什么 pop 被调用,而不是拉(与推送相比)......好问题。
答案 3 :(得分:1)
Push / Pop最初与asm land中的堆栈命令相关。推送将值(寄存器)放在堆栈上并更新堆栈指针,同时pop从堆栈中获取值并减少指针。这里没有插入,这意味着存在某种偏移。这就是你也有push / pop _front()和push / pop _back()函数的原因。它们代表推/弹操作的静态位置。
答案 4 :(得分:1)
至少在C ++中,push和pop只引用堆栈和队列之类的结构,其中操作所在的位置是数据结构中固有的。对于其他容器,例如矢量和列表,我们有push_back,push_front,pop_back等。对于我们实际上不知道项目最终位置的容器,或者我们将从哪里读取它,push和pop不用于所有
答案 5 :(得分:1)
Push和Pop只是从堆栈数据结构中插入和删除项目的操作的常规名称。任何遵循后进先出模式(LIFO)的操作通常称为Push和Pop,但它们可以被称为任何你喜欢的。
答案 6 :(得分:1)
推送和 pop 的命名可能只是为了区分可以在堆栈上执行的操作和可以在列表上执行的操作。您也可以将它们称为添加和删除,但这些通常意味着您可以在列表中的任何位置添加或删除元素,而不是仅仅在开头(或结束,如果你这样想的话)。同样,存在排队和出队,因为推送和弹出意味着插入或移除发生在同一位置,而不是在列表的两端。
如果您需要技术定义,您可能会说推送和 pop 是影响LIFO中列表同一端的O(1)操作(最后,先出)方式。
答案 7 :(得分:1)
Push和pop最初用于引用堆栈操作,但非正式地,这些术语通常用于涉及在任何线性数据结构(如堆栈,队列,数组或链接)的末尾添加/删除元素的操作列表。
答案 8 :(得分:0)
推送只是将一个项目添加到集合的开头(或结尾)。 Popping正在删除相同的项目。
在Java中,List接口添加了(0,item)和remove(0)。这些与push(item)和pop()实际上是相似的。
然而,push和pop以及堆栈的特定行为很有趣,因此许多都有专门的数据结构,使推送和弹出特别有效。
答案 9 :(得分:0)
你问的大多数都是惯例。对于队列,您可以推送或排队。你会看到两者。对于堆栈,您将看到添加或推送。对它来说,没有真正的硬性和快速的“规则”。如果您使用的语言使用“推送”作为惯例,请使用“推送”。命名很重要,但仅限于可用性和常识。只需确保您的命名在单个应用程序或系统中保持一致。
答案 10 :(得分:0)
在谈论堆栈时会使用名称push和pop。堆栈是后进先出(LIFO)。因此,名称表明pop将返回推送的最后一件事。
答案 11 :(得分:0)
直观地说,我们认为堆栈是我们可以推送值的东西,其最高值是最后推送的东西,并且如果我们弹出一个我们已推送值的堆栈,我们就有了原始堆栈。
这种直觉可以被视为抽象的代数, 使用Push和Pop表示对涉及ELements的Stack的数据对象的任何计算:
algrebra Stack
{
data Stack;
data Element;
Empty() -> Stack;
Push(Stack,Element) -> Stack;
Pop(Stack) -> Stack;
Top(Stack) -> Element;
axiom Top(Push(s,e))==e;
axiom Pop(Push(s,e))==s;
axiom Pop(Empty())==undefined;
}
这说明如果您可以在系统中找到实体,
那么各种函数的签名与代数中的签名相匹配, 如果您应用各种功能,它们将表现为 公理具体说明。 (您选择的实体是“同构的” 到代数)。
这种观点的优势在于它说没有 实现各种实体,同时仍然捕捉到本质。 这个代数涵盖了其他答案中讨论的各种工件; 应该清楚的是,用作堆栈的线性存储区域是堆栈, 链表使用堆栈是堆栈,deque使用的一端是堆栈, 用作堆栈的一系列磁盘块是堆栈,......
真正酷的是您可以重命名所有数据类型和功能 在堆栈代数中,但仍然可以识别堆栈,因为重命名 对同构不起作用(因为一致的重命名只是另一种同构, 和同构构成产品同构)。任何匹配的东西 这个规范是一个堆栈!
实现中的函数名称可以是任何东西 但仍然匹配,我们可以重命名抽象代数函数名称 任何东西,仍然匹配,按照惯例,允许我们给出抽象 代数函数命名我们认为具有代表性的函数。 “推” 而“pop”是按惯例选择的。
所以我要说,你可以把你的名字称为你的实施功能 比如说,如果他们的动作实现了这个代数,那么称他们为Push and Pop。
因此,可以通过正式规范定义Stack。您可以定义任何其他数据结构 这样也是。
太糟糕了,我们在记录实际代码方面没有做更多的事情。
答案 12 :(得分:0)
堆栈的基本操作是推送和弹出。术语push用于将一些数据元素放入堆栈中,pop用于从堆栈中删除一些数据元素。