Search code examples
cpointersstructswapbubble-sort

Swapping two structs from an array of structs (bubblesort)


I have a struct which holds 3 integers each resembling the size of one side of a triangle:

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

I firstly need to read the number of triangles to come (n). Then I read 3 sides of n triangles and sort them by the area of triangles in order from smallest to largest.

Now my idea was to compare the areas with each other and if the former area is larger than the later, I swap the corresponding structures. In the end, the values of structs (sides) will be printed out as an output from smallest to largest.

I am stuck with swapping the structures. So far I have done this:

void swap(tri *a, tri *b)
{
    tri t;
    t = *a;
    *a = *b;
    *b = t;
}

void sort_by_area(tri *tr, int n)
{
    int sorted, storage[n];

    for(int i = 0; i <= n-1; i++)
    {
        storage[i] = give_area(&tr[i]);
    }

    do
    {
        sorted = 1;
        for(int i = 0; i < n-1; i++)
        {
            if(storage[i] > storage[i+1])
            {
                /*swap(tr[i].a, tr[i+1].a);
                swap(tr[i]->b, tr[i+1]->b);  
                swap(tr[i]->c, tr[i+1]->c);*/
              /*the commented section was my another attempt in which I would change the swap inputs to swap(int a, int b) or swap(int *a, int *b)*/

                swap(&tr[i], &tr[i+1]);
                sorted = 0;

            }
        }
    }while(!sorted);
}

I'm sure I'm definitely completely wrong with putting the structs in.

If one needs more, here is my main function:

int main()
{
    int n;
    scanf("%d\n", &n);
    tri *tr = malloc(n*(sizeof(tri)));

    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("\n%d %d %d", tr[i].a, tr[i].b, tr[i].c);
    }
    free(tr);
return 0;
}

From my investigation the code works properly, I think the main issue lies either within the swap function, or the nested (for/if) loop in which the swap function is run.


Solution

  • The swap method is fine. There is a logical error in your approach though.

    You compare the storage (the areas), and if the comparison is true, you swap the triangles, but not the areas. As a result, the i-th triangle does not correspond anymore to the i-th storage necessarily.

    You need to swap the areas too, when their respective triangles are swapped, like this:

    (I used double to store the areas, but you could still use int for it, by losing in precision)

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    struct triangle{
        int a; int b; int c;
    };
    typedef struct triangle tri;
    
    void swap(tri *a, tri *b)
    {
        tri t;
        t = *a;
        *a = *b;
        *b = t;
    }
    
    void swap_double(double *a, double *b)
    {
        double tmp = *a;
        *a = *b;
        *b = tmp;
    }
    
    // Heron's formula
    double give_area(struct triangle *tr)
    {
      double t = (tr->a + tr->b + tr->c)/2.0; /* Compute half of the perimeter */
      return sqrt(t * (t - tr->a) * (t - tr->b) * (t - tr->c)); /* Return area */
    }
    
    void sort_by_area(tri *tr, int n)
    {
        int sorted;
        double storage[n];
    
        for(int i = 0; i <= n-1; i++)
        {
            storage[i] = give_area(&tr[i]);
        }
    
        do
        {
            sorted = 1;
            for(int i = 0; i < n-1; i++)
            {
                if(storage[i] > storage[i+1])
                {
                    swap(&tr[i], &tr[i+1]);
                    // Swap the areas too!!!
                    swap_double(&storage[i], &storage[i + 1]);
                    sorted = 0;
    
                }
            }
        }while(!sorted);
    }
    
    int main(void)
    {
        int n;
        scanf("%d\n", &n);
        tri *tr = malloc(n*(sizeof(tri)));
    
        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("\n%d %d %d", tr[i].a, tr[i].b, tr[i].c);
        }
        free(tr);
        return 0;
    }
    

    Compile like this:

    gcc main.c -Wall -Wextra -lm
    ./a.out
    

    Input:

    2
    7 8 9
    4 5 6
    

    Output:

    4 5 6
    7 8 9
    

    Debug-Tip: As @alk mentioned, when you are uncertain about the correctness of a specific method, write a laconic program to test that method (a minimal complete verified example (MCVE), as we tend to say here in Stack Overflow).