堆解密,二叉堆到底是樹還是隊列,二叉堆和堆棧有關係嗎?

在學習計算機編程的時候,堆棧是我們最經常使用到的概念,也是2種最基本的內存管理方式。可是在數據結構算法也有一個,還有叫二叉堆的,那麼堆棧的堆、堆、和二叉堆,到底是什麼,它們之間有關係嗎,本文就是來解密。

先說結論,數據結構中的二叉堆是一個概念,它們和內存管理中的沒有半毛錢的關係。爲了區別說法,本文我們稱前者是二叉堆,後者叫內存堆

內存堆

內存堆通常和棧出現在一起叫內存堆棧:

  • 棧:是指函數調用是參數和局部變量的存儲方式。在函數調用的時候由系統分配一塊連續內存,局部變量都存在在棧中,在函數結束後統一釋放。函數間的調用關係也是由函數棧通過先進先出的規則管理。
  • 堆:是動態分配的,需要程序主動控制。

二叉堆

設想我們有一個垃圾桶問題。假設:

  • 總共有7個固定的放垃圾桶的位置
  • 垃圾車隔10分鐘來一次,每次把一個最重的垃圾桶拉走
  • 居民每隔10分鐘會放一個新的垃圾桶,重量不定

要求設計一個方案,使得工作最輕鬆。


方案一,沒有任何設計的情況

  • 垃圾車取垃圾時,要每個秤一遍,選取最重的後拖走
  • 居民看到空的位置放上去。
    這個方案,垃圾車每次都需要:秤7次

方案二,每次都排序好

既然,垃圾車每次都要秤7次,不如我們先排好序,方案如下:

  • 垃圾車每次都在1號位置取
  • 居民沒次把垃圾桶排好序。
    這個方案優化了垃圾車都是一次搬走,但是對於居民每次要排序,怎麼排呢?最節省的方式是用二分查找,如下圖:

    先秤4號位置的垃圾桶,如果更輕,則再比較6號位置的,如果更輕,則最後比較7號位置的,如果還是更輕,則所有的桶需要向前移動一位,然後放到7號位置,如下圖:

    該方案的最壞情況,每次需要:秤3次,移6次

二叉堆出場

二叉堆排序,滿足以下要求:

  • 全二叉樹(即:一定要先填滿上面的)
  • 父節點比子節點重:如上所示,1比2和3重,2比4和5重,3比6和7重。

注意:這不是二叉搜索樹,二叉搜索樹是父節點比左子節點重,但比右子節點輕。

  • 二叉堆看着是二叉樹,實際上在存儲中還是使用數組,由於是全二叉樹,子節點可以通過2*k2*k + 1來定位。比如對於3號位置,其子節點就是3*2=63*2+1=7號位置。
    先看垃圾車的操作,最重在1號位置,所以1次搬走。
    再看居民的操作,假設新來一個垃圾桶是6kg:
    第一步:首先填上空着的1號位置,如下圖。之後,要把1號位置下沉到合適位置。

  • 第二步:先和兩個子節點比較,即2和3號位置,如果都比它們重則完成,否則和最重的交換位置,本例中,和3號交換位置如下。這一步:秤2次,移動1次


  • 第三步:先和兩個子節點比較,即6和7號位置,如果都比它們重則完成,否則和最重的交換位置,本例中,和7號位置交換。這一步:秤2次,移動1次。



    最壞的情況:秤4次,移2次

比較3種算法

方案 操作次數 複雜度
方案一 秤7次 O(N)
方案二 秤3次,移6次 O(N)
方案三 秤4次,移2次 O(Log(N))

顯然方案三最優。因爲數量較少,所以方案三的優勢不明顯,當數量逐漸增加時,Log(N)和N的差距就會越來越大。當有10000個垃圾桶時,以下是數據,這個優勢就是數量級的:

方案 操作次數 複雜度
方案一 秤10000次 O(N)
方案二 秤13次,移9999次 O(N)
方案三 秤14次,移14次 O(Log(N))

總結

  • 內存堆棧的堆和數據結構中的堆,沒有聯繫,它們只是都有上面小下面大,有點像米堆,呵呵;
  • 二叉堆二叉搜索樹的區別是,前者父節點比子節點都大,後者是父節點比左節點大,比右節點小;
  • 二叉堆算法被普遍用於調度算法中,其核心操作是獲取最大的插入二叉堆保證所有操作的複雜度在log(N)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章