【问题标题】:ArrayList.Sort should be a stable sort with an IComparer but is not?ArrayList.Sort 应该是带有 IComparer 的稳定排序,但不是吗?
【发布时间】:2011-06-30 04:09:54
【问题描述】:

stable sort 是一种保持具有相同值的元素的相对顺序的排序。

ArrayList.Sort 上的文档说,当提供 IComparer 时,排序是稳定的:

如果 comparer 设置为 null,此方法执行比较排序(也称为不稳定排序);也就是说,如果两个元素相等,则可能不会保留它们的顺序。相反,稳定排序保留了相等元素的顺序。要执行稳定排序,您必须实现自定义 IComparer 接口。

除非我遗漏了什么,否则下面的测试用例表明ArrayList.Sort 没有使用稳定的排序:

internal class DisplayOrdered {
    public int ID { get; set; }
    public int DisplayOrder { get; set; }
    public override string ToString() {
        return string.Format("ID: {0}, DisplayOrder: {1}", ID, DisplayOrder);
    }
}

internal class DisplayOrderedComparer : IComparer {
    public int Compare(object x, object y) {
        return ((DisplayOrdered)x).DisplayOrder - ((DisplayOrdered)y).DisplayOrder;
    }
}

[TestFixture]
public class ArrayListStableSortTest {

    [Test]
    public void TestWeblinkCallArrayListIsSortedUsingStableSort() {
        var call1 = new DisplayOrdered {ID = 1, DisplayOrder = 0};
        var call2 = new DisplayOrdered {ID = 2, DisplayOrder = 0};
        var call3 = new DisplayOrdered {ID = 3, DisplayOrder = 2};
        var list = new ArrayList {call1, call2, call3};

        list.Sort(new DisplayOrderedComparer());

        // expected order (by ID): 1, 2, 3 (because the DisplayOrder
        // is equal for ID's 1 and 2, their ordering should be
        // maintained for a stable sort.)
        Assert.AreEqual(call1, list[0]); // Actual: ID=2 ** FAILS 
        Assert.AreEqual(call2, list[1]); // Actual: ID=1
        Assert.AreEqual(call3, list[2]); // Actual: ID=3
    }
}

我错过了什么吗?如果不是,这是文档错误还是库错误?

显然在 Linq 中使用 OrderBy 可以提供稳定的排序。

【问题讨论】:

  • 评论的意图是否可能是“您需要实现自己的 IComparer 以强制排序稳定”而不是“如果您实现自己的 IComparer,排序将是稳定的隐式”?
  • 这不是实现比较的好方法。 blogs.msdn.com/b/ericlippert/archive/2011/01/27/…
  • 你确定你没有落入这里描述的谬论吗:blogs.msdn.com/b/ericlippert/archive/2011/01/27/… 编辑:呸,在试图找到链接时被打败了。 :D
  • @Mark - Eric 的观点提出了一些我不知道的好观点。实际上,我将这篇文章的比较器从使用 System.Integer32.CompareTo() 更改了,因为我认为它可能更容易理解。我想我应该离开它。
  • @Mark 哇,我希望我能为那个链接 +1 你。我一直认为减法是一种方便的“计算机”方式来表示比较。 glow.levelUp(); 谢谢!

标签: c# sorting arraylist stability


【解决方案1】:

文档似乎在说的是,使用ArrayList.Sort 获得稳定排序的唯一方法是使用IComparer,它以某种方式“知道”正在比较的项目的索引(可以想象通过使其在集合上运行初始传递来完成此操作)并将该信息用作其他相同元素的决胜局。

虽然我同意文档的措辞有很多不足之处,但任何考虑要比较的项目索引的旧比较器确实没有意义神奇地将一个固有不稳定的排序算法(Arraylist.Sort 就是)变成一个稳定的算法。

【讨论】:

  • 确实如此。 ArrayList.Sort 的当前实现只是调用Array.Sort,而不管使用了IComparerArray.Sort 被更明确地记录为使用不稳定的快速排序。 msdn.microsoft.com/en-us/library/afwbytk2.aspx
  • 虽然肯定不是我从文档中假设的那样,但这似乎是一个合理的解释。我的假设是,每当IComparer 以稳定的排序方式传递时,都会被使用。但是,正如 LukeH 指出并查看源代码所揭示的那样,情况并非如此。
猜你喜欢
  • 1970-01-01
  • 2012-05-16
  • 2017-05-13
  • 1970-01-01
  • 2016-05-23
  • 2021-05-06
  • 1970-01-01
  • 2017-06-02
  • 2017-12-16
相关资源
最近更新 更多