SortedSet.Remove()不适用于自定义比较器类

时间:2019-02-07 21:38:50

标签: c# data-structures

我正在尝试解决leetcode问题,在这里我想获得前k个频繁的数字。我正在尝试使用SortedSet解决O(log n)时间复杂性。

我的代码适用于所有输入 一项输入。

public class FreqNode
{
    public int number;
    public int freq;

    public FreqNode(int n, int f)
    {
        number = n;
        freq = f;
    }
}

class Program
{

    static void Main(string[] args)
    {
        int[] arr = new int[] { 3, 2, 3, 1, 2, 4, 5, 5, 6, 7, 7, 8, 2, 3, 1, 1, 1, 10, 11, 5, 6, 2, 4, 7, 8, 5, 6};

        TopKFrequent(arr, 10);
        Console.Read();

    }        

    static void TopKFrequent(int[] nums, int k)
    {
        SortedSet<FreqNode> sl = new SortedSet<FreqNode>(new MyComparer());
        Dictionary<int, FreqNode> ht = new Dictionary<int, FreqNode>();

        foreach (int i in nums)
        {
            if (ht.ContainsKey(i))
            {
                sl.Remove(ht[i]);
                ht[i].freq += 1;
            }
            else
            {
                ht[i] = new FreqNode(i, 1);
            }
            sl.Add(ht[i]);
        }


        for (int i = 0; i < k; i++)
        {
            FreqNode f = sl.ElementAt(i);
            Console.WriteLine(f.number);
        }
    }
}

public class MyComparer : IComparer<FreqNode>
{
    public int Compare(FreqNode fn1, FreqNode fn2)
    {
        //Remove entry with same number
        //Retain entries with same frequencies.
        if (fn1.number == fn2.number)
        {
            return 0;
        }
        else
        {
            int res = fn2.freq.CompareTo(fn1.freq);
            if (res == 0)
            {
                return 1;
            }
            else
            {
                return res;
            }
        }
    }
}

它将输出打印为-1,2,5,3,7, 6,6 ,4,8,10

代替-1,2,5,3,6,7,4,8,10,11

在调试过程中,我注意到比较器代码无法与现有的数字6进行比较。经过进一步调查,我发现SortedSet是使用Red-Black树实现的,但是我无法在代码中解决此错误。 / p>

1 个答案:

答案 0 :(得分:0)

这个问题对我来说很有趣,因为我认为这可能是SortedSet错误,并让我逐步浏览了SortedSet源代码。 las,不是SortedSet错误...对不起,但是您的IComparer有点怪。

您的IComparer实现通过首先更改排序比较的条件,然后反转比较对象,然后更改返回值,确实使比较变得奇怪。

首先您的比较者在说,

  

如果“数量”属性相等,则节点相等(很好)

if (fn1.number == fn2.number)
{
    return 0;
}

那是在说

  

在freq属性的倒数上排序(用fn1切换fn2可能不是一个好主意,并且排序标准已更改为'freq'属性(可能还可以))

int res = fn2.freq.CompareTo(fn1.freq);

然后将相等的频率更改为不相等

  

如果“频率”比较的结果相等,就假装它不相等(可能不是一个好主意)

if (res == 0)
{
    return 1;
}

糟糕的SortedSet的根必须旋转!! (哈哈哈!我开了一个数据结构的笑话!让它“根”?“旋转”?)

最后,Remove算法将'6'作为正确的子代查找,因为您的IComparer告诉它应该在该位置,而'6'实际上是左子代,因此Remove算法将其遗漏。

>

顺便说一句,请记住,SortedSet中的2个“ 6”节点和字典中的“ 6”节点实际上都是相同的FreqNode引用,因此如果您要同时更改所有这些引用,需要。

您可以查看(并下载).NET源here 然后按照说明here

将Visual Studio设置为调试源

最后,如果您坚持要以这种方式解决top-k问题,请尝试使用此比较器:

        public class MyComparer : IComparer<FreqNode>
        {
            public int Compare(FreqNode fn1, FreqNode fn2)
            {
                return fn1.number == fn2.number ? fn1.freq.CompareTo(fn2.freq) : fn1.number.CompareTo(fn2.number);
            }
        }

干杯,感谢您的调试!