我认为我开始至少理解大哦符号背后的理论,即它是一种测量函数速度增长速率的方法。换句话说,大O量化了算法的效率。但是它的实现是另一回事。
例如,在最佳情况下,推拉操作将为O(1),因为从堆栈中删除或添加到堆栈所需的步骤数将被修复。无论价值如何,过程都是一样的。
我试图想象一下诸如push和pop之类的事件序列如何降低从O(1)到O(n ^ 2)的性能。如果我有一个n / 2容量数组,n个推送和弹出操作,以及一个动态数组,当满或半满时将其容量加倍或减半,那么这些操作发生的顺序如何可能影响到程序完成了哪些?由于push和pop工作在堆栈的顶部元素上,我很难看到效率如何从常量变为O(n ^ 2)。
提前致谢。
答案 0 :(得分:4)
您假设动态数组非常智能地执行其调整大小操作。但是,如果不是这种情况,您最终可能会遇到O(n ^ 2)运行时:假设数组在完全时不会使其大小加倍,而只是将其大小调整为大小+ 1。另外,假设它从大小1开始。您将在O(1)中插入第一个元素。插入第二个元素时,需要将数组大小调整为大小2,要求它复制先前的值。当插入元素k时,它当前的大小为k-1,需要调整大小为k,导致需要复制的k-1个元素,依此类推。
因此,为了插入n个元素,你最终会复制数组n-1次:O(n)调整大小。复制操作也线性地依赖于n,因为插入的元素越多,就越需要复制:每次调整大小为O(n)个拷贝。这导致O(n * n)= O(n ^ 2)作为其运行时复杂度。
答案 1 :(得分:2)
如果我将堆栈实现为(比如说)链表,那么推送和弹出将始终是恒定时间(即O(1))。
我不会为堆栈选择动态数组实现,除非运行时对我来说不是问题,我碰巧有一个现成的动态数组,可以使用,而且我没有更高效的堆栈实施得心应手。但是,如果我确实使用了一个数组,当它分别变为full或half-empty时向上或向下调整大小,它的运行时间为O(1),而推送和弹出的数量足够低,不会触发调整大小和O(n) )当存在调整大小时(因此总体为O(n))。
我想不出这样一种情况:用作堆栈的动态数组可以提供与O(n ^ 2)一样糟糕的性能,除非它的实现存在错误。