為什麼建立一個二叉堆的時間為O(N)而不是O(Nlog(N))?

RT,今天被問到這個問題,我太笨想不明白了,請問各位大佬。

我的想法如下:

由上自下,第k層有2**(k-1)個元素,同時插入第k層元素時,需要比較(k-1)次,最後算出來結果就是O(Nlog(N))

然後csdn上有一個帖子,我沒看懂。。。請各位大佬指教

構建二叉堆時間複雜度的證明 - CSDN博客

一個小時後更新:

翻了翻《數據結構與演算法分析——C++語言描述》,已經解決,建立二叉堆的時候,不是以插入建立的,而是自下而上浮上去的,每次都只和上層比較。。。。。。


雖然已經解決了還是簡述一下:

如果用普通插入的方式,則總的時間複雜度為

Thetaleft(sum_k log k
ight) = Theta (n log n)

證明方式通過將求和放縮到積分進行,ln x的積分是 x ln x - x,再利用

int_{k-1}^{k} log x dx < log k < int_{k}^{k+1} log x dx

這樣求和就可以放縮到兩個積分上

int_{1}^{n} log x dx < sum_k log k < int_{1}^{n+1} log x dx

顯然階就是O(nlogn)了

而標準的構造方式從後往前進行,越是底層的節點需要的步驟反而越少,因為底層節點很多而上層節點少,於是節約了時間,總的時間複雜度為

Theta left(sum_k (log n - log k)
ight) = Theta(n)

證明方式仍然是放縮到積分,跟上面一樣的,不再贅述

證明求和式的階的最簡便的方法之一就是放縮到積分,對於單調函數非常有效。除此以外,錯位相加(或者叫做Abel求和公式)也是常用的方法。

補充一下,準確來說前面求和當中的log k應該是要向下取整的,但是因為每個取整的誤差不超過1,累積不超過O(n),而這裡的複雜度總和肯定是超過O(n)的,所以這部分誤差不會影響最後結果,如果是考試題的話,最好改用:

int_{k-1}^{k} (log x - 1) dx < lfloor log k 
floor < int_{k}^{k+1} log x dx

當然結果是沒有區別的。


構建堆的過程其實和錦標賽是一樣的:

數一下非葉子節點個數就是n-1個。


為什麼會邀請我回答這個問題(; ̄ェ ̄)

我演算法學的像屎一樣……

不過題目中說已經解決了,但我還是給你提供一點微不足道的幫助吧_(′?`」 ∠)_

我印象中『演算法藝術與信息學競賽』上面有一個關於這個問題的證明。

鏈接:https://pan.baidu.com/s/1o7RTT2a 密碼:gY72

諾,這是pdf (這本書寫的很好


直接按照插入的方法建堆當然是nlogn的……

但是如果使用隊列建堆……用左偏樹來搞……複雜度就是n的……


這是小學知識

題主需要回小學重造


推薦閱讀:

能否用通俗易懂的方法解釋下不相交集這種數據結構?
為什麼下面的代碼,鏈表的創建中,插入和刪除的操作中返回值是對象指針?
《數據結構與演算法分析C語言描述》真的適合初學者嗎?
文科生跨考類計算機專業,求分析?
O(1)刪除鏈表節點?

TAG:數據結構 | CC | 演算法與數據結構 |