【问题标题】:c++ quick sort running timec++快速排序运行时间
【发布时间】:2019-05-24 15:39:25
【问题描述】:

我有一个关于快速排序算法的问题。我实现了快速排序算法并播放它。 初始未排序数组中的元素是从一定范围内选择的随机数。 我发现随机数的范围会影响运行时间。例如,从 (1 - 2000) 范围内选择的 1, 000, 000 随机数的运行时间需要 40 秒。如果从范围(1 - 10,000)中选择 1,000,000 数字,则需要 9 秒。 但我不知道如何解释。在课堂上,我们讨论了枢轴值可以影响递归树的深度。
对于我的实现,数组的最后一个值被选为枢轴值。我不使用随机方案来选择枢轴值。

int partition( vector<int> &vec, int p, int r) {

  int x = vec[r];
  int i = (p-1);
  int j = p;
  while(1) {

    if (vec[j] <= x){
      i = (i+1);
      int temp = vec[j];
      vec[j] = vec[i];
      vec[i] = temp;
    }
    j=j+1;
    if (j==r)
      break;
 }
  int temp = vec[i+1];
  vec[i+1] = vec[r];
  vec[r] = temp;
  return i+1;
}

void quicksort ( vector<int> &vec, int p, int r) {

  if (p<r){
    int q = partition(vec, p, r);
    quicksort(vec, p, q-1);
    quicksort(vec, q+1, r);
  }
}

    void random_generator(int num, int * array) {

      srand((unsigned)time(0)); 
      int random_integer; 
      for(int index=0; index< num; index++){ 
        random_integer = (rand()%10000)+1; 
        *(array+index) = random_integer; 
      } 
    }

    int main() {
      int array_size = 1000000;
      int input_array[array_size];
      random_generator(array_size, input_array);
      vector<int> vec(input_array, input_array+array_size);

      clock_t t1, t2;
      t1 = clock();
      quicksort(vec, 0, (array_size - 1));   // call quick sort
      int length = vec.size();
      t2 = clock();
      float diff = ((float)t2 - (float)t1);
      cout << diff << endl;
      cout << diff/CLOCKS_PER_SEC <<endl;
    }

【问题讨论】:

  • 3 个枢轴值的中值提供更稳定的实现
  • 您需要发布快速排序代码才能回答您的问题。
  • 你试过C qsort 实现来验证吗?
  • 我想到的唯一因素是,如果可能的值越少,您在数组中获得相同数字的次数就越多,也许快速排序实现会受此影响...
  • @SB,qsort 不强制使用快速排序。有可能,虽然很愚蠢,但它可以使用冒泡排序。

标签: c++ performance quicksort


【解决方案1】:

很可能它表现不佳,因为快速排序不能很好地处理大量重复,并且仍然可能导致交换它们(不能保证保留键相等元素的顺序)。您会注意到每个数字的重复数是 100(10000)或 500(2000),而时间因子也大约是 5 倍。

您是否对每种尺寸至少 5-10 次运行的运行时间进行了平均,以便公平地获得良好的起始支点?

作为比较,您是否检查了 std::sort 和 std::stable_sort 在相同数据集上的表现?

最后对于这种数据分布(除非这是一个快速排序练习),我认为计数排序会好得多 - 40K 内存来存储计数并且它在 O(n) 中运行。

【讨论】:

  • ++ 我怀疑您对重复项是正确的。当然,如果您可以使用它,O(n) 排序就会获胜。 OP 询问的问题是为什么我不信任快速排序。我依赖归并排序,即使我自己编写代码。
【解决方案2】:

这可能与输入的排序程度有关。如果输入是合理随机的,则快速排序为 O(n logn)。如果它的顺序相反,性能可能会降低到 O(n^2)。您可能越来越接近数据范围较小的 O(n^2) 行为。

【讨论】:

  • 我不使用 3 个枢轴选择的中位数。我只是使用数组的最后一个元素被选为枢轴值。
【解决方案3】:

迟到的答案 - 重复的影响取决于分区方案。问题中的示例代码是 Lomuto 分区方案的一种变体,由于分区越来越差,随着重复数量的增加,它需要更多时间。在所有相等元素的情况下,Lomuto 仅在每一级递归中将大小减少 1 个元素。

如果改为使用 Hoare 分区方案(以中间值作为枢轴),随着副本数量的增加,通常需要更少的时间。由于重复,Hoare 将不必要地交换等于枢轴的值,但分区将接近将数组拆分为几乎相同大小的部分的理想情况。交换开销在某种程度上被内存缓存所掩盖。链接到 Hoare 分区方案的 Wiki 示例:

https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme

【讨论】:

    猜你喜欢
    • 2014-08-26
    • 2012-08-26
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 2014-09-17
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    相关资源
    最近更新 更多