Optimizing a 'sorting code' in C - c

I am working on a code I want to optimize. The code is all about sorting a double array by ascending order of its second .
The first input is an integer N, and the second is a 2D array of size N*2 (call it c), then we sort the array by ascending order of c[.][1], and when there are equal elements, say if c[i][1]==c[j][1], for two integers i and j, we sort those elements by ascending of the elements of the first columns, so c[i][1] is below c[j][1] if c[i][1]<c[j][1]. Let's take an example :
input
3
2 3
1 3
4 2
output
4 2
1 3
2 3
The fact is that the code needs to run in less than 0.5s and mine is really too slow. Here it is
#include <stdio.h>
#include <stdlib.h>
//determining the index of the max elments in an array
int max(int i, int N, int **c)
{
int j=0;
int M=0;
for(j=0;j<i;j++)
{if(c[j][1]>c[M][1]){M=j;}else{}}
return M;
}
int main ()
{
//integers used for the loops
int i;
int j;
//the size of the 2D array is N*2
int N;
scanf("%d",&N);
int **c;
int mx;
int maxi;
//this array is the output, thath is the 2D array sorted
int e[N][2];
//2D array we want to sort
c = malloc(N*sizeof(int*));
for (i=0;i<N;i++)
{
c[i] = malloc(2*sizeof(int));
for (j=0;j<2;j++)
{
scanf("%d",&c[i][j]);
}
}
//at the first step, we have initialized the value of the max
maxi=max(N,N,c);
for(i=0;i<N;i++)
{
//we sort the c[.][1], and we take the max (called 'mx') of the array. At each step of the loop, we throw away the max from the array c[.][1] (we mean the max found at the precedent step of the loop)
mx=max(N-i,N,c);
//Here, we look at the multiple occurence of the max, if there are, we sort the c[.][0] for which c[.][1]=c[mx][1] by ascending order
if(maxi==mx){int k;
for(k=0;k <N;k++){if(c[k][1]==c[mx][1]){if(c[k][0]>c[mx][0]){mx=k;}}else{}}
}else{}
//we keep the value of the max in order to verify that the same value of the max has another occurence in following steps
maxi=mx;
//e is the double array for the output
e[i][0]=c[mx][0];
e[i][1]=c[mx][1];
int j;
//here we throw away the max from the array
for(j=mx;j< N-i-1;j++){c[j][1]=c[j+1][1];c[j][0]=c[j+1][0];}
}
for(i=0;i<N;i++)
{printf("%d %d",e[N-1-i][0],e[N-1-i][1]);
printf("\n");}
}
Could anyone help ?

Your code has way too high computational complexity. Also, int e[N][2] only works under GCC extension since N is a variable determined at run time instead of compile time.
An easy (in terms of coding) way to improve it is utilizing qsort() in C standard library.
struct IntPair
{
int n[2];
};
int compareIntPair(const void* lhs, const void* rhs)
{
const struct IntPair *l = (const struct IntPair*)lhs;
const struct IntPair *r = (const struct IntPair*)rhs;
if(l->n[1] < r->n[1])
return -1;
if(l->n[1] > r->n[1])
return 1;
if(l->n[0] < r->n[0])
return -1;
if(l->n[0] > r->n[0])
return 1;
return 0;
}
int main(void)
{
//integers used for the loops
int i;
//the size of the 2D array is N*2
int N;
struct IntPair* c;
scanf("%d",&N);
c = (struct IntPair*)calloc(N, sizeof(struct IntPair));
for(i = 0; i < N; ++i)
{
scanf("%d%d", &c[i].n[0], &c[i].n[1]);
}
qsort(c, N, sizeof(struct IntPair), compareIntPair);
for(i = 0; i < N; ++i)
printf("%d %d\n", c[i].n[0], c[i].n[1]);
free(c);
return 0;
}
Edit: to answer the question in comment "could each element of the N-dynamic allocation points to 1D array of size 2?"
int compareElem(const void* lhs, const void* rhs)
{
const int *l = *(const int**)lhs;
const int *r = *(const int**)rhs;
if(l[1] < r[1])
return -1;
if(l[1] > r[1])
return 1;
if(l[0] < r[0])
return -1;
if(l[0] > r[0])
return 1;
return 0;
}
int main(void)
{
//integers used for the loops
int i;
//the size of the 2D array is N*2
int N;
int ** c;
scanf("%d",&N);
c = (int**)calloc(N, sizeof(int*));
for(i = 0; i < N; ++i)
{
c[i] = (int*)calloc(2, sizeof(int));
scanf("%d%d", &c[i][0], &c[i][1]);
}
qsort(c, N, sizeof(int*), compareElem);
for(i = 0; i < N; ++i)
{
printf("%d %d\n", c[i][0], c[i][1]);
free(c[i]);
}
free(c);
return 0;
}

Related

Can somone please explain this to me

