【问题标题】:How does the quicksort function work in a quicksort algorithm?快速排序函数在快速排序算法中是如何工作的?
【发布时间】:2020-03-23 13:55:09
【问题描述】:

我已经了解了快速排序算法中的分区部分是如何完成的,但是我无法理解快速排序递归函数。有人可以逐步向我解释它是如何工作的吗?我在这里粘贴 C++ 代码。

using namespace std;

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int myArray[], int low, int high) {
    int i = (low - 1);
    int pivot = myArray[high];

    for (int j = low; j <= high - 1; j++) {
        if (myArray[j] < pivot) {
            i++;
            swap(&myArray[i], &myArray[j]);
        }
    }
    swap(&myArray[i + 1], &myArray[high]);
    return (i + 1);
}

void quickSort(int myArray[], int low, int high) {

    if (low < high) {
        int pi = partition(myArray, low, high);

        quickSort(myArray, low, pi - 1);
        quickSort(myArray, pi + 1, high);
    }
}

void cinArray(int myArray[], int n) {
    for (int p = 0; p < n; p++) {
        cin >> myArray[p];
    }
}

void print(int myArray[], int n) {
    for (int z = 0; z < n; z++) {
        cout << myArray[z] << "\t";
    }
}

int main() {
    int myArray[10];
    int size = sizeof(myArray) / sizeof(myArray[0]);
    cout << "Write 10 numbers: ";
    cinArray(myArray, size);
    quickSort(myArray, 0, size - 1);
    print(myArray, size);
    return 0;
}

到目前为止,我的逻辑(一步一步)如下:

  1. if (low &lt; high) 永远是真的。第一次, 低 (0) 和高 (9) 值取自 int main。
  2. Pi 将等于分区函数的返回值 (i+1),我想为了返回该值,函数 必须先运行。
  3. 我们调用快速排序函数两次,为函数提供新参数。一次为 来自原始分区的 i+1 之后的值之前和一次的值。我想关注第一个发生的事情,即具有 i+1 之前值的那个。
  4. 函数再次启动,if语句为真(永远为真),pi调用函数partition并返回i+1,pi等于i+1。如果此时值仍未排序怎么办?我想快速排序功能会再次重新启动(感觉就像一个循环)。但既然 IF 语句永远为真,那么这种循环情况何时会停止呢?
  5. 另外,假设我在第 4 点的逻辑是正确的,那么代码第一次运行如何?它是否从第一个 quickSort(myArray, low, pi - 1); 函数调用开始并循环直到有东西停止它,然后对第二个调用 quickSort(myArray, pi + 1, high); 执行相同的操作?还是在 i+1 之前分区,然后在 i+1 之后分区并重新启动函数?

我知道这是一个基本问题,但我真的很难理解这个算法。

【问题讨论】:

    标签: c++ algorithm sorting quicksort


    【解决方案1】:

    if (low &lt; high) will always be true.

    不正确。第一次调用时会这样,但 QuickSort 调用自身是递归的,lowhigh 之间的间隔越来越小。这个if 是算法最终终止的原因 - 你在下面问这个问题。

    Pi will be equal to the returned value of the partition funcion (i+1)

    没错。 pi 是枢轴索引的缩写,即分区后所选枢轴结束的位置。

    And what if at this point the values are still not sorted?

    分区后,你知道左分区中没有值大于枢轴值,右分区中没有值小于枢轴值。这就是你所知道的,所有的算法都需要知道才能最终成功。每个分区被递归分区,直到它只有一个元素。

    when will this loop situation stop?

    请参阅我的第一点。

    【讨论】:

    • 当一个分区(比如说分区 A)再次被划分为 2 个较小的分区(A1 和 A2)时,这两个分区都需要再次分区,直到如你所说,还有IF 语句为真的要素很少。将第一个分区 A 划分为 2 个较小的分区后,是否计算两个递归调用? (对于小于和大于枢轴的值)。为了更好地解释,代码将像这样工作:1) 为 A1 运行调用函数 2) 为 A2 运行调用函数?还是代码一直处理A1,直到不能再分区,再转到A2?
    • 据我所知,机器会在继续前进之前尽可能多地尝试进入兔子洞以获得答案。这就是为什么我最初的印象是 A1 将被分区直到它不能再分区了,但是分区 A2 发生了什么?它跳回它?所以主要是处理代码的顺序让我不理解这个过程。 (也感谢您的回答)
    • 您是正确的,QS 使用深度优先方法,因此在初始分区之后,左侧分区在处理右侧分区之前被完全排序(通过递归)。
    【解决方案2】:

    分区函数将枢轴元素放置在适当的位置,并将索引返回到枢轴元素。接下来的两个调用不包括该元素,在最坏的情况下,一个调用将针对零个元素,另一个针对 n-1 个元素,并且继续最坏的情况,传递的大小仅减少 1 个元素每一级递归,时间复杂度为 O(n^2)。最好的情况是,如果枢轴最终位于中间,在每个递归级别上都有一个偶数拆分,或者时间复杂度 O(n log(n)) 接近偶数拆分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 2016-11-24
      • 2018-05-17
      • 1970-01-01
      • 1970-01-01
      • 2018-04-13
      相关资源
      最近更新 更多