C# 是列表<>;。Sort()减少检查次数的最佳方法是什么?

C# 是列表<>;。Sort()减少检查次数的最佳方法是什么?,c#,arrays,sorting,C#,Arrays,Sorting,我正在制作一个meme排名应用程序,它可以将你最喜欢的meme从最好到最差进行排名,并删除排名最低的meme,从而从旧的和过时的meme中删除多余的内容,从而节省磁盘空间。我认为,由于List.Sort()函数速度非常快,它可以快速帮助用户对数百个Meme进行排序。事实并非如此,因为当我尝试使用下面的方法进行排序时,我得到了一些奇怪的结果 // Using Task.Run() temp. due to the easy access. Will thread this properly in

我正在制作一个meme排名应用程序,它可以将你最喜欢的meme从最好到最差进行排名,并删除排名最低的meme,从而从旧的和过时的meme中删除多余的内容,从而节省磁盘空间。我认为,由于
List.Sort()
函数速度非常快,它可以快速帮助用户对数百个Meme进行排序。事实并非如此,因为当我尝试使用下面的方法进行排序时,我得到了一些奇怪的结果

// Using Task.Run() temp. due to the easy access. Will thread this properly in the future. 
Task.Run(() =>
{
    Manager.Files.Sort(delegate (Photo x, Photo y) {
        // I have Invoke built into the ChangeImage method but having double duty doesn't slow it down.
        Invoke(new MethodInvoker(() =>
        {
            ChangeImage(pictureBox1, x.Filename);
            ChangeImage(pictureBox2, y.Filename);
        }));
        WaitForButtonPress.WaitOne(); // Pauses the thread until an image is chosen. 
        switch (LastButton)
        {
            case 1: // if x is better than y
                return 1;
            case 2: // if y is better than x
                return -1;
            case 3: // if y and x are equals
                return 0;
            default:
                break;
        }
        return 0; 
    });
});
我在这段代码中遇到的问题是,有时
pepe.jpg
isThisAPidgon.png
经常被多次比较,尤其是在比较中连续出现之后
pepe.jpg
vs.
1.jpg
pepe.jpg
vs.
2.png
pepe.jpeg
vs.
nth.jpg
pepe.jpg
vs.
isThisAPidgon.png
,然后再
isThisAPidgon.png
vs.
pepe.jpg
,但相反。在发现这种奇怪的行为后,我试着检查它们被呼叫了多少次

static void Main(string[] args)
{
    List<Number> numbers = new List<Number>();
    Random rand = new Random(); 
    for (int i = 0; i < 500; i++)
    {
        numbers.Add(new Number() { Num = rand.Next(0, 500) });
    }

    foreach(Number num in numbers)
    {
        Console.WriteLine(num.num);
    }

    numbers.Sort((Number x, Number y) =>
    {
        int numx = x.Num;
        int numy = y.Num;
        if (numx > numy)
            return 1;
        else if (numy > numx)
            return -1;
        else
            return 0;

        //return x.Num - y.Num;
    });

    int total = 0;
    foreach(Number num in numbers)
    {
        Console.WriteLine($"Num: {num.num} Times Checked: {num.timesChecked}");
        total += num.timesChecked;
    }
    Console.WriteLine($"Finished with {total} checks.");
}
当比较返回1、-1或0,并返回
x.num
y.num
的差值时,两者都会产生相同的结果:有些比另一些更频繁地出现。这里有一些例子

#checked with differences
Num: 168 Times Checked: 8
Num: 170 Times Checked: 17
Num: 170 Times Checked: 316 #316?
Num: 170 Times Checked: 14
Num: 171 Times Checked: 15

#checked with differences
Num: 237 Times Checked: 12
Num: 237 Times Checked: 9
Num: 240 Times Checked: 105 #More reasonable... 
Num: 241 Times Checked: 14
Num: 242 Times Checked: 15

#checked with differences
Num: 395 Times Checked: 10
Num: 397 Times Checked: 8
Num: 398 Times Checked: 502 #How could it fail to sort this number in more tries than the array is long?
Num: 398 Times Checked: 7
Num: 399 Times Checked: 8

