算法(第四版)讀書筆記--排序(5)優先隊列

優先隊列主要用來處理部分有序的問題,例如N個元素抽取M個最小元素,堆是可以處理有限隊列的一種方式,需要注意的是堆有序不等同於數據有序。二叉堆可以保證每個節點的數據都大於或者小於他的子節點,前者叫做最大堆,後者叫做最小堆,可以分別處理抽取出最小值和最大值的問題。以最大堆爲例,如果要從M個數據中抽取N個最小的,每次新數據和堆頂最大值進行交換,然後採用下沉的方式保證堆有序,可以獲取N個最小值。最大堆實現如下:


public class MaxPQ<T> where T : IComparable
{
    /// <summary>
    /// 
    /// </summary>
    int MAX;

    /// <summary>
    /// 數據的數量,數據從PQ[1]開始存儲
    /// </summary>
    int Count = 0;

    /// <summary>
    /// 基於堆的完全二叉樹
    /// </summary>
    List<T> PQ;
    public MaxPQ(int n)
    {
        MAX = n;
        PQ = new List<T>(MAX + 1);
        for(int i=0;i<n+1;i++)
        {
            PQ.Add(default(T));
        }
        Count = 0;
    }

    public bool isEmpty()
    {
        return Count == 0;
    }

    public int size()
    {
        return Count;
    }

    /// <summary>
    /// 添加一個元素
    /// </summary>
    /// <param name="v"></param>
    public void insert(T v)
    {
        PQ[++Count] = v;
        swim(Count);
    }

    /// <summary>
    /// 返回最大元素
    /// </summary>
    /// <returns></returns>
    public T delMax()
    {
        //最大值爲第一個數據,數據從下標1開始放
        T max = PQ[1];
        //交換第一個與最後一個元素
        exch(1, Count--);
        //下潛保證堆有序,注意堆有序不代表數組有序
        sink(1);

        return max;
    }

    public void test()
    {
        while (Count > 0)
        {
            Console.Write(delMax().ToString() + "  ");
        }
        Console.ReadKey();
    }
    
    /// <summary>
    /// 比較
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    bool less(int a, int b) 
    {
        return PQ[a].CompareTo(PQ[b]) < 0;
        
    }

    /// <summary>
    /// 交換
    /// </summary>
    /// <param name="i"></param>
    /// <param name="j"></param>
    void exch(int i, int j) 
    {
        T tem;
        tem = PQ[i];
        PQ[i] = PQ[j];
        PQ[j] = tem;
    }

    /// <summary>
    /// 由下至上的上浮
    /// </summary>
    public void swim(int k)
    {
        while (k > 1 && less(k / 2, k))
        {

            exch(k / 2, k);
            k = k / 2;
        }
    }

    /// <summary>
    /// 由上至下的下潛
    /// </summary>
    public void sink(int k)
    {
        while (2*k <= Count)
        {
            int j = 2 * k;
            if (j < Count && less(j, j+1)) j++;
            if (!less(k, j))
            {
                break; 
            }
            exch(j, k);
            k = j;
        }
    }
    
    
}

,同時堆排序可以看做一種選擇排序,複雜度略高於快速排序,實現如下:

class Sort_Heap<T> where T: IComparable
{
    

    /// <summary>
    /// 數據的數量,數據從PQ[1]開始存儲
    /// </summary>
    int Count = 0;

    /// <summary>
    /// 基於堆的完全二叉樹
    /// </summary>
    List<T> PQ;
    public Sort_Heap(int n)
    {
        PQ = new List<T>(n + 1);
        for (int i = 0; i < n + 1; i++)
        {
            PQ.Add(default(T));
        }
        Count = 0;
    }

    public bool isEmpty()
    {
        return Count == 0;
    }

    public int size()
    {
        return Count;
    }

    /// <summary>
    /// 添加一個元素
    /// </summary>
    /// <param name="v"></param>
    public void insert(T v)
    {
        if (++Count >= PQ.Count)
        {
            PQ.Add(v);
        }
        else
        {
            PQ[Count] = v;
        }
        swim(Count);
    }

    /// <summary>
    /// 返回最大元素
    /// </summary>
    /// <returns></returns>
    public T delMax()
    {
        //最大值爲第一個數據,數據從下標1開始放
        T max = PQ[1];
        //交換第一個與最後一個元素
        exch(1, Count--);
        //下潛保證堆有序,注意堆有序不代表數組有序
        sink(1, Count);

        return max;
    }

    public void test()
    {
        for (int i = 0; i < Count; i++)
        {
            Console.Write(" " + PQ[i + 1] + " ");
        }
        Console.ReadKey();
    }

    /// <summary>
    /// 比較
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    bool less(int a, int b)
    {
        return PQ[a].CompareTo(PQ[b]) < 0;

    }

    /// <summary>
    /// 交換
    /// </summary>
    /// <param name="i"></param>
    /// <param name="j"></param>
    void exch(int i, int j)
    {
        T tem;
        tem = PQ[i];
        PQ[i] = PQ[j];
        PQ[j] = tem;
    }

    /// <summary>
    /// 由下至上的上浮
    /// </summary>
    public void swim(int k)
    {
        while (k > 1 && less(k / 2, k))
        {

            exch(k / 2, k);
            k = k / 2;
        }
    }
    

    /// <summary>
    /// 由上至下的下潛
    /// </summary>
    public void sink_sort(int k)
    {
        while (2 * k <= Count)
        {
            int j = 2 * k;
            if (j < Count)
            {
                if (less(k, j + 1))
                {
                    exch(k, j);
                    exch(j, j + 1);
                    k = j + 1;
                }
                else if (less(k, j))
                {
                    exch(k, j);
                    k = j;
                }
                else
                {
                    break;
                }
            }
            else
            {
                if (less(k, j))
                    exch(k, j);
                break;
            }
        }
    }
    

    /// <summary>
    /// 由上至下的下潛
    /// </summary>
    public void sink(int k , int N)
    {
        while (2 * k <= N)
        {
            int j = 2 * k;
            if (j < N && less(j, j + 1)) j++;
            if (!less(k, j))
            {
                break;
            }
            exch(j, k);
            k = j;
        }
    }
    /// <summary>
    /// 堆排序,最大堆,非遞增排序,如需改爲遞減修改less函數即可
    /// </summary>
    public void sort(List<T> v)
    {
        int N = v.Count;
        Count = N;
        v.Insert(0, default(T));
        PQ = v;
        for (int i = N / 2; i >= 1; i--)
        {
            sink(i, N);
        }
        while (N > 1)
        {
            exch(1, N--);
            sink(1, N);
        }
    }
}
 

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