为什么SortedSet不能用作优先级队列或Min-Heap?

时间:2017-08-09 20:08:00

标签: c#

我试图使用有序集解决运行中位数问题(在hackerrank上)。只有它的元素才能正确排序。

在此处查看此行动:http://rextester.com/NGBN25779

public class RunningMedian{

    List<int> list = new List<int>();
    SortedSet<int> sorted = new SortedSet<int>();

    public void Add(int num){
        list.Add(num);
        sorted.Add(num);
    }
    public double MedianNotWorking(){
        return GetMedian(sorted.ToArray());
    }
    public double MedianWorking(){
        int[] arr = list.ToArray();
        Array.Sort(arr);
        return GetMedian(arr);
    }
    public double GetMedian(int[] arr){
        int idx = list.Count / 2;
        if(arr.Length % 2 == 0){
            return (double)((double)(arr[idx] + arr[idx-1]) / 2);
        }else{
            return arr[idx];
        }
    }

}

static void Main(String[] args) {
    int n = Convert.ToInt32(Console.ReadLine());
    int[] a = new int[n];

    RunningMedian heap = new RunningMedian();
    for(int i = 0; i < n; i++){
        a[i] = Convert.ToInt32(Console.ReadLine());
        heap.Add(a[i]);

        //double median = heap.GetMedian();
        double median = heap.MedianNotWorking();
        Console.WriteLine(median.ToString("F1"));
    }
}

在大多数情况下,有序集合确实有效。然而,在较大的输入尺寸下,它开始给出错误的答案。它可能不是问题的最佳解决方案,但我很好奇它为什么会失败。 C#没有最小堆/优先级队列,为什么不能将排序集用作替代?

*编辑包含来自hackerrank的完整代码。

这是一个输入文件。 输入 http://textuploader.com/dovni

预期 http://textuploader.com/dovnb

输出 http://textuploader.com/dovwj

冲突出现在最后

预期 (跳过1-364) 54240.0 54576.5 54913.0 54576.5 54240.0

结果 (跳过1-364) 54240.0 54576.5 54913.0 54963.0 54576.5

2 个答案:

答案 0 :(得分:2)

SortedSet个集合根据定义仅包含唯一值。但是,您的输入文件包含数字21794两次,这意味着第二个21794条目未添加到您的SortedSet。因此,您的有序集合将包含的值少于列表,您的整个算法将不再起作用。

答案 1 :(得分:0)

通常,这可以通过为SortedSet比较定义新的IComparator行为来实现。对于最小优先级队列,将如下所示:

public class PriorityQueue<K,V> where K : IComparable
                                where V : IComparable
{
    private SortedSet<Node<K,V>> _set;
    private readonly int _amount;

    public PriorityQueue(int amount)
    {
        _set = new SortedSet<Node<K,V>>(new PriorityComparer<K,V>());
        _amount = amount;
    }

    public void Add(Node<K,V> value)
    {
        if (_amount > _set.Count)
            _set.Add(value);
        else
        {
            if (_set.Max.Val.CompareTo(value.Val) == 1)
            {
                _set.Remove(_set.Max);
                _set.Add(value);
            }
        }
    }

    public Node<K,V> ExtractMax()
    {
        var max = _set.Max;
        _set.Remove(max);

        return max;
    }

    public Node<K,V> ExtractMin()
    {
        var min = _set.Min;
        _set.Remove(min);

        return min;
    }

    public bool IsEmpty => _set.Count == 0;
}

public struct Node<K,V> where K : IComparable
                        where V : IComparable
{
    public K Key;
    public V Val;

    public Node(K key, V val)
    {
        Val = val;
        Key = key;
    }
}

public class PriorityComparer<K,V> : IComparer<Node<K,V>> where K: IComparable
                                                          where V: IComparable
{
    public int Compare(Node<K,V> i, Node<K,V> y)
    {
        var compareresult = i.Val.CompareTo(y.Val);

        if (compareresult == 0)
            return i.Key.CompareTo(y.Key);

        return compareresult;
    }
}