優先隊列主要用來處理部分有序的問題,例如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);
}
}
}