我的代码无法进行排序

时间:2019-06-09 07:52:14

标签: c

我有一些代码和一些测试用例。第一个案例通过了,第二个失败了。 我不明白问题是什么。

问题: 您会得到N个三角形,具体来说是它们的边a [i],b [i]和c [i]。以相同的样式打印它们,但按其面积从最小到最大进行排序。保证所有区域都不同。

我正在使用苍鹭的公式:

    double p = (a + b + c) / 2;
    double area = sqrt(p*(p-a)*(p-b)*(p-c))
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct triangle
{
int a;
int b;
int c;
};

typedef struct triangle triangle;

double area(int a, int b, int c)
{
    a = (double) a;
    b = (double) b;
    c = (double) c;

    double p = (a + b + c) / 2;
    return sqrt(p*(p-a)*(p-b)*(p-c));
}

int compareTringle(const void* left, const void* right){

  double leftArea = area(((triangle *)left)->a, ((triangle *)left)->b,
              ((triangle *)left)->c);
  double rightArea =
      area(((triangle *)right)->a, ((triangle *)right)->b,
           ((triangle *)right)->c);

  if (leftArea > rightArea)
    return 1;
  if (leftArea < rightArea)
    return -1;
  return 0;
}

void sort_by_area(triangle* tr, int n) {
    qsort(tr, n, sizeof(triangle), compareTringle);
}

int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
First test:
    Input:
        3
        7 24 25
        5 12 13
        3 4 5
    Output:
        3 4 5
        5 12 13
        7 24 25

通过了

Second case: https://pastebin.com/DFBGz2KD

怎么了?

2 个答案:

答案 0 :(得分:4)

这没有做你想要的:

a = (double) a;
b = (double) b;
c = (double) c;

问题在于变量abc仍然是整数。因此,您要将它们转换为两倍,然后将它们隐式转换回整数,并以整数形式存储回去。然后以下内容将不起作用:

double p = (a + b + c) / 2;

由于a + b + c是整数,所以除法是整数除法。

您可以通过以下方式解决此问题:

double da = a;
double db = b;
double dc = c;

,然后使用dadbdc代替abc

但是,如果您希望让编译器为您执行类型提升,则可以省去分配,而只需将分配从p更改为:

double p = (a + b + c) / 2.0;

这会将abc作为整数相加,然后将结果转换为double,因为它现在被一个双常量{{1}除以}。

这两种方法都可以。

答案 1 :(得分:2)

汤姆给了您一个很好的答案,可以解决整数提升问题,但是有很多问题只是邀请未定义行为而您可以解决。 >

首先,您必须始终验证所有输入。否则,您不知道scanf是否发生了 matching input 失败,并且您盲目地使用了在两种情况下均不确定的值失败。只需验证scanf的返回值,例如

    if (scanf("%d", &n) != 1) { /* validate every input */
        fputs ("error: invalid formate - 'n'.\n", stderr);
        return 1;
    }
    ...
    for (int i = 0; i < n; i++)
        if (scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c) != 3) {
            fputs ("error: invalid format - a,b,c.\n", stderr);
            return 1;
        }

出于完全相同的原因,您必须验证个分配(无论使用malloc, calloc还是realloc)。这不是"if"的问题,分配将失败,这是"when"的问题。由于分配失败设置了errno,因此您的错误报告是对perror的一次小小的调用,例如

    triangle *tr;
    ...
    if (!(tr = malloc (n * sizeof *tr))) {  /* validate every allocation */
        perror ("malloc-tr");
        return 1;
    }

在C中,当您声明一个函数并将括号为空()时,您已指定该函数采用 unspecified 个参数,而不是零。为了使您声明main()符合,您应该使用:

int main (void) {

请参阅:C11 Standard - §5.1.2.2.1 Program startup(p1)

area中不需要任何类型转换,只需在'.'之后添加2来解决整数除法问题,然后让默认促销处理其余部分,例如< / p>

double area (int a, int b, int c)   /* remove all casts, add '.' after 2 */
{
    double p = (a + b + c) / 2.;
    return sqrt (p*(p-a)*(p-b)*(p-c));
}

尽管您可以自由地分别声明structtypedef,但是也可以在单个声明中进行声明,例如

typedef struct {    /* you can simply create the typedef */
    int a, b, c;
} triangle;

修复整数除法问题后,您的代码将正常运行,但您应修复其他问题,以确保不会因可预见的分配输入而遇到未定义行为错误。固定整数除法后,针对您的测试输入运行将导致:

使用/输出示例

$ ./bin/triangle_sort_area < dat/triangles_20.txt
22 18 5
31 41 14
20 23 21
54 62 11
26 41 65
58 31 31
20 39 32
26 41 62
44 48 18
23 37 47
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50