以下quicksort方法如何工作?

时间:2017-06-16 10:31:33

标签: c# algorithm linq quicksort partitioning

我为教育目的编写了自己的Quicksort方法。为了改进它,我看了一下.NET源代码,看看如何实现LINQ OrderBy()方法。

我找到了以下Quicksort method

void QuickSort(int[] map, int left, int right) {
    do {
        int i = left;
        int j = right;
        int x = map[i + ((j - i) >> 1)];
        do {
            while (i < map.Length && CompareKeys(x, map[i]) > 0) i++;
            while (j >= 0 && CompareKeys(x, map[j]) < 0) j--;
            if (i > j) break;
            if (i < j) {
                int temp = map[i];
                map[i] = map[j];
                map[j] = temp;
            }
            i++;
            j--;
        } while (i <= j);
        if (j - left <= right - i) {
            if (left < j) QuickSort(map, left, j);
            left = i;
        }
        else {
            if (i < right) QuickSort(map, i, right);
            right = j;
        }
    } while (left < right);
}

我试图理解内部运作。 AFAIK看起来与Hoare partition scheme非常相似,但略有优化。

我不清楚的是:

  • 为什么我们在分区后只递归枢轴的一侧? (取决于if (j - left <= right - i)
  • 的结果
  • 为什么我们整个事情都有do { ... } while (left < right)?是因为我们只按照上面的建议递归枢轴的一侧吗?
  • 为什么在交换之前有if (i < j)条件测试?不够break;声明吗?

相比之下,这是我实际实现Quicksort的方式(Hoare分区方案的直接实现)

void QuickSort(int[] map, int left, int right)
{
    if (left < right)
    {
        int i = left - 1;
        int j = right + 1;
        int x = map[left + ((right - left) >> 1)];

        while (true)
        {
            do { i++; } while (Compare(map[i], x) < 0);
            do { j--; } while (Compare(map[j], x) > 0);

            if (i >= j) break;

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

        QuickSort(map, left, j);
        QuickSort(map, j + 1, right);
    }
}

1 个答案:

答案 0 :(得分:3)

  

为什么我们在分区后只递归枢轴的一侧?   (取决于if(j - left&lt; = right - i))

的结果

最小化递归深度(和堆栈使用)。当我们尽快处理较大的分区并仅对较小的分区进行递归时,深度不会超过log(n)

  

为什么我们在整个事情上有{...} while(左&lt;右)?

left之前和right之后的项目已排序,因此这些索引在所有数组都已排序时满足

  

为什么在交换之前有if(i&lt; j)条件测试?

只是为了避免对等索引进行不必要的交换