c# - 堆栈溢出与快速排序实现

标签 c# algorithm stack-overflow quicksort

<分区>

我正在尝试实现快速排序算法(在 C# 中),这是我的代码:

public static void sort(ref int[] A)
{
    if (A.Length==0 || A.Length==1) 
    { 
        return; 
    }
    quickSort(ref A,0,A.Length-1);
}

private static void quickSort(ref int[] A, int left, int right)
{
    if (left >= right || left < 0 || right < 0) 
        return;

    int pivot = A[left];

    int i = left - 1;
    int j = right + 1;

    while (true) 
    {
        do 
        { 
            i++; 
        } 
        while (A[i] < pivot);

        do 
        { 
            j--; 
        } 
        while (A[j] > pivot);

        if (i >= j) 
            break;

        int temp = A[i];
        A[i] = A[j];
        A[j] = temp;
    }

    quickSort(ref A,left,j);
    quickSort(ref A, j + 1, right);
}

这个算法工作正常,但是有些地方似乎不合逻辑,我选择了pivot等于A[left]然后在 while(true)循环我写了do{i++}while(A[i]<pivot) , 我现在注意到第一次它会增加 i所以A[i]将等于 A[left]这是枢轴值,所以这应该意味着这个 do while循环将在 i 的第一个增量后停止,因此当我尝试添加 = 时运算符到 while这样它就不会在第一次递增后停止:while(A[i]<=)我得到了一个堆栈溢出异常(当我在第二个 do while : while(A[j]>=pivot) 中添加相等运算符时也得到了堆栈溢出异常),我不明白为什么会这样,有人能解释一下吗?

最佳答案

这是霍尔分区方案。 do while 循环需要使用 < 或 >,而不是 <= 或 >=,因为它们依赖于找到枢轴或等于枢轴的元素来停止循环并防止循环超出范围 [lo,你好]。通常中间元素作为枢轴,比如

    int pivot = A[(left+right)/2];   // or A[left + (right-left)/2]

在当前代码中,唯一不能用于主元的元素是 A[right],因为这会导致堆栈溢出(快速排序调用最终会卡在 high = low + 1)。

因此使用 pivot = A[left],第一个 do while 以 i == left 停止,第二个 do while 以 j <= right 停止。如果 i < j,则发生交换,将枢轴交换到 A[j] 并将元素 <= 枢轴交换到 A[i == left]。每次交换都会阻止下一对 do while 越过边界 [low, high],因此在这对 do while 之后只需要检查 i >= j 以检查分区步骤是否完成。

为枢轴选择中间元素有助于某些数据模式,例如已排序的数据或反向排序的数据。尽管如此,如果左侧元素 == pivot,第一个 do while 将在第一个循环中停止。

请注意,Hoare 分区方案仅将分区拆分为元素 <= 枢轴和元素 >= 枢轴。主元或等于主元的任何元素可以在分区步骤后的任何位置结束。这不是问题,因为最终枢轴或等于枢轴的元素最终将位于正确的位置(这可能不会发生,直到达到低 == 高的递归级别)。

关于c# - 堆栈溢出与快速排序实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58547595/

相关文章:

c# - 在 C# 中使用 C++ 类

c# - C#中的数字总和

java - Eratosthenes算法的并行筛寻找素数

javascript - 有效搜索较大字符串中的多个子字符串之一

android - onLocationChanged 多次触发并导致堆栈溢出

java错误堆栈溢出

c# - ASP.NET 身份验证问题

c# - 即使签名匹配,也无法将一种类型的委托(delegate)分配给另一种

java 堆栈溢出错误

c# - Entity Framework 5.0 代码中第一个一对一和一对多的关系