【问题标题】:Comparing Execution time with Time Complexity in Merge & Quick Sort在合并和快速排序中比较执行时间和时间复杂度
【发布时间】:2020-07-23 10:25:45
【问题描述】:

我已经在教科书中实现了合并和快速排序,它说每种类型的时间复杂度是这样的: 合并排序:O(n.log(n)) / 快速排序:平均 O(n.log(n))O(n 2) 在最坏的情况下(如果键数组已排序)。

所以我使用两种类型的数组执行程序:排序的和随机的,大小不同。

由于我想获得平均时间,我每个案例都尝试了 10 次。

这是合并和快速排序的代码:

#include <iostream>
#include <ctime>
#include <vector>
#include <algorithm>

using namespace std;

void Merge(vector<int>& s, int low, int mid, int high) {
    int i = low;
    int j = mid + 1;
    int k = low;
    vector<int> u(s);

    while (i <= mid && j <= high) {
        if (s.at(i) < s.at(j)) {
            u.at(k) = s.at(i);
            i++;
        } else {
            u.at(k) = s.at(j);
            j++;
        }
        k++;
    }
    if (i > mid) {
        for (int a = j; a < high + 1; a++) {
            u.at(k) = s.at(a);
            k++;
        }
    } else {
        for (int a = i; a < mid + 1; a++) {
            u.at(k) = s.at(a);
            k++;
        }
    }
    for (int a = low; a < high + 1; a++)
        s.at(a) = u.at(a);
}
void MergeSort(vector<int>& s, int low, int high) {
    int mid;
    if (low < high) {
        mid = (low + high) / 2;
        MergeSort(s, low, mid);
        MergeSort(s, mid + 1, high);
        Merge(s, low, mid, high);
    }
}

void swap(int& a, int& b) {
    int tmp = a;
    a = b;
    b = tmp;
}
void Partition(vector<int>& s, int low, int high, int& pvpoint) {
    int j;
    int pvitem;

    pvitem = s.at(low);
    j = low;
    for (int i = low + 1; i <= high; i++) {
        if (s.at(i) < pvitem) {
            j++;
            swap(s.at(i), s.at(j));
        }
        pvpoint = j;
        swap(s.at(low), s.at(pvpoint));
    }
}

void QuickSort(vector<int>& s, int low, int high) {
    int pvpoint;
    if (high > low) {
        Partition(s, low, high, pvpoint);
        QuickSort(s, low, pvpoint - 1);
        QuickSort(s, pvpoint + 1, high);
    }
}

这些 main() 函数中的每一个都以 SORTED 和 RANDOM 键数组的形式打印执行时间。 您可以通过在 Visual Studio(C++) 中添加以下主要功能之一来查看结果:

//Sorted key array
int main() {
    int s;
    for (int i = 1; i < 21; i++) { //Size is from 300 to 6000
        s = i * 300;
        vector<int> Arr(s);
        cout << "N : " << s << "\n";

        //Assign Random numbers to each elements
        Arr.front() = rand() % Arr.size();
        for (int j = 1; j < Arr.size(); j++) { Arr.at(j) = ((737 * Arr.at(j - 1) + 149) % (Arr.size() * 5)); }
        sort(Arr.begin(), Arr.end());

        //QuickSort(Arr, 0, Arr.size() - 1);  <- you can switch using this instead of MergeSort(...) below
        for (int i = 0; i < 10; i++) { //print 10 times of execution time
            clock_t start, end;
            start = clock();
            MergeSort(Arr, 0, Arr.size() - 1);
            end = clock() - start;
            printf("%12.3f  ", (double)end * 1000.0 / CLOCKS_PER_SEC);
        }
        cout << endl;
    }
    return 0;
}

//Random key array
int main() {
    int s;
    for (int i = 1; i < 21; i++) {
        s = i * 3000;
        vector<int> Arr(s);
        cout << "N : " << s << "\n";
        for (int i = 0; i < 10; i++) {
            //Assign Random numbers to each elements
            Arr.front() = rand() % Arr.size();
            for (int j = 1; j < Arr.size(); j++) { Arr.at(j) = ((737 * Arr.at(j - 1) + 149) % (Arr.size() * 5)); }

            //QuickSort(Arr, 0, Arr.size() - 1);  <- you can switch using this instead of MergeSort(...) below
            clock_t start, end;
            start = clock();
            MergeSort(Arr, 0, Arr.size() - 1);
            end = clock() - start;
            printf("%12.3f  ", (double)end * 1000.0 / CLOCKS_PER_SEC);
        }
        cout << endl;
    }
    return 0;
}

问题是,结果与它们的时间复杂度不匹配。例如,合并排序(随机数组) 大小 N=3000 打印 20 毫秒,但大小 N=60000 打印 1400~1600 毫秒 !!它应该打印近 400 毫秒,因为快速排序中的时间复杂度(不是在最坏的情况下)是 O(n.log(n)),不是吗?我想知道对这个时间有什么影响,我怎么能看到我预期的打印时间。

【问题讨论】:

  • 这可能与超过更快缓存的大小有关。假设 L1 缓存为 32 KB,那么 3000 个 int 将适合 L1 缓存,但不是 60,000。时间似乎很慢;您是否在某种调试模式下对此进行测试?
  • 我只是通过调试来测试它,而不是“不调试就开始”,我想知道我做得对。我明白你说的,非常感谢。那么..那么当我用随机测试快速排序时,时间有时会变大,这也是同样的原因吗?(就像 10 个打印时间之一是 1,500 毫秒,其他都是 150 毫秒,N=34000)
  • 增加样本量,直到算法耗时最长约 1 分钟。您无法将如此短的时间与渐近测量进行比较。

标签: time-complexity quicksort mergesort execution-time


【解决方案1】:

您在此问题中发布了相同的代码:Calculate Execution Times in Sort algorithm,但您没有考虑我的回答。

您的MergeSort 函数有一个缺陷:您在merge 中复制了整个 数组,导致大量开销和二次时间复杂度。这个看起来很无辜的定义:vector&lt;int&gt; u(s);u 定义为一个向量,该向量初始化为 s 的副本,即完整数组

C++ 是一种非常强大的语言,通常过于强大,充满了诸如此类的陷阱和陷阱。您尝试从算法的已知时间复杂度来验证您的程序是否满足预期性能是一件非常好的事情。这种担忧实在是太少见了。

【讨论】:

  • 我是多么愚蠢...我以为我已经修复了合并功能,但是复制粘贴时仍然是以前的代码,这并不意味着我没有回答。对不起,再次感谢:D
  • @qkekehrtnfl97:没问题。您也可以对对您有帮助的答案投票。
猜你喜欢
  • 2012-05-07
  • 2012-07-06
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
  • 2015-07-22
  • 2014-08-26
  • 2020-08-08
  • 1970-01-01
相关资源
最近更新 更多