Big o 大Oh符号-推送和弹出

Big o 大Oh符号-推送和弹出,big-o,Big O,我想我至少已经开始理解大Oh符号背后的理论了,也就是说,它是一种测量函数增长速度的方法。换句话说,大O量化了算法的效率。但它的实施是另一回事 例如,在最佳情况下,推拉操作将是O(1),因为从堆栈中移除或添加到堆栈中所需的步骤数将是固定的。不管值是多少,过程都是一样的 我试图设想一系列事件(如推送和弹出)如何将性能从O(1)降低到O(n^2)。如果我有一个包含n/2容量、n个推送和弹出操作的数组,以及一个动态数组,在满或半满时将其容量加倍或减半,那么这些操作发生的顺序如何可能影响程序完成的速度?由

我想我至少已经开始理解大Oh符号背后的理论了,也就是说,它是一种测量函数增长速度的方法。换句话说,大O量化了算法的效率。但它的实施是另一回事

例如,在最佳情况下,推拉操作将是O(1),因为从堆栈中移除或添加到堆栈中所需的步骤数将是固定的。不管值是多少,过程都是一样的

我试图设想一系列事件(如推送和弹出)如何将性能从O(1)降低到O(n^2)。如果我有一个包含n/2容量、n个推送和弹出操作的数组,以及一个动态数组,在满或半满时将其容量加倍或减半,那么这些操作发生的顺序如何可能影响程序完成的速度?由于push和pop在堆栈的顶部元素上工作,所以我很难看到效率如何从常数变为O(n^2)

提前感谢。

如果我将堆栈实现为(比如)一个链表,那么push和pop将始终是固定时间(即O(1))

我不会为堆栈选择动态数组实现,除非运行时对我来说不是问题,我碰巧有一个动态数组已经构建好并且可以使用,而且我手头没有一个更高效的堆栈实现。但是,如果我确实使用了一个数组,当它分别变为满或半空时,它的运行时间将是O(1),而推送和弹出的数量足够低,不会触发调整大小,当有调整大小时,它的运行时间将是O(n)(因此总的O(n))

我想不出一个用作堆栈的动态数组可以提供像O(n^2)一样差的性能,除非它的实现中有一个bug。

如果我将堆栈实现为(比如)一个链表,那么push和pops将始终是常数时间(即O(1))

我不会为堆栈选择动态数组实现,除非运行时对我来说不是问题,我碰巧有一个动态数组已经构建好并且可以使用,而且我手头没有一个更高效的堆栈实现。但是,如果我确实使用了一个数组,当它分别变为满或半空时,它的运行时间将是O(1),而推送和弹出的数量足够低,不会触发调整大小,当有调整大小时,它的运行时间将是O(n)(因此总的O(n))


我想不出哪种情况下,用作堆栈的动态数组可以提供与O(n^2)一样差的性能,除非它的实现中存在错误。

您假设动态数组非常智能地执行其调整大小操作。但是,如果不是这样,您可能会得到一个O(n^2)运行时:假设数组在满时大小不会翻倍,而只是调整为大小+1。另外,假设它以大小1开始。在O(1)中插入第一个元素。插入第二个elment时,需要将数组的大小调整为2,要求它复制上一个值。插入元素k时,它当前的大小为k-1,需要调整大小为k,从而产生需要复制的k-1元素,以此类推


因此,对于插入n个元素,最终将复制数组n-1次:O(n)调整大小。复制操作也与n成线性关系,因为插入的元素越多,需要复制的元素就越多:每次调整大小复制O(n)个副本。这将导致O(n*n)=O(n^2)作为其运行时复杂性。

您假设动态数组非常智能地执行其调整大小操作。但是,如果不是这样,您可能会得到一个O(n^2)运行时:假设数组在满时大小不会翻倍,而只是调整为大小+1。另外,假设它以大小1开始。在O(1)中插入第一个元素。插入第二个elment时,需要将数组的大小调整为2,要求它复制上一个值。插入元素k时,它当前的大小为k-1,需要调整大小为k,从而产生需要复制的k-1元素,以此类推


因此,对于插入n个元素,最终将复制数组n-1次:O(n)调整大小。复制操作也与n成线性关系,因为插入的元素越多,需要复制的元素就越多:每次调整大小复制O(n)个副本。这将导致O(n*n)=O(n^2)作为其运行时复杂性。

。。。@rainer很好地描述了这类错误。这里的一个微妙之处是,当我说链接列表的“推送和弹出将始终是恒定时间”时,单个推送或弹出将是恒定时间,但正如@rainer所指出的,
n
推送或弹出当然需要与
n
成比例的时间。。。。@rainer很好地描述了这类错误。这里的一个微妙之处是,当我说链接列表的“推送和弹出始终是恒定时间”时,单个推送或弹出将是恒定时间,但正如@rainer所指出的那样,
n
推送或弹出当然需要与
n
成比例的时间。