数字的输入和输出如何在C中对数组进行排序?

时间:2017-07-22 05:59:37

标签: c sorting

以下代码如何打印排序数组?我无法理解这背后的逻辑。

#include <stdio.h>

int a[1000000];

int main(void) {
    int t, i = 0, temp;
    scanf("%d", &t);
    for (i = 0; i < t; i++) {
        scanf("%d", &temp);
        a[temp]++;
    }
    for (i = 0; i <= 1000000; i++) {
        while (a[i] != 0) {
            printf("%d\n", i);
            a[i]--;
        }
    }
    return 0;
}

3 个答案:

答案 0 :(得分:1)

让我们分成更小的部分:

scanf("%d", &t);

这很简单:它向用户询问一个整数,并将其存储在t中。此变量表示我们要排序的整数数。

for(i = 0; i < t ; i++)
{
    scanf("%d", &temp);
    a[temp]++;
}

这段代码要求用户输入t个整数。在每次迭代中,数组temp的位置a的值都会增加。

这是什么意思?将数组a视为计数器数组,其中每个计数器最初设置为0.当用户输入新的整数n时,n的计数器(即{{1} })增加。

在循环结束时,数组a[n]的第j个元素存储数字a的出现次数。

假设您有以下数字要排序: j

在第一次迭代之前:4 1 8 7 6 7

  1. a = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...]
  2. a[4]++ => a = [0, 0, 0, 0, 1, 0, 0, 0, 0, ...]
  3. a[1]++ => a = [0, 1, 0, 0, 1, 0, 0, 0, 0, ...]
  4. a[8]++ => a = [0, 1, 0, 0, 1, 0, 0, 0, 1, ...]
  5. a[7]++ => a = [0, 1, 0, 0, 1, 0, 0, 1, 1, ...]
  6. a[6]++ => a = [0, 1, 0, 0, 1, 0, 1, 1, 1, ...]
  7. 此时,您已经完成了打印它们所需的一切:

    a[7]++ => a = [0, 1, 0, 0, 1, 0, 1, 2, 1, ...]

    第二个for(i=0; i <= 1000000; i++) { while(a[i] != 0) { printf("%d\n", i); a[i]--; } } 循环遍历for的所有元素,即所有&#39;计数器&#39;。当计数器大于0时,打印a的次数等于计数器的值。回想一下,i不仅是此循环中数组当前元素的位置,而且它也是与计数器关联的数字。

    这是一个聪明的算法,不需要比较,但它有一些陷阱。

    1. 您只能排序整数,例如没有花车。
    2. 您只能排序正整数,例如没有负整数。
    3. 要排序的整数的最大值受数组长度的限制。
    4. 如果您只需要排序2个数字,并且这些数字是1和1000,则需要一个长度为1001的数组。
    5. 可以修改算法的实现以解决或缓解上述问题。

      如果您想了解有关此主题的更多信息,请参阅Counting Sort

答案 1 :(得分:1)

首先,数组应该是[1000001],或者for循环应该是for(i=0;i<1000000;i++)。假设第二个答案

据我所知,数组中允​​许的最大数量必须为999999。 该程序的主要逻辑(实现Count Sort)是:

  1. 计算范围内每个可能数字的频率(0 - 999999)。
  2. 遍历从0到999999的每个可能的数字并检查其频率,打印它在原始数组中出现的次数
  3. <小时/>     int a[1000000];:这声明一个数组,用于保存每个数字的频率,范围为0 - 999999,每个数字的频率与数字本身的索引相同,即数字n的频率将为[n]。< p>

    for(i=0;i<t;i++)
    {
        scanf("%d",&temp);
        a[temp]++;
    }
    

    此代码扫描每个元素并更新其频率(每次出现时增加1)。

    for(i=0;i<=1000000;i++)
    {
        while(a[i]!=0)
        {
            printf("%d\n",i);
            a[i]--;
        }
    }
    

    遍历每个元素0到999999,并为每个元素:     打印元素并将其频率降低1,直到其频率变为0,即打印元素与其频率相同的次数。

    <小时/> 为什么会这样?

    我们得到一个数组,按升序排序(从代码中假设)。 升序意味着首先是较小的数字。

    因此,我们从范围内的最小数量开始,并检查它是否存在。如果它存在于数组中,我们将它打印出它在数组中出现的次数。一旦完成最小数字,我们将继续下一个最小数字并重复相同的数字。

    重复相同的直到999999将确保打印的数组现在按升序排列,因为我们首先打印数字较小的数组,并且与原始数组相同,因此,没有数字会出现比原始数组更多或更少的数字

答案 2 :(得分:0)

步骤很简单:

  • 数组a用于计算输入的每个数字的出现次数。
  • 第二个循环遍历此数组,打印计数非零的数字相应的次数。

这种非常简单的排序方法称为计数排序。

请注意,该程序有缺点和潜在的错误:

  • 未测试scanf()的返回值,如果输入无法转换为整数,则会导致潜在的未定义行为。

  • 数字必须在0999999的范围内。超出此范围的数字将导致未定义的行为。

  • 最终循环包含迭代到1000000,访问超出最后一个元素的数组,导致未定义的行为。

以下是更正后的版本:

#include <stdio.h>

int a[1000000];

int main(void) {
    int t, i, temp;
    if (scanf("%d", &t) != 1)
        return 1;
    for (i = 0; i < t; i++) {
        if (scanf("%d", &temp) != 1)
            return 1;
        if (temp < 0 || temp >= 1000000) {
            fprintf(stderr, "number is out of range: %d\n", temp);
            continue;
        }
        a[temp]++;
    }
    for (i = 0; i < 1000000; i++) {
        while (a[i] != 0) {
            printf("%d\n", i);
            a[i]--;
        }
    }
    return 0;
}