目前我正在快速排序。我遵循了快速排序规则;但我发现了一件奇怪的事。
这个过程就像这张照片。
请帮我找到我的错误:
以下是代码:
static void QuickSortFromMiddle(int[] arr, int low, int high)
{
if (low < high)
{
int middleValue = arr[(low+high)/2];
int h = high+1;
int l = low-1;
while (l < h)
{
while (arr[--h] > middleValue && l<h);
while (arr[++l] < middleValue && l<h) ;
if (l >= h)
break;
int temp = arr[l];
arr[l] = arr[h];
arr[h] = temp;
}
QuickSortFromMiddle(arr,low,l-1);
QuickSortFromMiddle(arr, h+1, high);
}
}
/// <summary>
///
/// </summary>
static void QuickSort(int[] arr)
{
QuickSortFromMiddle(arr, 0, arr.Length - 1);
}
/// <summary>
///
/// </summary>
static void TestQuickSort()
{
var arr = new[] { 1, 5, 3, 4, 57, 5, 5, 53 };
QuickSort(arr);
foreach (int i in arr)
{
Console.WriteLine(i);
}
}
这是结果(我很困惑......)
正如Dukeling所说&#34;枢轴通常被移到任何一端&#34;首先,我应该将数据枢轴放在数组的末尾
其次,我应该把枢轴放在arr的正确位置(大于左边,小于右边)
这是正确的过程:
答案 0 :(得分:1)
整体算法如下:
只要条件满足,有几种分区方案,其中任何一种都可以工作。您的分区方案是我以前从未见过的。特别是,我从未见过快速排序分区方案,它将集中定位的值作为支点。 有关一些标准分区方案(例如Lomuto),请参阅the wikipedia page。
总的来说,您的分区方案存在以下限制:
arr[l]
和arr[h]
之前,您甚至无法检查是否需要交换它们。您只是假设在l
和h
(两个内部while循环)的初始移动之后,需要交换所有其他数字。您需要使分区方案更通用,或者尝试理解并使用其中一个标准方案。
答案 1 :(得分:1)
正如Parakram写的那样,枢纽元素是你的主要问题。 该算法不会将数组拆分到pivototelement的中间或位置,它会将数组拆分为两个,其中pivot- 值。它将被分割的位置由l和h搜索。当他们见面时,你就有了分裂的位置。
我在您的代码中添加了一些注释。我觉得这个有用......
static void QuickSortFromMiddle(int[] arr, int low, int high)
{
Console.WriteLine("Low: {0}, High: {1}, Arr: {2}", low, high, string.Join("|", arr));
if (low < high)
{
int pivot = arr[high]; // Select you pivot element. After the run all smaller numbers will be left of it, all bigger ones on the high-side.
int h = high;
int l = low;
// breaks at specific condition within the loop
while(true)
{
// Search for the first element which is smaller, beginning on the high-side
while (arr[h] >= pivot && l < h)
{
h--;
}
// Search for the first element which is bigger, beginning on the low-side
while (arr[l] < pivot && l < h)
{
l++;
}
// we now have pivot (still at position "high")
// we got an element which is bigger that pivot on "l"
// we got an element which is smaller than pivot on "h"
// conclusion: we need to change their positions
Console.WriteLine("h: " + h + ", l: " + l + ", Arr: " + string.Join("|", arr));
// if l&h are at the same position, we're done and have to check if the pivot element has to be moved to this position
if (l >= h)
break;
// we change elements on position l and h, because we know that arr[l] is bigger that our pivot and arr[h] is smaller.
int temp = arr[l];
arr[l] = arr[h];
arr[h] = temp;
}
// l equals h. This is now the position for pivot, because all elements on the lower side are smaller and all elements on the right side are bigger
Console.WriteLine(">h: " + h + ", l: " + l + ", Arr: " + string.Join("|", arr));
if (arr[l] > pivot)
{
arr[high] = arr[l];
arr[l] = pivot;
}
// We start two new runs. One for the lower values: from Low to l and from l+1 to high.
// Why? As we know l is our pivot value which splits the elements into two groups. smaller ones on the lower side, bigger ones on the higher side.
// We now can focus on those two groups separately.
QuickSortFromMiddle(arr, low, l);
QuickSortFromMiddle(arr, l + 1, high);
}
}