算法(第四版)读书笔记--排序(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);
        }
    }
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值