Не работает мой код, посвященный сортировке - PullRequest
1 голос
/ 09 июня 2019

У меня есть код и несколько тестов.Первый случай пройден, второй потерпел неудачу.Я не понимаю, в чем проблема.

Проблема: Вам дано 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 ]

4 голосов
/ 09 июня 2019

Это не делает то, что вы хотите:

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

Проблема в том, что переменные a, b и c все еще являются целыми числами.Таким образом, вы конвертируете их в удвоенные значения, затем они неявно преобразуются обратно в целые числа и сохраняются в виде целых чисел.Тогда следующее не работает:

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

, поскольку a + b + c является целым числом, поэтому деление является целочисленным делением.

Вы можете исправить это, выполнив:

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

, а затем с помощью da, db, dc вместо a, b, c.

Но если вы предпочитаете, чтобы компилятор выполнилнабрав для вас рекламные акции, вы можете избавиться от назначений и вместо этого просто изменить назначение на p на:

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

Это добавит a, b и c в виде целых чисел, затем преобразуйте результат в double, так как теперь он делится на двойную константу, 2.0.

В любом случае будет работать.

2 голосов
/ 09 июня 2019

Том дал вам хороший ответ, чтобы решить вашу проблему целочисленного продвижения, но есть ряд проблем, которые просто приглашают Неопределенное поведение и ряд других гнид, которые вы можете очистить.

Во-первых, вы должны всегда проверять ВСЕ ввод. В противном случае вы не сможете понять, произошел ли сбой , соответствующий или input , с scanf, и вы слепо используете значения, которые будут неопределенными в случае любого сбоя. Просто подтвердите возвращение 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, когда вы объявляете функцию и оставляете круглые скобки пустыми (), вы указали, что функция принимает неопределенное количество аргументов, а не ноль. Чтобы сделать заявление о соответствии main(), вы должны использовать:

int main (void) {

См .: C11 Standard - §5.1.2.2.1 Запуск программы (p1)

В area нет необходимости ни в одном из ваших приведений, просто решите проблему целочисленного деления, добавив '.' после 2 и позвольте промоушенам по умолчанию обрабатывать все остальное, например,

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));
}

Хотя вы можете декларировать struct и typedef отдельно, вы можете сделать это и в одной декларации, например,

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

После того, как вы исправите проблему с целочисленным делением, ваш код будет работать нормально, но вы должны исправить другие проблемы, чтобы убедиться, что вы не столкнетесь с Undefined Behavior из-за предсказуемого ввода ошибки распределения , С фиксированным целочисленным делением работа с тестовым вводом приведет к:

Пример использования / Вывод

$ ./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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...