For n=3 and a={1,2,3},b={4,5,6} its supposed to calculate 1*4+2*5+3*6.
I don't understand why does it work because p is a pointer and p=produs(a,b,n) means that the address of p becomes the value returned by produs.
#include <stdio.h>
#include <conio.h>
void citire(int *x,int *n)
{
for(int i=1; i<=*n; i++)
scanf("%d",&x[i]);
}
int produs(int *a,int*b,int n)
{
int produs=0;
for(int i=1;i<=n;i++)
produs=a[i]*b[i]+produs;
return produs;
}
int main()
{
int n;
int*p;
scanf("%d",&n);
int *a=(int*)malloc(n*sizeof(int));
int *b=(int*)malloc(n*sizeof(int));
citire(a,&n);
citire(b,&n);
p=produs(a,b,n);
printf("%d",p);
return 0;
}
When you do:
size_t size = 10;
int* x = calloc(size, sizeof(int));
You get an array x with 10 items in it, indexed 0..9, not 1..10. Here calloc is used to make it abundantly clear what's being requested instead of doing multiplication that can be mysterious or obtuse.
As such, to iterate:
for (int i = 0; i < size; ++i) {
x[i] ...
}
You have a number of off-by-one errors in your code due to assuming arrays are 1..N and not 0..(N-1).
Putting it all together and cleaning up your code yields:
#include <stdio.h>
#include <stdlib.h>
void citire(int *x, size_t s)
{
for(int i=0; i < s; i++)
scanf("%d", &x[i]);
}
int produs(int *a, int* b, size_t s)
{
int produs = 0;
for(int i = 0; i < s; i++)
produs = a[i] * b[i] + produs;
return produs;
}
int main()
{
int n;
scanf("%d",&n);
int* a = calloc(n, sizeof(int));
int* b = calloc(n, sizeof(int));
citire(a, n);
citire(b, n);
// produs() returns int, not int*
int p = produs(a,b,n);
printf("%d", p);
return 0;
}
You're using pointers in places where pointers don't belong. In C passing a pointer to a single value means "this is mutable", but you don't change those values, so no pointer is necessary nor advised.
Try and use size_t as the "size of thing" type. That's what's used throughout C and it's an unsigned value as negative indexes or array lengths don't make any sense.

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.
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).
The problem with the code is that the auxiliary array storage stays unchanged when structure elements are swapped.
In fact there is no need to have this auxiliary array. Without it you could just write
if( give_area(&tr[i] ) > give_area( &tr[i+1] ) )
Otherwise you have to add one more swap function like
void swap_storage(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
and use it together with the already defined function swap
swap(&tr[i], &tr[i+1]);
swap_storage( &storage[i[, ^storage[i+1[ );

Boubble sorting with arrays with C

#include <stdio.h>
int main(){
void sorting(){
int a[4];
a[0]=1;
a[1]=6;
a[2]=15;
a[3]=3;
a[4]=19;
int size = 4;
int t =1;
if (size ==0) return; // ie if you reach to the end stop
int i;
for (i=0;i<size-1;i++){
if(a[i+1] >a[i]) { //if the +1 element is bigger than before it do the swap
int j;
j= a[i+1];
a[i+1]=a[i]; //swap
a[i] = j; //swap
}
}
sorting(*a,size - 1);//recursion
void print_int() {
int i; // Loop counter
for (i = 0; i < 4; i++) {
printf("%d\n", a[i]);
}}
}
It compiles ok but when I try to run the file nothing appears? My intentions were to create an array sort them then display them.
Also, the code where the recursion happened "sorting(*a,size - 1);//"
if I tried to replace *a with a[] an error will happen. Why is that?
the error is "error expected expression before ']' token"!
thank you.
int a[4];
But you access a[4]=19; index 4 that is out of bound. You can access highest index 3.
I think function void sorting() should be defined outside main .Nested functions are GNU extensions in GCC.
Your code has to many problems. Here is a working Array sort:
#include <stdio.h>
void bubble_sort(int *array, int length){
int i,j, k, temp;
for (i = 0 ; i < length-1; i++){
for (k = 0 ; k < length-i-1; k++){
if (array[k] > array[k+1]){
temp = array[k];
array[k] = array[k+1];
array[k+1] = temp;
}
}
}
printf("The sorted Array List:\n\n");
for ( j = 0 ; j < length ; j++ ){
printf("%d ", array[j]);
}
}
int main(void){
int array[] = {1,6,15,3,19};
int length = sizeof array / sizeof array[0];
bubble_sort(array, length);
printf("\n");
return 0;
}
You should read about functions declarations and definitions.
About arrays you should know that if you declare:
int array[4];
Your working array is from 0 to 3 and not from 0 to 4.
Take a look at the following:
int main(void){
int array[] = {1,6,15,3,19};
int size = 5;
int i;
for(i=0;i<size;i++){
printf("%d ",array[i]);
}
return 0;
}
I have size=5 and not size=4- like you tried. You should be careful about number of Array elements.
Aside from all the problems spotted by others, you must repeatedly execute the for loop until no more exchanges are made, which is the standad way of bubbling. As you use recursion, it is of course nonsense to declare the array to be sorted (and its size) inside the function called recursively.

Recursive function calculating average from int array three by three elements

Calculating average three by three elements and replacing those elements with the average result.
Example array [1,2,7,-2,5,0, 2,8]
After transformation [3,3,3,1,1,1,5,5]
Something is wrong, I can't get it to work.
#include <stdio.h>
int main ( ) {
int n, c[n];
int *avg;
int pom=0;
printf("Enter lenght of array\n");
scanf("%d",&n);
printf("Enter elements");
for(i = 0;i < n; i++)
scanf("%d",c[i]);
avg=Average(c , n, pom);
for(i = 0; i < n; i++)
printf("Avg elements= %d",*(avg+i))
return 0;
}
int Average(int arr[], int size, int z)
{
int k, l, m, Asum;
if (size < 0) {
return arr;
} else {
k=arr[z];
l=arr[z+1];
m=arr[z+2];
Asum=(k + l + m)/3;
arr[z]=Asum;
arr[z+1]=Asum;
arr[z+2]=Asum;
}
return Average(arr,size--,z++);
}
int n, c[n]; is a problem. n is uninitialized so the size of the array is who-knows-what? This is undefined behavior.
Instead
int main(void) {
int n;
int *avg;
int pom=0;
printf("Enter length of array\n");
if (scanf("%d",&n) != 1) return -1;
int c[n];
for(i = 0;i < n; i++)
// scanf("%d",c[i]);
scanf("%d",&c[i]); // pass the address of an `int`
Likely other issues too.
Try simple input first, imagine what happens when you enter only 1 number, what will the Average function do? Don't run the code but try to execute it in your head or with pencil and paper. If you think the program only has to work with three or more numbers, try three.
A serious program would explicitly reject invalid input.

Double pointer to traverse and find 5 max elem in 2D array. C

So am trying to do a question that aims to find 5 max elements in int 2D array.
I had no issues with dynamically allocating the array and inputting the elements into it.
printf("Your 2-d order of choice?\n");
scanf ("%d %d", &i ,&j);
int array[i][j];
//Taking 2d array input
for (int c = 0; c < i; c++)
{
for (int d = 0; d < j; d++)
{
scanf("%d", &array[c][d]);
}
}
However, to find the 5 max elements and store them in an array it asks for a function with prototype.
int * max5(int **, int ,int)
I don’t know how to use double pointer to traverse the 2D array, even though I read a few other posts regarding int**, and what will int* (return type) exactly be and how to incorporate it.
There are the many ways to pass array as pointers
As per you said that if you take array like int array[10][10];.
Using single pointer you can do like
int *arr = max5 ((int *)array, 10, 10);
And traverse array as
int * max5 (int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
//.........
}
OR using double pointer you can also do like
int *arr = max5 ((int **)array, 10, 10);
And traverse like
int * max5 (int **arr, int m, int n)// Same as int * max5 (int *arr[], int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
//.........
}
Now other way also possible it just for your information
From C99, C language supports variable sized arrays to be passed simply by specifying the variable dimensions.
int *arr = max5 (array, 10, 10);
And traverse like
int * max5 (int arr[][10],int m,int n) //Same as int * max5 ( int (*arr)[10], int m,int n))
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", arr[i][j]);
//.........
}
This is the max5 function.
It gets 5 elements in res (allocated by malloc), then for the remaining elements of a, it finds the smallest elements of res and compare it with that a element - if the res element is maller than the a element, that res element is replaced with the a one.
Note that I wouldn't usually use a magic number (5) in the function, but since it's called max5 ..
#include <limits.h>
int *max5(int **a, int rows, int cols) {
int *res = malloc(5 * sizeof(int));
int i,j,k,n=0; // n, number of elements in res
for (i=0 ; i<rows ; i++) {
for (j=0 ; j<cols ; j++) {
if (n < 5) res[n++] = a[i][j];
else {
// find lowest res element
int lowest=0;
for(k=1 ; k<5 ; k++) { // start from 1!
if (res[k] < res[lowest]) {
lowest = k;
}
}
// if lowest res is < a[i][j], replace it
if (res[lowest] < a[i][j]) res[lowest] = a[i][j];
}
}
}
return res;
}
For the sake of demo, this is not optimized (looking for the min all the time). One way would be to sort the res array after 5 elements have been inserted, and after one of its element is replaced (which should statistically happen less and less over the iterations). Another way would be to build a tree when the elements are input initially.
As mentioned by #haccks, array is to be declared as a int **, then i rows must be int * allocated (ie, i pointers to int), then each of the row is to be allocated the size of j int.
With the given prototype, you have to declare array as int ** and dynamically allocate memory to it.
int **array = malloc(i*sizeof(int*));
for(int row = 0; row < i; row++)
array[row] = malloc(j*sizeof(int));
Now you can call your max5 function as
int *a = max5(array, i, j);
Then dynamically allocate an array inside max5 and return it from max5.

Resources