Algorithm 非专业人士的摊销复杂性';什么条件?
有人能用外行的术语解释摊销后的复杂性吗?我一直很难在网上找到一个精确的定义,我不知道它与算法分析有什么关系。任何有用的东西,即使是外部引用的,都将受到高度赞赏。摊销复杂性原则是,尽管某些事情在你做的时候可能相当复杂,但由于不经常做,因此被认为是“不复杂”。例如,如果您创建了一个需要不时进行平衡的二叉树(例如,每Algorithm 非专业人士的摊销复杂性';什么条件?,algorithm,amortized-analysis,Algorithm,Amortized Analysis,有人能用外行的术语解释摊销后的复杂性吗?我一直很难在网上找到一个精确的定义,我不知道它与算法分析有什么关系。任何有用的东西,即使是外部引用的,都将受到高度赞赏。摊销复杂性原则是,尽管某些事情在你做的时候可能相当复杂,但由于不经常做,因此被认为是“不复杂”。例如,如果您创建了一个需要不时进行平衡的二叉树(例如,每2^n插入一次),因为平衡树非常复杂,但每n次插入只发生一次(例如,在插入编号256处一次,然后在512th、1024th处再次发生)。在所有其他插入上,复杂性是O(1)-是的,每n个插入
2^n
插入一次),因为平衡树非常复杂,但每n次插入只发生一次(例如,在插入编号256处一次,然后在512th、1024th处再次发生)。在所有其他插入上,复杂性是O(1)-是的,每n个插入需要O(n)一次,但它只是1/n
概率-因此我们将O(n)乘以1/n得到O(1)。这就是所谓的“O(1)的摊销复杂性”——因为当你添加更多的元素时,重新平衡树所花费的时间是最小的 摊销指的是在重复运行中进行分割。最坏情况下的行为保证不会频繁发生。例如,如果最慢的情况是O(N),但发生这种情况的机会只有O(1/N),否则过程是O(1),那么算法仍然会有摊销常数O(1)时间。只需将每个O(n)运行的工作分为N个其他运行。
这个概念取决于是否有足够的跑步时间来分配总时间。如果算法只运行一次,或者每次运行都必须满足截止日期,那么最坏情况下的复杂度更为相关。这有点类似于将算法中不同分支的最坏情况复杂度乘以执行该分支的概率,然后将结果相加。因此,如果某个分支不太可能被采用,那么它对复杂性的贡献就较小 摊销复杂度是在一系列操作中评估的每个操作的总费用 其想法是保证整个序列的总费用,同时允许单个操作比摊余成本昂贵得多 示例:
C++的代码> STD::向量< /代码>。当
push_back()
将向量大小增加到其预先分配的值以上时,它将使分配的长度加倍
因此,执行单个push_back()
可能需要O(N)
时间(因为数组的内容被复制到新的内存分配中)
但是,由于分配的大小增加了一倍,对push_back()
的下一次N-1
调用将分别花费O(1)
时间执行。因此,N
操作的总数仍然需要O(N)
时间;因此,每次操作的摊余成本为O(1)
除非另有规定,摊销复杂性是任何操作序列的渐近最坏情况保证。这意味着:
- 与非摊销复杂性一样,用于摊销复杂性的big-O表示法忽略了固定的初始开销和恒定的性能因素。因此,为了评估big-O摊销绩效,您通常可以假设任何摊销操作序列都“足够长”以摊销固定的启动费用。具体来说,对于
示例,这就是为什么您不必担心是否会遇到std::vector
额外的操作:分析的渐进性质已经假设您会遇到N
- 除了任意长度外,摊销分析不会对您正在计量成本的操作顺序做出假设——它是对任何可能的操作顺序的最坏情况保证。无论操作选择得多么糟糕(比如,恶意对手!),摊销分析必须确保足够长的操作顺序的成本不会持续超过其摊销成本的总和。这就是为什么(除非作为限定词特别提及)“概率”和“平均情况”与摊销分析不相关的原因——它们与普通最坏情况下的大O分析不相关
put(x): Push x on the right-hand stack.
y=get(): If the left-hand stack is empty:
Pop each element off the right-hand stack and
push it onto the left-hand stack. This effectively
reverses the right-hand stack onto the left-hand stack.
Pop and return the top element of the left-hand stack.