如果这两个冒泡排序实现的步数和交换次数相似,为什么它们在运行时会有显着差异?

时间:2018-11-25 18:32:07

标签: c

我试图在C语言中实现冒泡排序。I've done so in this gist.

我实现了Wikipedia上关于冒泡排序的文章sort_bubble提出的算法,并将其与我在github bubble_sort上找到的参考实现进行了比较:

typedef struct Bubble_Sort_Stats {
    int num_swaps;
    int num_steps;
} bubble_sort_stats_t;

bubble_sort_stats_t bubble_sort(int arr[], int n) {
    bubble_sort_stats_t stats;
    stats.num_swaps = 0;
    stats.num_steps = 0;

    int temp;
    int i;
    int j;

    while (i < n) {
        j = 0;
        while (j < i) {
            stats.num_steps++;
            if (arr[j] > arr[i]) {
                temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
                stats.num_swaps++;
            }
            j++;
        }
        i++;
    }
    return stats;
}

bubble_sort_stats_t sort_bubble(int array[], int length_of_array) {
    bubble_sort_stats_t stats;
    stats.num_swaps = 0;
    stats.num_steps = 0;

    int n = length_of_array;
    int new_n;
    while (n >= 1) {
        new_n = 0;
        for (int i = 0; i < n - 1; i++) {
            stats.num_steps++;

            if (array[i] > array[i+1]) {
                int l = array[i];
                stats.num_swaps++;
                new_n = i + 1;
                array[i] = array[i + 1];
                array[i + 1] = l;
            }
        }
        n = new_n;
    }

    return stats;
}

#define BIG 10000

int main() {
    int nums1[BIG], nums2[BIG];
    for (int i = 0; i < BIG; i++) {
        int newInt = rand() * BIG;;
        nums1[i] = newInt;
        nums2[i] = newInt;
    }

    long start, end;
    bubble_sort_stats_t stats;

    start = clock();
    stats = bubble_sort(nums2, BIG);
    end = clock();
    printf("It took %ld ticks and %d steps to do %d swaps\n\n", end - start, stats.num_steps, stats.num_swaps);

    start = clock();
    stats = sort_bubble(nums1, BIG);
    end = clock();
    printf("It took %ld ticks and %d steps to do %d swaps\n\n", end - start, stats.num_steps, stats.num_swaps);

    for (int i = 0; i < BIG; i++) {
        if (nums1[i] != nums2[i]) {
            printf("ERROR at position %d - nums1 value: %d, nums2 value: %d", i, nums1[i], nums2[i]);
        }

        if (i > 0) {
            if (nums1[i - 1] > nums1[i]) {
                printf("BAD SORT at position %d - nums1 value: %d", i, nums1[i]);
            }
        }
    }

    return 0;
}

现在,当我运行该程序时,我得到以下结果:

It took 125846 ticks and 49995000 steps to do 25035650 swaps

It took 212430 ticks and 49966144 steps to do 25035650 swaps

也就是说,交换的次数是相同的,sort_bubble实际上需要执行更少步,但是这种大小的数组几乎要花两倍的时间!

我怀疑差异与控件结构本身,索引有关,与之类似。但是我对c编译器如何工作以进一步猜测并不太了解,甚至不知道如何通过调试来确定。

所以我想知道为什么,但是我也想凭经验找出答案。

1 个答案:

答案 0 :(得分:3)

您的bubble_sort实际上不是冒泡排序:它不仅比较相邻的对。

这是一个插入排序,其内部循环奇怪地反转了,该循环仍按预期工作。可以按以下方式重写它,而无需更改步骤数或交换数。

bubble_sort_stats_t bubble_sort(int arr[], int n) {
    bubble_sort_stats_t stats;
    stats.num_swaps = 0;
    stats.num_steps = 0;

    for (int i = 1; i < n; i++) {
        for (int j = i; j > 0; j--) {
            stats.num_steps++;
            if (arr[j-1] > arr[j]) {
                int temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;

                stats.num_swaps++;
            }
        }
    }
    return stats;
}

要从中获得适当的插入排序,只需将if条件移动到内部循环中,如下所示。

bubble_sort_stats_t bubble_sort(int arr[], int n) {
    bubble_sort_stats_t stats;
    stats.num_swaps = 0;
    stats.num_steps = 0;

    for (int i = 1; i < n; i++) {
        for (int j = i; j > 0 && arr[j-1] > arr[j]; j--) {
            stats.num_steps++;

            int temp = arr[j];
            arr[j] = arr[j-1];
            arr[j-1] = temp;

            stats.num_swaps++;
        }
    }
    return stats;
}

这样,您可以看到步骤数实际上等于交换次数,并且小于实际冒泡排序(sort_bubble)的步骤数。