快速排序代码说明

时间:2012-08-15 18:45:11

标签: c++ algorithm recursion quicksort

这是我遇到的实现快速排序算法的代码。你能解释一下递归是如何起作用的吗?

 void quickSort(int arr[], int left, int right)
 {
  int i = left, j = right;
  int tmp;
  int pivot = arr[(left + right) / 2];

  /* partition */
  while (i <= j) {
        while (arr[i] < pivot)
              i++;
        while (arr[j] > pivot)
              j--;
        if (i <= j) {
              tmp = arr[i];
              arr[i] = arr[j];
              arr[j] = tmp;
              i++;
              j--;
    }
}
/* recursion */
if (left < j)
    quickSort(arr, left, j);
if (i < right)
        quickSort(arr, i, right);
}

请注意,这不是作业。

3 个答案:

答案 0 :(得分:8)

不确定你的意思是“解释递归是如何工作的”。但是你走了:

您发布的函数采用了一组int和两个索引。它不会对整个数组进行排序,只会对两个索引之间的部分进行排序,忽略它们之外的任何内容。这意味着如果传递第一个和最后一个索引,相同的函数可以对整个数组进行排序,或者如果传递的left值不是数组的第一个元素的索引和/或right值不是最后一个元素的索引。

排序算法是众所周知的快速排序。作为枢轴,它使用中心元素(它也可以使用任何其他元素)。它将数组分区为less than (or equal to) pivot子阵列和greater than (or equal to) pivot子阵列,留下的元素等于两个分区之间的数据透视。

然后它递归调用自己对两个分区进行排序,但只在必要时才进行排序(因此在递归调用之前是ifs)。

实施有效,但在许多方面都是次优的,可以改进。 以下是一些可能的改进:

  1. 如果阵列足够短,则切换到另一种排序算法
  2. 选择轴心值为三个值的中位数(通常是第一个,最后一个和中间个)
  3. 最初将一个透视值移出数组(将其置于第一个或最后一个位置并将焦点减少到数组的其余部分)然后更改测试以传递等于数据透视表的值以减少数量交换涉及他们。您将把枢轴值重新放入最后的最终交换中。如果您不遵循建议2并选择第一个/最后一个元素而不是中间元素,则此功能特别有用。

答案 1 :(得分:4)

迟到的回复,但我刚刚添加了一些打印件,它可能会帮助遇到这种情况的人理解代码。

#include<iostream>
using namespace std;

void quickSort(int arr[], int left, int right)
 {
  int i = left, j = right;
  int tmp;
  int pivot = arr[abs((left + right) / 2)];
  cout<<"pivot is"<<pivot<<endl;

  /* partition */
  while (i <= j) {
        while (arr[i] < pivot)
              i++;
        while (arr[j] > pivot)
              j--;
        if (i <= j) {
              cout<<"i and j are"<<i<<" "<<j<<"and corresponding array value is"<<arr[i]<<" " <<arr[j]<<endl;
              tmp = arr[i];
              arr[i] = arr[j];
              arr[j] = tmp;
              i++;
              j--;
              cout<<"entering first big while loop"<<endl;
         for(int i=0;i<7;i++)
    cout<<arr[i]<<" "<<endl ;
    }
}
cout<<"recursion"<<endl;

/* recursion */
if (left < j)
    quickSort(arr, left, j);

if (i< right)
        quickSort(arr, i, right);
}
int main(){
    int arr[7]= {2,3,8,7,4,9,1};
        for(int i=0;i<7;i++)
    cout<<arr[i]<<" " ;
    quickSort(arr,0,6);
    cout<<endl;
    for(int i=0;i<7;i++)
    cout<<arr[i]<<" " ;
int wait;
cin>>wait;
return 0;
}

答案 2 :(得分:1)

这是你的答案 - 在通常的情况下,将执行递归调用,因为它们之上的条件将为真。但是,在角落情况下,您可以将pivot元素设置为最大(或最小)元素。在这种情况下,您只需要进行一次递归调用,在从数组中删除pivot元素后,通过选择不同的pivot,基本上将再次尝试该进程。