最小優先順序隊列(基於最小二元堆積演算法)

來源:互聯網
上載者:User

在最小產生樹Prim演算法中,可以利用最小優先順序隊列來改善時間複雜度,同時在單源最短路徑Dijkstra演算法中也同樣可以利用這種最小優先順序隊列來改善演算法時間複雜度。實現最小優先順序隊列可以有很多種方式,比如基於二叉最小堆,或者斐波那契堆等。這裡是二叉最小堆的C#實現,原理是根據書上的虛擬碼來的,但有些地方我做了改進,比如書key值改變,原來書上只能變大,這裡取掉了這個限制。同時還提供了根據衛星值來選擇元素的功能,下面是代碼:

 /// <summary>    /// 隊列元素封裝類    /// </summary>    /// <typeparam name="T">實際元素類型</typeparam>    public class QueueElement<T>    {        /// <summary>        /// Key值        /// </summary>        public int KeyValue { get; internal set; }        /// <summary>        /// 實際對象        /// </summary>        public T Element { get; private set; }        public QueueElement(T Item, int KeyVal)        {            KeyValue = KeyVal;            Element = Item;        }    }    /// <summary>    /// 最小優先順序隊列    /// </summary>    /// <typeparam name="T"></typeparam>    public class MinHeapQueue<T>    {        /// <summary>        /// 隊列元素存放,採用List實現.        /// </summary>        private List<QueueElement<T>> _queueValues = new List<QueueElement<T>>();        /// <summary>        /// 隊列元素數目        /// </summary>        public int Count        {            get            {                return _queueValues.Count;            }        }        /// <summary>        /// 擷取隊列Key值最小的元素        /// </summary>        /// <returns></returns>        public T GetMinimum()        {            return _queueValues[0].Element;        }        /// <summary>        /// 從隊列中取出Key值最小的元素        /// </summary>        /// <returns></returns>        public T ExtractMin()        {            if (_queueValues.Count <= 0)            {                throw new Exception("隊列為空白");            }            T theMin = _queueValues[0].Element;            int theTail = Count - 1;            _queueValues[0] = _queueValues[theTail];            _queueValues.RemoveAt(theTail);            MinHeapify(0);            return theMin;        }        /// <summary>        /// 整理堆元素,保持最小堆特性,這個函數跟DownAdjust功能相同        /// </summary>        /// <param name="i"></param>        public void MinHeapify(int i)        {            int HeapSize = Count;            int theL = HeapL(i);            int theR = HeapR(i);            int theLeast = i;            if (theL < HeapSize && _queueValues[theL].KeyValue < _queueValues[theLeast].KeyValue)            {                theLeast = theL;            }            if (theR < HeapSize && _queueValues[theR].KeyValue < _queueValues[theLeast].KeyValue)            {                theLeast = theR;            }            if (theLeast != i)            {                SwapElement(i, theLeast);                MinHeapify(theLeast);            }        }        /// <summary>        /// 改變元素key值        /// </summary>        /// <param name="SelectFunc"></param>        /// <param name="NewKey"></param>        public void ChangeKey(Func<T, bool> SelectFunc, int NewKey)        {            int theIndex = -1;            for (int i = 0; i < Count; i++)            {                if (SelectFunc(_queueValues[i].Element) == true)                {                    theIndex = i;                    break;                }            }            if (theIndex < 0)            {                return;            }            if (_queueValues[theIndex].KeyValue < NewKey)            {                _queueValues[theIndex].KeyValue = NewKey;                DownAdjust(theIndex);                return;            }            if (_queueValues[theIndex].KeyValue > NewKey)            {                _queueValues[theIndex].KeyValue = NewKey;                UpAdjust(theIndex);                return;            }        }        /// <summary>        /// 沿樹根方向整理元素,保持最小堆特性        /// </summary>        /// <param name="i"></param>        private void UpAdjust(int i)        {            int theIndex = i;            int thePIndex = HeapP(theIndex);            while (thePIndex >= 0 && _queueValues[theIndex].KeyValue < _queueValues[thePIndex].KeyValue)            {                SwapElement(thePIndex, theIndex);                theIndex = thePIndex;                thePIndex = HeapP(theIndex);            }        }        /// <summary>        /// 沿樹葉方向整理元素,保持最小堆特性        /// </summary>        /// <param name="i"></param>        private void DownAdjust(int i)        {            int HeapSize = Count;            int theL = HeapL(i);            int theR = HeapR(i);            int theLeast = i;            if (theL < HeapSize && _queueValues[theL].KeyValue < _queueValues[theLeast].KeyValue)            {                theLeast = theL;            }            if (theR < HeapSize && _queueValues[theR].KeyValue < _queueValues[theLeast].KeyValue)            {                theLeast = theR;            }            if (theLeast != i)            {                SwapElement(i, theLeast);                DownAdjust(theLeast);            }        }        /// <summary>        /// 改變元素key值        /// </summary>        /// <param name="i"></param>        /// <param name="NewKey"></param>        public void ChangeKey(int i, int NewKey)        {            int theIndex = i;            if (_queueValues[theIndex].KeyValue > NewKey)            {                _queueValues[theIndex].KeyValue = NewKey;                UpAdjust(theIndex);                return;            }            if (_queueValues[theIndex].KeyValue < NewKey)            {                _queueValues[theIndex].KeyValue = NewKey;                DownAdjust(theIndex);                return;            }        }        /// <summary>        /// 刪除隊列元素        /// </summary>        /// <param name="SelectFunc"></param>        public void HeapDelete(Func<T, bool> SelectFunc)        {            int theIndex = -1;            for (int i = 0; i < Count; i++)            {                if (SelectFunc(_queueValues[i].Element) == true)                {                    theIndex = i;                    break;                }            }            if (theIndex < 0)            {                return;            }            SwapElement(theIndex, Count - 1);            _queueValues.RemoveAt(Count - 1);            if (theIndex < Count)            {                int theP = HeapP(theIndex);                bool theUp = false;                if (theP >= 0)                {                    if (_queueValues[theIndex].KeyValue < _queueValues[theP].KeyValue)                    {                        UpAdjust(theIndex);                        theUp = true;                    }                }                if (theUp == false)                {                    MinHeapify(theIndex);                }            }        }        /// <summary>        /// 隊列元素交換位置        /// </summary>        /// <param name="i"></param>        /// <param name="j"></param>        private void SwapElement(int i, int j)        {            QueueElement<T> theTmp = _queueValues[i];            _queueValues[i] = _queueValues[j];            _queueValues[j] = theTmp;        }        /// <summary>        /// 將元素插入隊列        /// </summary>        /// <param name="Element"></param>        /// <param name="Key"></param>        public void HeapInsert(T Element, int Key)        {            _queueValues.Add(new QueueElement<T>(Element, int.MinValue));            ChangeKey(Count - 1, Key);        }        /// <summary>        /// 取節點的左孩子節點        /// </summary>        /// <param name="i"></param>        /// <returns></returns>        private int HeapL(int i)        {            return i * 2 + 1;        }        /// <summary>        /// 取節點的右孩子節點        /// </summary>        /// <param name="i"></param>        /// <returns></returns>        private int HeapR(int i)        {            return i * 2 + 2;        }        /// <summary>        /// 取節點的父節點        /// </summary>        /// <param name="i"></param>        /// <returns></returns>        private int HeapP(int i)        {            return (i + 1) / 2 - 1;        }    }

需要注意的,我前面有篇基於二叉最大堆的優先順序隊列演算法跟這篇很類似,但上篇演算法中有小錯誤,而這篇演算法中的優先順序隊列已通過測試,沒問題。大家可對比一下,看錯誤在哪裡。

Ps:既然到首頁,還是加點注釋.

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.