代码改变世界

我写的C#优先队列

2008-09-09 18:57  JimLiu  阅读(3739)  评论(10编辑  收藏  举报

前几天才知道.NET类库里没有优先队列,而今天JAVA课上翻书时发现JAVA类库里有,不爽。本来就打算写一个的,这回正好。下午一下课就开始写,现在搞定了。

这个优先队列用二叉堆实现,泛型,需要元素实现IComparable<T>接口。

具体算法就不说了,太经典了,随便一本数据结构书都有。

堆的算法,提供了两种堆维护和一个基于堆维护的堆排序——这是一个辅助类,用于进行堆维护。

有时候用Array.Sort提供的快排腻了(还有这种人?哈哈!),玩玩堆排序也不错,常数级辅助空间,省啊!

/// <summary>
/// 大顶堆
/// </summary>
/// <typeparam name="T"></typeparam>
public class Heap<T> where T : IComparable<T> {
    
public static void HeapSort(T[] objects) {
        
for (int i = objects.Length / 2 - 1; i >= 0--i)
            heapAdjustFromTop(objects, i, objects.Length);
        
for (int i = objects.Length - 1; i > 0--i) {
            swap(objects, i, 
0);
            heapAdjustFromTop(objects, 
0, i);
        }
    }
    
public static void heapAdjustFromBottom(T[] objects, int n) {
        
while (n > 0 && objects[(n - 1>> 1].CompareTo(objects[n]) < 0) {
            swap(objects, n, (n 
- 1>> 1);
            n 
= (n - 1>> 1;
        }
    }
    
public static void heapAdjustFromTop(T[] objects, int n, int len) {
        
while ((n << 1+ 1 < len) {
            
int m = (n << 1+ 1;
            
if (m + 1 < len && objects[m].CompareTo(objects[m + 1]) < 0)
                
++m;
            
if (objects[n].CompareTo(objects[m]) > 0return;
            swap(objects, n, m);
            n 
= m;
        }
    }
    
private static void swap(T[] objects, int a, int b) {
        T tmp 
= objects[a];
        objects[a] 
= objects[b];
        objects[b] 
= tmp;
    }
}

基于二叉堆的优先队列,同样需要元素实现IComparable<T>接口。

public方法我基本上按照STL里的PQ来写的,也没有任何优化(我不会)。

缓冲区满时开二倍新空间,拷贝——虽然效率不见得高,但绝对简单实用的方法。

/// <summary>
/// 泛型优先队列,大者先出队
/// </summary>
/// <typeparam name="T">实现IComparable&lt;T&gt;的类型</typeparam>
public class PriorityQueue<T> where T : IComparable<T> {
    
private const int defaultCapacity = 0x10;//默认容量为16

    
public PriorityQueue() {
        buffer 
= new T[defaultCapacity];
        heapLength 
= 0;
    }

    
public bool Empty() {
        
return heapLength == 0;
    }

    
public T Top() {
        
if (heapLength == 0throw new OverflowException("优先队列为空时无法执行返回队首操作");
        
return buffer[0];
    }

    
public void Push(T obj) {
        
if (heapLength == buffer.Length) expand();
        buffer[heapLength] 
= obj;
        Heap
<T>.heapAdjustFromBottom(buffer, heapLength);
        heapLength
++;
    }

    
public void Pop() {
        
if (heapLength == 0throw new OverflowException("优先队列为空时无法执行出队操作");
        
--heapLength;
        swap(
0, heapLength);
        Heap
<T>.heapAdjustFromTop(buffer, 0, heapLength);
    }

    
private void expand() {
        Array.Resize
<T>(ref buffer, buffer.Length * 2);
    }

    
private void swap(int a, int b) {
        T tmp 
= buffer[a];
        buffer[a] 
= buffer[b];
        buffer[b] 
= tmp;
    }

    
private int heapLength;
    
private T[] buffer;

}

做了道以前的ACM题目,迷宫,优先队列BFS,原来用c++写的,46ms通过,现在这个93ms通过,出去输入输出慢,和JIT编译的时间,我觉得效率还不低——其实本来Heap可以优化的余地就不大,STL源代码大概看了下,好像也没什么优化。

虽然平衡二叉树也可以实现堆,但我总是觉得那样不爽——可能受STL影响。最重要的是——我不会写平衡二叉树,哈哈!

喜欢的、有需要的朋友就拿去用用吧,呵呵。