我的通用QuickSort算法有两个问题我无法确定原因。
列表未正确排序的情况相当罕见,因此列表必须相当大。 下面的粘贴显示了已安装软件的172个元素列表的前13个元素,第一列显示第一个排序后的输出,第二个列显示第二个排序。
Adobe AIR 7-Zip 4.65 (x64 edition)
7-Zip 4.65 (x64 edition) Adobe AIR
Adobe Community Help Adobe Community Help
Adobe Encore CS4 Codecs Adobe Encore CS4 Codecs
Adobe Media Encoder CS4 Exporter Adobe Media Encoder CS4 Exporter
Adobe Media Encoder CS4 Importer Adobe Media Encoder CS4 Importer
Adobe Media Player Adobe Media Player
Adobe Reader X (10.1.0) Adobe Reader X (10.1.0)
Adobe Setup Adobe Setup
Adobe Setup Adobe Setup
Apple Application Support Adobe Setup
Adobe Setup Apple Application Support
Apple Mobile Device Support Apple Mobile Device Support
... ...
正如您所看到的,第一次排序时,会出现一些不正确的行为,这可以通过另一种排序来解决。
如果我对我的大型Windows事件日志列表进行排序,则会发生堆栈溢出的第二个问题。如果我在4周内排序52,000个日期,那似乎很高兴;但是,如果我排序52,000个具有多次重复的ID号,我的堆栈大小在崩溃系统之前就会变成998个项目。如果我按照主要是'gupdate'的列排序30,000个长列表,也会发生这种情况。
现在,据我所知,堆栈计数应该是log2(n),因为添加到堆栈的数量等于完成的切割量。
我让我的支点随机来帮助这个效果,但它没有太大的区别。
Log2(60000)= 16.这对于堆栈溢出来说还不够!
这是关注的代码:
private static void QuickSortFunction<T>(T[] array, int start, int end, Comparer<T> comparer)
{
if (end - start >= 1)
{
int leftPtr, rightPtr, pivot;
Random random = new Random();
pivot = random.Next(start, end);
Swap(array, pivot, start);
pivot = start;
leftPtr = start + 1;
rightPtr = end;
while (leftPtr < rightPtr)
{
while ((comparer.Compare(array[leftPtr], array[pivot])) <= 0 && (leftPtr < rightPtr))
{
leftPtr++;
}
while ((comparer.Compare(array[rightPtr], array[pivot])) >= 0 && (leftPtr <= rightPtr))
{
rightPtr--;
}
if (leftPtr < rightPtr)
{
Swap(array, leftPtr, rightPtr);
}
}
Swap(array, pivot, rightPtr);
pivot = rightPtr;
QuickSortFunction(array, start, pivot - 1, comparer);
QuickSortFunction(array, pivot + 1, end, comparer);
}
}
private static void Swap<T>(T[] array, int pointer1, int pointer2)
{
T temp = array[pointer1];
array[pointer1] = array[pointer2];
array[pointer2] = temp;
}
对于任何有兴趣的人,这是无序故障的修复。基本上,当它出现故障时,它无法识别2元素阵列。例如{E,B},它不会改变,因为它不会看自己的支点。
if (end - start >= 1)
{
int leftPtr, rightPtr, pivot;
Random random = new Random();
pivot = random.Next(start, end);
Swap(array, pivot, start);
pivot = start;
leftPtr = start;
rightPtr = end;
while (leftPtr < rightPtr)
{
while ((comparer.Compare(array[leftPtr], array[pivot])) < 0 && (leftPtr < rightPtr))
{
leftPtr++;
}
while ((comparer.Compare(array[rightPtr], array[pivot])) >= 0 && (leftPtr < rightPtr))
{
rightPtr--;
}
if (leftPtr < rightPtr)
{
Swap(array, leftPtr, rightPtr);
}
}
Swap(array, pivot, rightPtr);
pivot = rightPtr;
QuickSortFunction(array, start, pivot - 1, comparer);
QuickSortFunction(array, pivot + 1, end, comparer);
}
一旦我为堆栈溢出编写解决方案,就会更新。
答案 0 :(得分:1)
现在,据我所知,堆栈计数应该是log2(n),因为添加到堆栈的数量等于完成的切割量。
只有将输入分成类似 1 大小的两半时才会出现这种情况。例如,如果您对所有项目相等的列表进行排序,则会得到一个非常不均匀的分割,其中一侧没有元素,另一侧除了枢轴之外的所有内容。在这种情况下,您将获得 O(n)堆栈大小,因为每个级别仅将输入大小减小1.
避免这种情况的一种方法是使用三向分区,将所有元素放在中间等于枢轴。
1 如果分割总是好于某个常数比例,那你就没事了。
答案 1 :(得分:1)
让我们先看一下乱序问题。大循环一直持续到leftPtr >= rightPtr
。由于你的第二个循环测试leftPtr <= rightPtr
,有可能在最后leftPtr > rightPtr
,在这种情况下你交换(在大循环之后)枢轴和一个被认为“OK”的元素( rightPtr
指向leftPtr
)
不确定堆栈溢出问题,但是Hammar的建议似乎是合理的,特别是你说这个问题出现在很多相同元素的大型列表上
答案 2 :(得分:0)
观察您创建的无限循环...函数必须终止其内在值才能在使用中实现。