优先队列主要用来处理部分有序的问题,例如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);
}
}
}