數據結構之大/小頂堆--C#版

面試考察頻率:⭐⭐⭐⭐

什麼是大/小頂堆?

大/小根堆的實現可以看似爲一顆完全二叉樹,但和完全二叉樹還是有區別的(具體的完全二叉樹在之後會講。
堆頂元素爲整個堆的最大/小元素。

使用情景?

局部元素排序、實現優先隊列、SPFA優化

如何來實現?

構建思路如下
⚪操作只有Push和Pop。
⚪文中通過數組來實現,本文主要講解大頂堆(小頂堆同理),只要任意保證子節點小於父節點就可以。存儲可以從下標從0開始或下標從1開始,個人更偏向於使用從1開始存儲的方式操作更方便。
⚪從0開始存儲時,獲取子節點的公式爲:左孩子爲parent2+1,右孩子爲parent2+2。 獲取父節點的公式爲:(child-1)/2
⚪從1開始存儲時,獲取子節點的公式爲:左孩子爲parent2,右孩子爲parent2+1。 獲取父節點的公式爲:child/2。
在這裏插入圖片描述
基礎結構表示:

 		int[] heap = new int[1000];
        int heapSize = 0;


Push元素:

 		public void Push(int x)
        {
            //思路:每次先將新元素放到最後,在進行調整。從下向上,比較父元素
            heap[++heapSize] = x;
            int now = heapSize, nxt = 0;

            while (now > 1)
            {
                nxt = now / 2;
                if (heap[now] <= heap[nxt]) break;
                Swap(ref heap[now], ref heap[nxt]);
                now = nxt;
            }
        }
每次講新元素放到堆的最後,在從下向上進行調整。
如果父節點比子節點小就交換當前子節點和父節點,爲了始終保持父節點大於子節點。
如果出現父節點大於子節點的情況退出循環。

Pop元素:

        public int Pop()
        {
            //思路:把頂的元素先存到零時變量中,在將堆末尾的元素覆蓋到頂元素完成刪除。之後再由頂	
            //      向下進行調整。上一個元素比較子兩個元素,其中要比較兩個子元素的大小,選擇最大/	小的與上邊的元素進行交換
            int res = heap[1];
            int now = 1, nxt = 0;
            heap[1] = heap[heapSize--];

            while (now * 2 <= heapSize)
            {
                nxt = now * 2;
                if (heap[nxt + 1] > heap[nxt] && nxt + 1 <= heapSize) nxt++;
                if (heap[nxt] <= heap[now])
                {
                    return res;
                }
                Swap(ref heap[nxt], ref heap[now]);
                now = nxt;
            }
            return res;
        }
每次將堆頂元素保存到臨時變量中(因爲堆頂元素要Pop出去,最後還要返回堆頂元素所以需要保存下來)。
之後把堆尾元素覆蓋到堆頂元素去,再從上到下調整整個堆。
其中要注意,由於子節點有兩個,一定要選最大的進行於父節點交換。所以注意這個情況的判定。

完整代碼如下,更多數據C#數據結構源碼歡迎瀏覽我的倉庫:https://github.com/w199753/DataStructural-CSharp 最後附上完整代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataStructural
{
    /// <summary>
    /// 大根堆。小根堆實現方法相同
    /// </summary>
    public class MaxHeap
    {
        int[] heap = new int[1000];
        int heapSize = 0;

        /// <summary>
        /// 添加元素
        /// </summary>
        /// <param name="x"></param>
        public void Push(int x)
        {
            //思路:每次先將新元素放到最後,在進行調整。從下向上,比較父元素
            heap[++heapSize] = x;
            int now = heapSize, nxt = 0;

            while (now > 1)
            {
                nxt = now / 2;
                if (heap[now] <= heap[nxt]) break;
                Swap(ref heap[now], ref heap[nxt]);
                now = nxt;
            }
        }

        /// <summary>
        /// 刪除元素並返回最大值
        /// </summary>
        /// <returns></returns>
        public int Pop()
        {
            //思路:把頂的元素先存到零時變量中,在將堆末尾的元素覆蓋到頂元素完成刪除。之後再由頂	
            //      向下進行調整。上一個元素比較子兩個元素,其中要比較兩個子元素的大小,選擇最大/	小的與上邊的元素進行交換
            int res = heap[1];
            int now = 1, nxt = 0;
            heap[1] = heap[heapSize--];

            while (now * 2 <= heapSize)
            {
                nxt = now * 2;
                if (heap[nxt + 1] > heap[nxt] && nxt + 1 <= heapSize) nxt++;
                if (heap[nxt] <= heap[now])
                {
                    return res;
                }
                Swap(ref heap[nxt], ref heap[now]);
                now = nxt;
            }
            return res;
        }

        public void Clear()
        {
            heap = new int[1000];
            heapSize = 0;
        }
        private void Swap(ref int a, ref int b)
        {
            a ^= b;
            b ^= a;
            a ^= b;
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章