優先順位つきキュー

ソース長いので


優先順位つきキューと二分ヒープのセット。

Verifyはまだしてない。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace TopCoderLib
{
    public static partial class Algorithm
    {
        /// <summary>
        /// 二分ヒープを表します
        /// </summary>
        /// <typeparam name="T">ヒープに格納されるデータの型</typeparam>
        public class Heap<T>
            where T : IComparable<T>
        {
            private T[] array;
            private static T[] empty = null;
            private int size;
            private Compare cmp;

            /// <summary>
            /// 整列のために要素を比較する際に用いるデリゲートです
            /// </summary>
            /// <param name="a">比較する値</param>
            /// <param name="b">比較する値</param>
            /// <returns>a > bなら正数、a == bなら0、a <![CDATA[<]]> bなら負数を返します</returns>
            public delegate int Compare(T a, T b);

            /// <summary>
            /// このヒープに格納されている要素の数を表します
            /// </summary>
            public int Count { get { return size; } }

            /// <summary>
            /// このヒープに格納されている値をインデックスを使って取得します。
            /// ルート要素を取得するには0を指定してください。他の場合はIndexOfメソッドと併せて使用してください。
            /// </summary>
            /// <param name="index">取得したい値のインデックス</param>
            public T this[int index] { get { return array[index]; } }

            /// <summary>
            /// 新しいヒープを生成します。
            /// </summary>
            public Heap()
            {
                array = empty;
                size = 0;
                cmp = delegate(T a, T b) { return a.CompareTo(b); };
            }

            /// <summary>
            /// 与えられた数のぶんだけ要素を格納できる新しいヒープを生成します。
            /// 必要があればヒープはInsertメソッドによって自動的に拡張されます。
            /// </summary>
            /// <param name="capacity">確保する領域の大きさ</param>
            public Heap(int capacity)
            {
                array = new T[capacity];
                size = 0;
                cmp = delegate(T a, T b) { return a.CompareTo(b); };
            }

            /// <summary>
            /// データの比較方法を指定した新しいヒープを生成します。
            /// </summary>
            /// <param name="compare">二つのデータを比較するデリゲート</param>
            public Heap(Compare compare)
            {
                array = empty;
                size = 0;
                cmp = compare;
            }

            /// <summary>
            /// データの比較方法を指定して、与えられた数の分だけ要素を格納できる新しいヒープを生成します。
            /// </summary>
            /// <param name="compare">二つのデータを比較するデリゲート</param>
            public Heap(int capacity, Compare compare)
            {
                array = new T[capacity];
                size = 0;
                cmp = compare;
            }

            /// <summary>
            /// ヒープに要素を追加します。必要があればヒープは自動的に拡張されます。
            /// </summary>
            /// <param name="data">追加するデータ</param>
            public void Insert(T data)
            {
                if (array == empty || array.Length == size)
                {
                    T[] dest = new T[(array == empty) ? 4 : (2 * array.Length)];
                    if(array != empty)
                        Array.Copy(array, dest, array.Length);
                    array = dest;
                }
                int n = ++size;
                array[n - 1] = data;
                while (n != 1 && cmp(array[n / 2 - 1], array[n - 1]) > 0)
                {
                    int i = n / 2 - 1, j = n - 1;
                    T tmp = array[i];
                    array[i] = array[j];
                    array[j] = tmp;
                    n /= 2;
                }
            }

            /// <summary>
            /// ルート要素を削除します
            /// </summary>
            /// <returns>削除される前のルート要素を返します</returns>
            public T RemoveRoot()
            {
                T res = array[0];
                array[0] = array[--size];

                int i = 0;
                while (2 * i < size)
                {
                    int j = 2 * i + 1;
                    if (j < size && cmp(array[j], array[j + 1]) > 0)
                        ++j;
                    if (cmp(array[i], array[j]) > 0)
                    {
                        T tmp = array[i];
                        array[i] = array[j];
                        array[j] = tmp;
                    }
                    else { break; }
                    i = j;
                }

                return res;
            }

            /// <summary>
            /// 指定されたデータがこのヒープのどこにあるか探索します
            /// </summary>
            /// <param name="data">探索するデータ</param>
            /// <returns>データのあるインデックス</returns>
            public int IndexOf(T data)
            {
                for (int i = 0; i < size; ++i)
                    if (cmp(array[i], data) == 0)
                        return i;
                return -1;
            }
        }

        /// <summary>
        /// 優先順位つきキューを表します
        /// </summary>
        /// <typeparam name="T">優先順位つきキューに格納するデータの型</typeparam>
        public class PriorityQueue<T>
            where T : IComparable<T>
        {
            private Heap<T> heap;

            /// <summary>
            /// このキューに格納されている要素の数を表します
            /// </summary>
            public int Count { get { return heap.Count; } }

            /// <summary>
            /// 新しい優先順位つきキューを生成します
            /// </summary>
            public PriorityQueue()
            {
                heap = new Heap<T>();
            }

            /// <summary>
            /// 既定の初期値を格納する新しい優先順位つきキューを生成します
            /// </summary>
            /// <param name="data">はじめに保持するデータ</param>
            public PriorityQueue(IEnumerable<T> data)
            {
                heap = new Heap<T>();
                foreach (T v in data)
                {
                    heap.Insert(v);
                }
            }

            /// <summary>
            /// 比較の方法を指定して、新しい優先順位つきキューを生成します
            /// </summary>
            /// <param name="cmp">比較に用いるデリゲート</param>
            public PriorityQueue(Heap<T>.Compare cmp)
            {
                heap = new Heap<T>(cmp);
            }

            /// <summary>
            /// 比較の方法を指定して、既定の初期値を格納する新しい優先順位つきキューを生成します
            /// </summary>
            /// <param name="data">はじめに保持するデータ</param>
            /// <param name="cmp">比較に用いるデリゲート</param>
            public PriorityQueue(IEnumerable<T> data, Heap<T>.Compare cmp)
            {
                heap = new Heap<T>(cmp);
                foreach (T v in data)
                {
                    heap.Insert(v);
                }
            }

            /// <summary>
            /// この優先順位つきキューに要素を追加します
            /// </summary>
            /// <param name="data">追加するデータ</param>
            public void Enqueue(T data)
            {
                heap.Insert(data);
            }

            /// <summary>
            /// この優先順位つきキューから要素を取り出します
            /// </summary>
            /// <returns>取り出されたデータ</returns>
            public T Dequeue()
            {
                return heap.RemoveRoot();
            }
        }
    }
}