【问题标题】:Improve the time complexity of my implementation of Counting Sort (C)提高我实现计数排序 (C) 的时间复杂度
【发布时间】:2019-10-20 16:32:21
【问题描述】:

考虑以下代码:

#define SIZE 12

void randomize(int* array, int array_size);
void print(int* array, int array_size);
void counting_sort(int* array, int array_size);
int get_max(int* array, int array_size);
void construct(int* sorted, int sorted_array_size, int* values);

int main(void)
{
    srand(time(NULL));
    int* array = (int*)malloc(sizeof(int) * SIZE);
    randomize(array, SIZE);
    print(array, SIZE);
    counting_sort(array, SIZE);
    free(array);

    return 0;
}

void randomize(int* array, int array_size) {...}

void print(int* array, int array_size) {...}

void counting_sort(int* array, int array_size) {
    int minVal, maxVal;
    int* sorted = (int*)malloc(sizeof(int) * SIZE);
    maxVal = get_max(array, array_size);

    int* values = (int*)malloc(maxVal * sizeof(int));

    memset(values, 0, maxVal * sizeof(int));

    for (int i = 0; i < array_size; i++) {
        values[array[i]]++;
    }

    construct(sorted, SIZE, values);

    free(values);
    free(sorted);
    }

int get_max(int* array, int array_size) {...}

void construct(int* sorted, int array_size, int* values) {
    for (int i = 0, j = 0; i < array_size; i++) {
        while (!values[++j]);
        sorted[i] = j;
        --values[j];
    }
    print(sorted, SIZE);
} 

main() 声明一个数组,其大小由宏SIZE 控制。然后有一些函数可以随机化、打印并找到该数组的最大值。之后是计数排序本身的实现,它使用construct(..) 函数来创建排序数组。我已经测试了几次,找不到任何错误。然而,这就是我所关心的。

for (int i = 0, j = 0; i < array_size; i++) {
            while (!values[++j]);...

我们有 2 个内部循环,这些循环中的变量递增。这意味着construct(...) 函数的时间复杂度变成二次的,而不是线性的。问题是我想不出一个好方法来丢弃values[] 中的所有0。线性解决方案是最受欢迎的。

添加完整代码:

#include <stdlib.h>
#include <cassert>
#include <time.h>
#include <limits.h>
#include <string.h>

#define SIZE 160

void randomize(int* array, int array_size);
void print(int* array, int array_size);
void counting_sort(int* array, int array_size);
int get_max(int* array, int array_size);
void construct(int* sorted, int sorted_array_size, int* values);

int main(void)
{
    srand(time(NULL));
    int* array = (int*)malloc(sizeof(int) * SIZE);
    randomize(array, SIZE);
    print(array, SIZE);
    counting_sort(array, SIZE);
    free(array);

    return 0;
}

void randomize(int* array, int array_size) {
    for (int i = 0; i < array_size; i++) {
        array[i] = rand() % array_size;
    }
}

void print(int* array, int array_size) {
    for (int i = 0; i < array_size; i++) {
        printf("%4d ", array[i]);
    }
    putchar('\n');
}

void counting_sort(int* array, int array_size) {
    int minVal, maxVal;
    int* sorted = (int*)malloc(sizeof(int) * SIZE);
    maxVal = get_max(array, array_size);

    int* values = (int*)malloc(maxVal * sizeof(int));

    memset(values, 0, maxVal * sizeof(int));

    for (int i = 0; i < array_size; i++) {
        values[array[i]]++;
    }

    construct(sorted, SIZE, values);

    free(values);
    free(sorted);
}

int get_max(int* array, int array_size) {
    int max = INT_MIN;
    for (int i = 0; i < array_size; i++) {
        if (max < array[i]) {
            max = array[i];
        }
    }
    return max;
}

void construct(int* sorted, int array_size, int* values) {
    for (int i = 0, j = 0; i < array_size; i++) {
        while (!values[j]) {
            ++j;
        }
        sorted[i] = j;
        --values[j];
    }
    print(sorted, SIZE);
} 

【问题讨论】:

  • 那段代码还能用吗?你试过像{5,5,5,0,0,0}这样的数组吗?
  • 是的,它适用于这样的数组,@user3386109
  • 可能重复:Correctly allocating multi-dimensional arrays。该程序中明显的性能损失是缺少 2D 数组 - 相反,您正在处理分散在堆中的段。此外,calloc 可能比 malloc + memset 稍微快一点。
  • "变成二次的,而不是线性的。" 不,因为你从来没有重置 j 也没有递减它,所以复杂度是 2*array_size (values如果我理解的话,它的大小与排序的相同)......假设你的算法是正确的(比如@user3386109,我不确定,但你没有给出所有代码)
  • 首先你通过越界访问获得了UB,假设你有一个数组{0,5,4},最大元素为5,那么你分配values,大小为5,然后你访问@987654336 @ 在循环中 (values[array[i]]++;)。

标签: c algorithm time-complexity counting-sort


【解决方案1】:

您的实现是线性的。您有一个内部 while 循环,但 j 的值永远不会重置为 0,它在 for 循环的每次迭代中不断增长。总体而言,i 将从0 计数到sizej 将从0 计数到n

【讨论】:

    猜你喜欢
    • 2013-03-14
    • 2017-06-06
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    相关资源
    最近更新 更多