【问题标题】:Calculate Execution Times in Sort algorithm在排序算法中计算执行时间
【发布时间】:2020-07-22 04:36:25
【问题描述】:

我在 C++ 中实现了合并排序和快速排序,我想使用两者中的每一个来获取执行时间,其中许多情况已经排序或未排序并且大小不同。

#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);
    }
}

int main() {
    vector<int> CaseSize(20);

    for (int i = 0; i < 10; i++) { //10 Arrays those are sorted
        CaseSize.at(i) += (i + 1) * 500;
    }

    for (int i = 10; i < 20; i++) { //rest 10 those are not sorted
        CaseSize.at(i) += (i + 1) * 5000;
    }

    cout << "------------------Sorted------------------\n\n";
    cout << "      Quick Sort       Merge Sort\n";
    for (int i = 0; i < 10; i++) {
        vector<int> Arr(CaseSize.at(i));
        Arr.front() = rand() % Arr.size();
        for (int j = 1; j < Arr.size(); j++) {
            Arr.at(j) = ((17 * Arr.at(j - 1) + 43) % (Arr.size() * 5));
        }
        vector<int> Arr2(Arr);

        sort(Arr.begin(), Arr.end());
        sort(Arr2.begin(), Arr2.end());

        cout << "N : " << CaseSize.at(i) << "    ";
        clock_t start = (int)clock();
        QuickSort(Arr, 0, Arr.size() - 1);
        printf("%0.5fms", (float)(clock() - start) / CLOCKS_PER_SEC);
        cout << "\t\t";

        clock_t start2 = (int)clock();
        MergeSort(Arr2, 0, Arr2.size() - 1);
        printf("%0.5fms", (float)(clock() - start) / CLOCKS_PER_SEC);
        cout << endl;
    }
    cout << endl;
    cout << "------------------Random------------------\n\n";
    cout << "        Quick Sort     Merge Sort\n";
    for (int k = 10; k < 20; k++) {
        vector<int> Arr(CaseSize.at(k));
        Arr.front() = rand() % Arr.size();
        for (int l = 1; l < Arr.size(); l++) {
            Arr.at(l) = ((17 * Arr.at(l - 1) + 43) % (Arr.size() * 5));
        }
        vector<int> Arr2(Arr);

        cout << "N : " << CaseSize.at(k) << "    ";

        clock_t start = (int)clock();
        QuickSort(Arr, 0, Arr.size() - 1);
        printf("%0.5fms", (float)(clock() - start) / CLOCKS_PER_SEC);

        cout << "\t\t";

        clock_t start2 = (int)clock();
        MergeSort(Arr2, 0, Arr2.size() - 1);
        printf("%0.5fms", (float)(clock() - start) / CLOCKS_PER_SEC);
        cout << endl;
    }
    return 0;
}

嗯,程序确实可以运行,但是打印的执行时间与我预期的不一样。 我做得好吗?我想运行这两种算法以显示它们的执行时间,因此我可以通过这种方式比较它们的 TIME COMPLEXITY(尽可能不修复排序算法)。

【问题讨论】:

  • 它打印了什么,你期望什么?
  • vector&lt;int&gt; CaseSize(20); -- 这是一个太小的测试用例。即使使用冒泡排序,所花费的时间也是瞬时的。您需要数千甚至数百万个元素。
  • 要绘制时间复杂度,您需要涉及多个 N 值。这里只有一个。尝试使用 20、200、2000、20000 等。每次增加 10 次方。
  • 另外,如果您想看到快速排序要慢得多,因为它最坏的情况是O(n^2),而合并排序的情况是O(n*log(n))。但这在随机测试中并没有太大区别,因为快速排序的平均情况是 O(n*log(n))
  • 还要确保您正在使用编译器优化

标签: c++ time-complexity quicksort mergesort


【解决方案1】:

您的合并排序算法非常效率低下:Merge 在每次递归调用开始时复制整个数组,这是一个二次成本。

在一些非常常见的情况下,快速排序的实现也非常慢:如果数组已经排序,枢轴值总是切片中的最小元素,所以递归深度是数组的长度,你得到二次如果不是堆栈溢出,则时间复杂度。

如果不衡量这些低效率是否会最大程度地损害性能,很难判断,但我猜MergeSort 是失败者。

另外,如果你想打印毫秒,使用这个表达式:

printf("%0.5fms", (clock() - start) * 1000.0 / CLOCKS_PER_SEC);

要解决Merge 中的问题,请修改代码以创建正确大小的向量:

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

    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) {
        while (j <= high) {
            u.at(k) = s.at(j);
            j++;
            k++;
        }
    } else {
        while (i <= mid) {
            u.at(k) = s.at(i);
            i++;
            k++;
        }
    }
    for (i = low, k = 0; i <= high; i++, k++)
        s.at(i) = u.at(k);
}

【讨论】:

  • 感谢您的回答!!实际上,我认为我仍然无法在这里看到准确的时间(我正在尝试使用 Putty 和 Visual Studio),所以我认为我应该修复更多
  • @qkekehrtnfl97:精确计时代码是一门难的艺术。在其他陷阱和陷阱中,您应该避免在所有测试完成之前产生输出。将经过的时钟值存储在一个数组中,并在所有测试完成后循环输出时序表。您还应该通过循环检查数组是否已排序来检查排序功能是否正确完成。您还可以对 C++ sort 模板函数进行基准测试以供参考。
猜你喜欢
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-10
  • 2010-10-26
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多