如何对包含NaN的C的数组进行排序

时间:2019-03-13 21:47:40

标签: c nan bubble-sort

一直在尝试实现我的代码,以对包括NaN在内的所有整数进行排序。但是似乎找不到找到将NaN排序到我的程序中的函数。代码可以对包括整数在内的其他整数进行排序,但是,当输入nan时,程序会识别输入,但不会将其排序到列表的开头。任何帮助,将不胜感激。

#include <stdio.h>
#include <math.h>

int main()
{
    float array[100], swap;
    int c, d, n;

    printf("Enter the size of array\n");
    scanf("%d", &n);

    printf("Enter %d integers\n", n);

    for (c = 0; c < n; c++)
        scanf("%f", &array[c]);

    for (c = 0; c < (n - 1); c++)
    {
        for (d = 0; d < n - c - 1; d++)
        {
            if (array[d] > array[d + 1]) 
            {
                swap = array[d];
                array[d] = array[d + 1];
                array[d + 1] = swap;
            }
        }
    }

    printf("Sorted array in ascending order:\n");


    for (c = 0; c < n; c++)
        printf("%f\n", array[c]);

    return 0;
}

2 个答案:

答案 0 :(得分:1)

请注意,根据C标准,即使两个NaN值具有相同的位模式,它们也不会比较相等。如果要使用NaN排序数据,则需要:

  1. 确定应将NaN值排序为正确值的位置(通常是“在负无穷大之前”或“在正无穷大之后”)。
  2. 使用比简单的a > b比较要精致得多的测试。

您可以找到散布在C11标准周围的相关信息。例如:

您可能会安排创建一个比较两个相关类型的浮点值的函数(可能是inline函数,除非您要将其传递给类似qsort()的函数)。似乎您正在使用floatisnan()分类宏来确定两个值中的一个或两个都是NaN的isnanf()。如果两个值都是NaN,则该函数可能会返回一个表示相等的值,但是如果一个值是NaN,则返回值会将其放置在另一个值之前或之后,这取决于您希望NaN出现的顺序,并且它将返回比较其他值(正常值,零,无穷大,次正规数)的合适值-常规值和无穷大只需要常规比较运算符,除非您需要正确地对负零和正零进行排序。

例如,编写一个适用于qsort()(并使用类型double而不是float的函数)的结果类似,假定数字应按升序排序,并且NaN的比较值应小于任何其他值。该代码包括用于从标准输入读取数据,对其进行打印,对其进行排序并再次打印的测试代码。

#include <math.h>

/* Belongs in a header! */
extern int cmp_double(const void *v1, const void *v2);

/* Sort doubles, with NaNs coming first */
/* Switch return values -1 and +1 after testing n1, n2 to sort NaNs last */
int cmp_double(const void *v1, const void *v2)
{
    double d1 = *(const double *)v1;
    double d2 = *(const double *)v2;
    int n1 = isnan(d1);
    int n2 = isnan(d2);

    if (n1 && n2)
        return 0;
    if (n1)
        return -1;
    if (n2)
        return +1;
    if (d1 < d2)
        return -1;
    if (d1 > d2)
        return +1;
    // The values are 'equal', but …
    if (d1 != 0.0)
        return 0;
    // They're both zero, but they could have different signs
    int s1 = signbit(d1);
    int s2 = signbit(d2);
    if (s1 != s2)
        return (s1) ? -1 : +1;
    return 0;
}

#include <stdio.h>
#include <stdlib.h>

static void dump_doubles(const char *tag, int num, double values[num])
{
    printf("%s (%d):\n", tag, num);
    int line_len = 0;
    for (int i = 0; i < num; i++)
    {
        int n = printf(" %+12.4f", values[i]);
        if (n <= 0)
            break;
        line_len += n;
        if (line_len >= 60)
        {
            line_len = 0;
            putchar('\n');
        }
    }
    if (line_len > 0)
        putchar('\n');
}

int main(void)
{
    enum { NUM_VALUES = 50 };
    double values[NUM_VALUES];

    int i = 0;

    for (i = 0; i < NUM_VALUES; i++)
    {
        if (scanf("%lf", &values[i]) != 1)
            break;
    }

    dump_doubles("Before sort", i, values);
    qsort(values, i, sizeof(values[0]), cmp_double);
    dump_doubles("After sort", i, values);

    return 0;
}

请注意在+0.0之前对-0.0进行排序所需的测试!

考虑输入数据:

3023.421800 9033.902200 nan -9370.952500 3088.884900 6829.135400 0
-0.000000 -inf -5267.546800 -8784.373300 5663.944600 -9728.231300 inf
-inf -5373.038600 4282.941600 6245.734200 -5533.975400 nan 8445.713600
+inf -9108.960400 -3796.671200 nan -2363.851300 877.460400 9936.416900
-3480.867400

输出是:

Before sort (29):
   +3023.4218   +9033.9022          nan   -9370.9525   +3088.8849
   +6829.1354      +0.0000      -0.0000         -inf   -5267.5468
   -8784.3733   +5663.9446   -9728.2313         +inf         -inf
   -5373.0386   +4282.9416   +6245.7342   -5533.9754          nan
   +8445.7136         +inf   -9108.9604   -3796.6712          nan
   -2363.8513    +877.4604   +9936.4169   -3480.8674
After sort (29):
          nan          nan          nan         -inf         -inf
   -9728.2313   -9370.9525   -9108.9604   -8784.3733   -5533.9754
   -5373.0386   -5267.5468   -3796.6712   -3480.8674   -2363.8513
      -0.0000      +0.0000    +877.4604   +3023.4218   +3088.8849
   +4282.9416   +5663.9446   +6245.7342   +6829.1354   +8445.7136
   +9033.9022   +9936.4169         +inf         +inf

答案 1 :(得分:-1)

如评论中所述,您的代码是C代码而不是C ++。这是您的C ++代码,带有附加条件,可以解决您的问题:

#include <iostream>
#include <vector>
#include <cmath>

int main()
{
    std::size_t array_size;
    std::cout << "Enter the size of array\n";
    std::cin >> array_size;

    std::cout << "Enter " << array_size << " integers\n";

    std::vector<float> array(array_size);
    for(std::size_t i = 0; i < array.size(); ++i)
        std::cin >> array[i];

    for(std::size_t a = 0; a < array.size() - 1; ++a)
        for(std::size_t b = 0; b < array.size() - 1 - a; ++b)
            if(std::isnan(array[b + 1]) || array[b] > array[b + 1])
                std::swap(array[b], array[b + 1]);

    std::cout << "Sorted array in ascending order:\n";

    for(const auto& a : array)
        std::cout <<  a << '\n';

    return 0;
}

如果您不想自己编写所有排序内容,则可以使用更多的C ++和算法库(以及添加的输入检查)来做到:

template<typename T>
T get_input()
{
    T input;
    while(true)
    {
        std::cin >> input;
        if(std::cin)
            return input;
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "Invalid input! Please try again.\n";
    }
}

int main()
{
    std::cout << "Enter the size of array\n";
    std::size_t array_size = get_input<std::size_t>();

    std::cout << "Enter " << array_size << " integers\n";

    std::vector<float> input(array_size);
    for(auto& a : input)
        a = get_input<float>();

    std::sort(input.begin(), input.end(), [](const auto& a, const auto& b){ return std::isnan(a) || a < b; });

    std::cout << "Sorted array in ascending order:\n";

    for(const auto& a : input)
        std::cout << a << '\n';
}