#checked with <==>
Num: 306 Times Checked: 15
Num: 306 Times Checked: 17
Num: 307 Times Checked: 756 #This is ridiculous how does this happen?
Num: 307 Times Checked: 13
Num: 309 Times Checked: 15
#检查差异
检查次数:168次:8
检查次数:170次:17
检查次数:170次:316#316?
检查次数:170次:14
检查次数:171次:15
#核对差异
检查次数:237次:12
检查次数:237次:9
检查次数:240次:105#更合理。。。
检查次数:241次:14
检查次数:242次:15次
#核对差异
检查次数:395次:10次
检查次数:397次:8
Num:398次检查:502#它怎么会在超过数组长度的多次尝试中对该数字排序失败?
检查次数:398次:7次
检查次数:399次:8
#核对
检查次数:306次:15次
检查次数:306次:17次
Num:307次检查:756#这太荒谬了怎么会这样?
检查次数:307次:13
检查次数:309次:15次
差异似乎低于10000次总检查,但使用/1,-1,0方法检查时,似乎始终高于15000次总检查。是否有一种排序算法,其重点是减少需要对对象进行比较以进行排序的次数


编辑:我在比较示例中犯了一个错误。我使用了
x.Num
y.Num
两次,这使结果膨胀。为了解决这个问题,我将这两个属性存储为局部变量,并将总数从15000以上降至10000以下(约9000),而减去sill后的总数将保持在10000以下(约8000)。

大多数排序算法的复杂性为O(n log n),这意味着它们需要执行如此多的比较才能对数据进行排序。所以,不,您不能使用Sort来完成您正在做的事情

其次,一些内置排序方法会根据列表的大小切换行为,因此用户界面可能会因选择的算法而异。我以前从未见过有人使用排序来确定UI行为,新颖但不同寻常

如果您确实想使用排序算法,可以选择插入排序(使用二进制搜索将每个新项与现有列表进行比较,以找到它的位置)或快速排序(通过将一个元素与所有其他元素进行比较,将元素分为两组)

但是。。。我认为这两种方式都不会成为一种很好的用户体验,它们都会让人感觉重复。而且,考虑到这是一个主观问题,答案通常不是项目的纯线性排序。人们不一致,他们这样做时会创建周期A->B->C->A

因此,这里有一个UI体验的建议,它感觉不那么重复,可以处理主观异常,并且易于实现:

随机挑选一对图片,让用户将一张图片排在另一张图片的前面。如果用户愿意,让他们保持不一致。将他们创建的每一对A->B放在一个图表中。在图中找到任何尚未连接的节点,或者只有一个连接的节点,然后重点询问它们与您已经评分的节点的排名

那样的话,如果他们把A->B->C排到了C->D,那么算法就不会一直问A和B与D相比如何了

最后应用一种叫做拓扑排序的技术,忽略你发现的任何循环。一个近似的拓扑排序

有一个图形库(我写的)包含了这个功能。有关调用
.TopologicalSortApprox()
的示例,请参见


一旦所有项目都在图形中,您就可以继续使用比较,尝试将图形展平到接近直线的位置。但在任何时候,如果用户感到厌烦并想停止(没有人想进行n个log n比较!),您至少可以使用一个近似的排名。

大多数排序算法的复杂性为O(n个log n),这意味着它们需要执行那么多比较才能对数据进行排序。所以,不,您不能使用Sort来完成您正在做的事情

其次,一些内置排序方法会根据列表的大小切换行为,因此用户界面可能会因选择的算法而异。我以前从未见过有人使用排序来确定UI行为,新颖但不同寻常

如果您确实想使用排序算法,可以选择插入排序(使用二进制搜索将每个新项与现有列表进行比较,以找到它的位置)或快速排序(通过将一个元素与所有其他元素进行比较,将元素分为两组)

但是。。。我认为这两种方式都不会成为一种很好的用户体验,它们都会让人感觉重复。而且,考虑到这是一个主观问题,答案通常不是项目的纯线性排序。人们并不始终如一,他们会信口开河
#checked with differences
Num: 168 Times Checked: 8
Num: 170 Times Checked: 17
Num: 170 Times Checked: 316 #316?
Num: 170 Times Checked: 14
Num: 171 Times Checked: 15

#checked with differences
Num: 237 Times Checked: 12
Num: 237 Times Checked: 9
Num: 240 Times Checked: 105 #More reasonable... 
Num: 241 Times Checked: 14
Num: 242 Times Checked: 15

#checked with differences
Num: 395 Times Checked: 10
Num: 397 Times Checked: 8
Num: 398 Times Checked: 502 #How could it fail to sort this number in more tries than the array is long?
Num: 398 Times Checked: 7
Num: 399 Times Checked: 8

#checked with <==>
Num: 306 Times Checked: 15
Num: 306 Times Checked: 17
Num: 307 Times Checked: 756 #This is ridiculous how does this happen?
Num: 307 Times Checked: 13
Num: 309 Times Checked: 15