在实现这个通用的合并排序(Merge Sort)时,我把它当做一种代码卡塔。在此期间,我发现了 IEnumerable 和 List 之间的一个区别,希望能得到帮助来解决这个问题。
下面是 MergeSort 的代码:
如果我从
示例
那么尝试这个。
这里到底发生了什么?
下面是 MergeSort 的代码:
public class MergeSort<T>
{
public IEnumerable<T> Sort(IEnumerable<T> arr)
{
if (arr.Count() <= 1) return arr;
int middle = arr.Count() / 2;
var left = arr.Take(middle).ToList();
var right = arr.Skip(middle).ToList();
return Merge(Sort(left), Sort(right));
}
private static IEnumerable<T> Merge(IEnumerable<T> left, IEnumerable<T> right)
{
var arrSorted = new List<T>();
while (left.Count() > 0 && right.Count() > 0)
{
if (Comparer<T>.Default.Compare(left.First(), right.First()) < 0)
{
arrSorted.Add(left.First());
left=left.Skip(1);
}
else
{
arrSorted.Add(right.First());
right=right.Skip(1);
}
}
return arrSorted.Concat(left).Concat(right);
}
}
如果我从
left
和 right
变量中删除 .ToList()
,它将无法正确排序。你明白为什么吗?示例
var ints = new List<int> { 5, 8, 2, 1, 7 };
var mergeSortInt = new MergeSort<int>();
var sortedInts = mergeSortInt.Sort(ints);
使用.ToList()
[0]: 1 [1]: 2 [2]: 5 [3]: 7 [4]: 8
未使用.ToList()
[0]: 1 [1]: 2 [2]: 5 [3]: 7 [4]: 2
编辑
这是我的愚蠢测试。
我像这样进行测试:
var sortedInts = mergeSortInt.Sort(ints);
ints.Sort();
if (Enumerable.SequenceEqual(ints, sortedInts)) Console.WriteLine("ints sorts ok");
只需将第一行更改为
var sortedInts = mergeSortInt.Sort(ints).ToList();
去除这个问题(以及懒惰的评估)。
编辑 2010-12-29
我本来想弄清楚懒惰的评估是如何在这里出错的,但我还是不明白。
像这样从Sort方法中删除 .ToList()
:
var left = arr.Take(middle);
var right = arr.Skip(middle);
那么尝试这个。
var ints = new List<int> { 5, 8, 2 };
var mergeSortInt = new MergeSort<int>();
var sortedInts = mergeSortInt.Sort(ints);
ints.Sort();
if (Enumerable.SequenceEqual(ints, sortedInts)) Console.WriteLine("ints sorts ok");
当调试时,您可以看到在ints.Sort()
之前sortedInts.ToList()
返回的内容
[0]: 2
[1]: 5
[2]: 8
但是在ints.Sort()
之后,它返回了:
[0]: 2
[1]: 5
[2]: 5
这里到底发生了什么?
ToList()
后,必须承认它在我的电脑上运行良好。 - nanleft=left.Skip(1)
,可能会有延迟执行的问题,但我不知道具体情况。 - Kobi