优化冒泡排序——我错过了什么?

Optimizing bubble sort - What am I missing?

我正在尝试了解冒泡排序算法的可能优化方法。我知道有更好的排序方法,但我只是好奇

为了测试我使用 std::chrono 的效率。该程序对 10000 number long int 数组排序 30 次并打印平均排序时间。在每次迭代中随机选择数字(最多 10000)。这是代码,没有优化:

#include <iostream>
#include <ctime>
#include <chrono>
using namespace std;



int main() {


    //bubble sort
    srand(time(NULL));

    chrono::time_point<chrono::steady_clock> start, end;

    const int n = 10000;
    int i,j, last, tests = 30,arr[n];
    long long total = 0;
    bool out;

    while (tests-->0) {


        for (i = 0; i < n; i++) {
            arr[i] = rand() % 1000;
        }


        j = n;

        start = chrono::high_resolution_clock::now();
        while(1){

            out = 0;
            for (i = 0; i < j - 1; i++) {

                if (arr[i + 1] < arr[i]) {
                    swap(arr[i + 1], arr[i]);
                    out = 1;
                }
            }

            if (!out) {
                    break;
            }

            //j--;

        }


        end = chrono::high_resolution_clock::now();

        total += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
        cout << "Remaining :"<<tests << endl;

    }

    cout << "Average  :" << total / static_cast<double>(30)/1000000000<<" seconds"; // tests(30)  + nanosec -> sec


    cin.sync();
    cin.ignore();
    return 0;
}

我得到 0.17 秒的平均排序时间。

如果我取消注释第 47(j--;) 行以避免比较已经排序的数字,我得到 0.12 排序时间,这是可以理解的。

如果我记得交换发生的最后位置,我知道在那个索引之后,元素被排序,因此可以在进一步的迭代中排序到那个位置。 post 的第二部分对此有更好的解释:。 这是实现新的可能优化的代码:

#include <iostream>
#include <ctime>
#include <chrono>
using namespace std;



int main() {


    //bubble sort
    srand(time(NULL));

    chrono::time_point<chrono::steady_clock> start, end;

    const int n = 10000;
    int i,j, last, tests = 30,arr[n];
    long long total = 0;
    bool out;

    while (tests-->0) {


        for (i = 0; i < n; i++) {
            arr[i] = rand() % 1000;
        }


        j = n;

        start = chrono::high_resolution_clock::now();
        while(1){

            out = 0;
            for (i = 0; i < j - 1; i++) {

                if (arr[i + 1] < arr[i]) {
                    swap(arr[i + 1], arr[i]);
                    out = 1;
                    last = i;
                }
            }

            if (!out) {
                    break;
            }

            j = last + 1;

        }


        end = chrono::high_resolution_clock::now();

        total += chrono::duration_cast<chrono::nanoseconds>(end - start).count();
        cout << "Remaining :"<<tests << endl;

    }

    cout << "Average  :" << total / static_cast<double>(30)/1000000000<<" seconds"; // tests(30)  + nanosec -> sec


    cin.sync();
    cin.ignore();
    return 0;
}

注意第 40 和 48 行。问题来了:平均时间现在又是 0.17 秒左右。 我的代码有问题,还是我遗漏了什么?

更新:

我用 10 倍以上的数字进行排序,现在得到以下结果: 无优化:19.3 秒 第一次优化(j--):14.5秒 第二次(假设)优化(j=last+1):17.4 秒;

根据我的理解,第二种方法在任何情况下都应该比第一种好,但数字说明了一些不同的东西。

嗯...问题是这个问题可能没有正确或错误的答案。

首先,当你只比较 10000 个元素时,你不能真正称之为效率测试。尝试比较更多数量的元素 - 可能是 500000(尽管您可能需要为此动态分配一个数组)。

其次,可能是编译器。编译器经常尝试优化一些东西,以便程序执行 运行 更流畅、更快。