I have to write a program that uses the qsort function to sort a vector
of points in the Cartesian plane. Each point is formed by a pair of
coordinates (x, y).
Points must be sorted by ascending x-axis. With the same x-axis,
y-axis is ordered by descending.
This is a sample input:
5 (Struct numbers)
2 5
12 2
2 7
3 4
2 2
With the output:
2 7
2 5
2 2
3 4
12 2
Now, this is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct x_y
{
int x;
int y;
}coordinates;
typedef coordinates *coordinatesList;
int compare(const void *a, const void *b)
{
coordinates *a1 = (coordinates *)a;
coordinates *b1 = (coordinates *)b;
if (a1->x > b1->x)
return 1;
else if (a1->x < b1->x)
return (-1);
else if (a1->x == b1->x)
{
if (a1->y < b1->y)
return 1;
else if (a1->y > b1->y)
return (-1);
else
return 0;
}
}
int main()
{
int n, i;
scanf("%d", &n);
coordinatesList *A = (coordinatesList*)malloc(n * sizeof(coordinates));
for (i = 0; i < n; i++)
{
A[i] = (coordinatesList)malloc(sizeof(coordinates));
scanf("%d%d", &A[i]->x, &A[i]->y);
}
qsort(A, n, sizeof(coordinates*), compare);
for (i = 0; i < n; i++)
printf("%d %d\n", A[i]->x, A[i]->y);
return 0;
}
whith his wrong output:
2 7
3 4
2 2
2 5
12 2
If I try to separate the structs by element:
int compare(const void *a, const void *b)
{
coordinates *a1 = (coordinates *)a;
coordinates *b1 = (coordinates *)b;
int a_x = a1->x;
int a_y = a1->y;
int b_x = b1->x;
int b_y = b1->y;
if (a_x > b_x)
return 1;
else if (a_x < b_x)
return (-1);
else if (a_x == b_x)
{
if (a_y < b_y)
return 1;
else if (a_y > b_y)
return (-1);
else
return 0;
}
}
...gives me a different wrong output:
2 2
12 2
2 7
3 4
2 5
The compare function gets pointers to the elements to be sorted, so here it gets pointers to coordinates pointers. The correct beginning is:
int compare(const void *a, const void *b)
{
const coordinates *a1 = *(const coordinates **)a;
const coordinates *b1 = *(const coordinates **)b;
I added const because you shouldn't cast away const-ness, even if it doesn't matter here. You would notice if you used warnings with the compilation.
You should also use sizeof(coordinates) in the call to qsort, not sizeof(coordinates*), because otherwise the sort function can't know how big your elements are, but these two probably have the same value here.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
In this declaration
coordinatesList *A = (coordinatesList*)malloc(n * sizeof(coordinates));
you have to use expression sizeof( coordinatesList ) instead of the expressions sizeof( coordinates ).
In the function compare you have to write
int compare(const void *a, const void *b)
{
const coordinatesList a1 = *( const coordinatesList *)a;
const coordinatesList b1 = *( const coordinatesList *)b;
//...
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
typedef struct x_y
{
int x;
int y;
} coordinates;
typedef coordinates *coordinatesList;
int compare( const void *a, const void *b )
{
const coordinatesList a1 = *( const coordinatesList * )a;
const coordinatesList b1 = *( const coordinatesList * )b;
if ( a1->x < b1->x )
{
return -1;
}
else if ( b1->x < a1->x )
{
return 1;
}
else
{
if ( a1->y < b1-> y )
{
return 1;
}
else if ( b1->y < a1->y )
{
return -1;
}
else
{
return 0;
}
}
}
int main(void)
{
const size_t N = 5;
coordinatesList *A = malloc( N * sizeof( coordinatesList ) );
for ( size_t i = 0; i < N; i++ )
{
A[i] = malloc( sizeof( coordinates ) );
}
A[0]->x = 2; A[0]->y = 5;
A[1]->x = 12; A[1]->y = 2;
A[2]->x = 2; A[2]->y = 7;
A[3]->x = 3; A[3]->y = 4;
A[4]->x = 2; A[4]->y = 2;
for ( size_t i = 0; i < N; i++ )
{
printf( "%d\t%d\n", A[i]->x, A[i]->y );
}
putchar( '\n' );
qsort( A, N, sizeof( coordinatesList ), compare );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d\t%d\n", A[i]->x, A[i]->y );
}
putchar( '\n' );
return 0;
}
Its output is
2 5
12 2
2 7
3 4
2 2
2 7
2 5
2 2
3 4
12 2
Related
I am trying to sort an array of structs using qsort, but it's not properly sorting the content.
The structure node consists of the starting vertex, the ending vertex, and the cost of reaching from vertex 'a' to vertex 'b'.
I am writing the code for Kruskal's algorithm
#include <stdio.h>
#include <stdlib.h>
int v, e;
typedef struct node {
int a;
int b;
int cost;
} node;
int compare(const void *a, const void *b) {
const node *x = *(node **)a;
const node *y = *(node **)b;
return (x->cost > y->cost) ? 1 : 0;
}
int main() {
scanf("%d %d", &v, &e);
int i;
node *arr[e];
for (i = 0; i < e; i++) {
int a, b, cost;
scanf("%d %d %d", &a, &b, &cost);
arr[i] = (node *)malloc(sizeof(node));
arr[i]->a = a;
arr[i]->b = b;
arr[i]->cost = cost;
}
qsort(arr, e, sizeof(node *), compare);
printf("\n\n");
for (int i = 0; i < e; i++) {
printf("%d %d %d\n", arr[i]->a, arr[i]->b, arr[i]->cost);
}
return 0;
}
Input:
9 14
2 5 4
7 8 7
0 1 4
1 7 11
0 7 8
7 6 1
6 5 2
5 4 10
3 5 14
3 4 9
2 3 7
1 2 8
2 8 2
8 6 6
Output:
2 5 4
2 8 2
0 1 4
8 6 6
6 5 2
7 6 1
7 8 7
2 3 7
1 2 8
0 7 8
3 4 9
5 4 10
1 7 11
3 5 14
The first few rows are not sorted properly as per the output. Please help me out.
The comparison function must return one of the following values, negative, zero or positive value, depending on whether the first compared elements is greater than, equal to or less than the second compared element for the descending sorting.
So this function definition
int compare(const void* a,const void* b){
const node* x = *(node**)a;
const node* y = *(node**)b;
return (x->cost > y->cost)?1:0;
}
is incorrect.
Instead you could write the following way (provided that you are going to sort the array in the descending order
int compare(const void* a,const void* b){
const node* x = *(node**)a;
const node* y = *(node**)b;
return ( x->cost < y->cost ) - ( y->cost < x->cost );
}
If you want to sort the array in the ascending order then the comparison function can look like
int compare(const void* a,const void* b){
const node* x = *(node**)a;
const node* y = *(node**)b;
return ( y->cost < x->cost ) - ( x->cost < y->cost );
}
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int a;
int b;
int cost;
}node;
int ascending(const void* a,const void* b){
const node* x = *(node**)a;
const node* y = *(node**)b;
return ( y->cost < x->cost ) - ( x->cost < y->cost );
}
int descending(const void* a,const void* b){
const node* x = *(node**)a;
const node* y = *(node**)b;
return ( x->cost < y->cost ) - ( y->cost < x->cost );
}
int main(void)
{
node * arr[] =
{
malloc( sizeof( node ) ), malloc( sizeof( node ) ), malloc( sizeof( node ) )
};
const size_t N = sizeof( arr ) / sizeof( *arr );
arr[0]->a = 2;
arr[0]->b = 5;
arr[0]->cost = 4;
arr[1]->a = 7;
arr[1]->b = 8;
arr[1]->cost = 7;
arr[2]->a = 0;
arr[2]->b = 1;
arr[2]->cost = 4;
for ( size_t i = 0; i < N; i++ )
{
printf( "%d %d %d\n", arr[i]->a, arr[i]->b, arr[i]->cost );
}
putchar( '\n' );
qsort( arr, N, sizeof( *arr ), ascending );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d %d %d\n", arr[i]->a, arr[i]->b, arr[i]->cost );
}
putchar( '\n' );
qsort( arr, N, sizeof( *arr ), descending );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d %d %d\n", arr[i]->a, arr[i]->b, arr[i]->cost );
}
putchar( '\n' );
for ( size_t i = 0; i < N; i++ )
{
free( arr[i] );
}
}
The program output is
2 5 4
7 8 7
0 1 4
2 5 4
0 1 4
7 8 7
7 8 7
2 5 4
0 1 4
I have to use the recursive selection sort in order to order different arrays of integers.
These arrays are respectively formed by 100, 1000, 10000, 100000, 200000, 500000 items and can be formed by ordered numbers, partially ordered numbers, inverted ordered numbers and random numbers.
After that I have to calculate the time the algorithm took to order the array.
I have to use recursion, It's a homework.
I created a function that generates the array:
typedef enum {ORINATO, INVERS, PARZ_ORDINATO, RANDOM} Ordine;
int *generaArray(int dimensione, Ordine ordine) {
int i, j, n;
int *array = (int*)malloc(dimensione * sizeof(int));
if (!array){
return NULL;
}
switch (ordine){
case ORINATO:
for (i = 0; i < dimensione; i++){
array[i] = i;
} break;
case INVERS:
n =0;
for ( i = dimensione-1; i >= 0 ; i--) {
array[i] = n;
n++;
}break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione/2 ; i++) {
array[i] = i;
}
for (j = i+1; j <dimensione; j++){
n = rand();
array[j] = n;
};break;
case RANDOM:
for ( i = 0; i <= dimensione ; i++) {
array[i] = rand();
}break;
default:
break;
}
return array;
}
And it works like wonders.
Then I have created the recursive selection sort like follows:
void recursiveSelectionSort(int *array, int dim, int start){
int min=0;
if (start >= dim-1){
return;
}
min = findMin(array, start, start+1, dim);
swap(&array[min], &array[start]);
recursiveSelectionSort(array, dim, start+1);
}
int findMin(int *array, int min, int start, int dim){
if(start == dim ){
return min;
}
if (array[start]< array[min]){
min = start;
}
return findMin(array, min, start+1, dim);
}
void swap (int* x, int *y){
int temp = *x;
x = *y;
y = *temp;
}
Now, this as well should work but something clearly isn't. Let's make an example with the implementation, this is what i put in my main:
int main() {
int *array;
clock_t start, end;
double t;
array = generaArray(1000, ORINATO);
start = clock();
recursiveSelectionSort(array, 1000, 0);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("\nIl tempo impiegato per 1000 elementi รจ: %lf secondi", t);
return 0;
}
This works (but it's slower thank it should be). However if you try and change the dimension from 1000 to 200000 or 500000 it shows error 11.
What is it causing it? I tried everything but it doesn't seem to work.
For starters recursive functions called for large arrays can invoke a stack overflow.
So use non-recursive functions that implement the method selection sort for large arrays.
As for your implementation then for example the function swap has typos.
void swap (int* x, int *y){
int temp = *x;
x = *y;
y = *temp;
}
I think you mean
void swap (int* x, int *y){
int temp = *x;
*x = *y;
*y = temp;
}
All other functions have too many parameters.
For example the function findMin can be declared the following way
size_t findMin( const int *a, size_t n );
and can be also defined as a recursive function (if you decided to write recursive functions then this function can be also recursive)
Here is a demonstrative program that shows how the functions can be defined
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap( int *x, int *y )
{
int temp = *x;
*x = *y;
*y = temp;
}
size_t findMin( const int a[], size_t n )
{
if ( n < 2 )
{
return 0;
}
else
{
size_t i = findMin( a + 1, n - 1 ) + 1;
return a[i] < a[0] ? i : 0;
}
}
void recursiveSelectionSort( int a[], size_t n )
{
if ( !( n < 2 ) )
{
size_t i = findMin( a + 1, n - 1 ) + 1;
if ( a[i] < a[0] ) swap( &a[0], &a[i] );
recursiveSelectionSort( a + 1, n - 1 );
}
}
int main(void)
{
enum { N = 15 };
int a[N];
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < N; i++ )
{
a[i] = rand() % N;
}
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
recursiveSelectionSort( a, N );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
return 0;
}
The program output might look like
11 9 3 5 6 8 2 4 5 3 7 9 2 0 14
0 2 2 3 3 4 5 5 6 7 8 9 9 11 14
In a block of memory, treatead as two segments, A and B,
i set up pointers in segment A such that values from
segment B can be viewed as matrices and accessed by indices:
float **matrix = ( ( void ** ) view->data[ i ] )[ j ];
After allocating memory and assigning the pointers i then set all the
values for a specific matrix.
However, when trying to print individual values of that matrix,
the program seg-faults due to an invalid read.
If i dont't call the set_weights function, values are printed
fine ( and valgrind reports no leaks ). So i assume that trying
to set values has an unwanted side effect of messing up pointers.
I would like to understand if the error is in the pointer assignments
or on access.
Pease have a look and help me.
Regards,
Alfred
[ OS: x86_64 debian linux, gcc 4.2.9 ]
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
enum { Weight, Delta, Max };
typedef struct {
void **data;
} View;
void matrix_2D_print( int x, int y, float **values ) {
int i, j;
for( i = 0; i < x; ++i ) {
for( j = 0; j < y; ++j ) {
printf( "\t\t%f", values[ i ][ j ] ); // Invalid read
if( j < ( y - 1 ) ) {
printf( ", " );
}
}
printf( "\n" );
}
}
void set_weights( int layers, int x, int y, View *view ) {
int i, j, l;
void **view_ptr = view->data[ Weight ];
for( l = 0; l < layers; ++l ) {
float **m2_data = view_ptr[ l ];
for( i = 0; i < x; ++i ) {
for( j = 0; j < y; ++j ) {
m2_data[ i ][ j ] = 0.27f;
}
}
}
}
int main( int argc, char **argv ) {
int i, l, m;
int x = 3;
int y = 2;
int layers = 2;
size_t step_view = Max * sizeof( void ** );
size_t len_step_view = x * sizeof( void ** );
size_t len_segment_A = step_view + x * layers * Max * sizeof( void ** );
size_t len_segment_B = x * y * layers * Max * sizeof( float );
char *storage = calloc( 1, len_segment_A + len_segment_B );
float *segment_b = ( float * )( storage + len_segment_A );
View view;
view.data = ( void ** ) storage;
for( m = 0; m < Max; ++m ) {
void **segment_a = ( void ** )( storage + step_view );
view.data[ m ] = segment_a;
for( l = 0; l < layers; ++l ) {
segment_a[ l ] = segment_b;
void **cur = segment_a[ l ];
for( i = 0; i < x; ++i ) {
cur[ i ] = segment_b;
segment_b += y;
}
step_view += len_step_view;
}
}
assert( len_segment_A == step_view );
set_weights( layers, x, y, &view );
void **view_ptr = view.data[ Weight ];
printf( "\tLayer: %d\n", 0 );
matrix_2D_print( x, y, view_ptr[ 0 ] );
free( storage );
return 0;
}
I'm trying to write a sorting function with just recursion. I keep getting the error:
lvalue required as unary '&' operand
This are the functions I'm using:
void sorter_rec (int a[], int n) {
if (n ==1 ) return;
else {
swap( &(maximumrec(a,n)), &a[n-1]);
sorter_rec(a,n-1);
return;
};
}
The error is in sorter_rec.
void swap(int *px, int *py)
{ int z = *px;
*px = *py;
*py = z;
return;
}
int maximumrec(int ar[], int n)
{
if (n == 1) {
return ar[0];
} else {
int max = maximumrec(ar, n-1);
return ar[n-1] > max ? ar[n-1] : max;
}
}
How can I solve this?
You may not apply the operator & to the temporary object returned by the function maximumrec.
Also if you are using the selection sort starting from the end of array then the maximum element should be also searched starting from the end of array. In this case the sorting algorithm will be more stable.
Here is a demonstrative program that uses your approach but instead of the searching maximum element it searches minimum element. You can rewrite it such a way that it would search the maximum element if you want.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define N 20
int * min_element( int a[], size_t n )
{
int *min = a;
if ( !( n < 2 ) )
{
min = min_element( a + 1, n - 1 );
min = *min < *a ? min : a;
}
return min;
}
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void sort( int a[], size_t n )
{
if ( !( n < 2 ) )
{
int *min = min_element( a, n );
if ( min != a ) swap( a, min );
sort( a + 1, n - 1 );
}
}
int main(void)
{
int a[N];
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < N; i++ ) a[i] = rand() % N;
for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
printf( "\n" );
sort( a, N );
for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
printf( "\n" );
return 0;
}
The program output might look like
17 9 12 15 1 17 19 17 6 2 14 19 2 8 5 19 0 12 16 8
0 1 2 2 5 6 8 8 9 12 12 14 15 16 17 17 17 19 19 19
Your basic algorithm works. All I had to do was fix up the way you passed pointers around, and it worked the first time! Hope this helps. I changed some names to fit my own style a bit, and added some convenience things (macro and logging method), and main() so I could test it.
Note that the name of an array is the same as &array[0]
#include <stdio.h>
#define INT_COUNT(n) (sizeof(n) / sizeof(int))
void dumpIntArray(int *array, int n) {
printf("{ ");
for (int i = 0; i < n; i++) {
printf("%d ", array[i]);
}
printf(" }\n");
}
void swap(int *px, int *py) {
int z = *px;
*px = *py;
*py = z;
return;
}
int *ptrToMax(int *sortable, int n) {
if (n == 1) {
return sortable;
} else {
int *maximum = ptrToMax(sortable, n - 1);
return sortable[n - 1] > *maximum ? &sortable[n - 1] : maximum;
}
}
void quicksort(int *sortable, int n) {
if (n == 1 ) {
return;
} else {
swap(ptrToMax(sortable, n), &sortable[n - 1]);
quicksort(sortable, n - 1);
return;
}
}
int main(int argc, char **argv) {
int foo[] = { 1, 5, 3, 2, 4, 9, 10, 8, 7 };
printf("Before:\n");
dumpIntArray(foo, INT_COUNT(foo));
quicksort(foo, INT_COUNT(foo));
printf("After:\n");
dumpIntArray(foo, INT_COUNT(foo));
}
I have a stucture containing two arrays: the row- and the column-index of a matrix. These indices are not order and I would like to sort them using qsort.
What I do not want to use
I am aware that this is easy if I have an array of structures. The could then looks as follows
// structure to store the row/column index
typedef struct Index {
int row;
int col;
} Index;
// function to compare two entries
int cmp(const void *a, const void *b){
Index *Ia = (Index *) a;
Index *Ib = (Index *) b;
if(Ia->row < Ib->row ) return -1;
if(Ia->row == Ib->row && Ia->col < Ib->col) return -1;
if(Ia->row == Ib->row && Ia->col == Ib->col) return 0;
if(Ia->row == Ib->row && Ia->col > Ib->col) return 1;
if(Ia->row > Ib->row ) return 1;
}
// main program
int main(void) {
int N = 3;
Index mat[N];
// fill the matrix with fictitious data
mat[0].row = 1; mat[0].col = 3;
mat[1].row = 0; mat[0].col = 2;
mat[2].row = 0; mat[0].col = 1;
// sort the "matrix": first ascending rows, then ascending columns
qsort(mat,N,sizeof(Index),cmp);
return 0;
}
What I do want to use
My program is constructed such that I do not have an array of structures, but I have a structure of arrays:
// define structure
typedef struct Matrix {
int* row;
int* col;
} Matrix;
// main program
int main(void) {
// define fictitious data
int row[3] = { 1 , 1 , 0 };
int col[3] = { 3 , 2 , 1 };
// define matrix
Sparse mat;
mat.row = row;
mat.col = col;
// sort
// ...?
return 0;
}
I want to sort the row/column index such as above. So far I copied the data to an array of structures, sorted, and copied back. However, the data-set I am using is so large that I want to avoid this.
Thanks!
Not an answer but a comment on the way you are using the compare() function in qsort(). It would be more efficient like this.
int cmp(const void *a, const void *b){
Index *Ia = (Index *) a;
Index *Ib = (Index *) b;
if(Ia->row < Ib->row) return -1;
if(Ia->row > Ib->row) return 1;
if(Ia->col < Ib->col) return -1;
if(Ia->col > Ib->col) return 1;
return 0;
}
If you don't want to use additional memory then you should write your qsort like below (I made only short tests):
Original source of qsort: http://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Quicksort
#include <stdio.h>
typedef struct Matrix {
int* row;
int* col;
} Matrix;
int cmp(Matrix* m, int a, int b)
{
if( m->row[a] != m->row[b] )
return m->row[a] - m->row[b];
return m->col[a] - m->col[b];
}
void swap(Matrix *m, int l, int r)
{
int tmp;
tmp = m->row[l];
m->row[l] = m->row[r];
m->row[r] = tmp;
tmp = m->col[l];
m->col[l] = m->col[r];
m->col[r] = tmp;
}
void sort(Matrix* tab, int begin, int end)
{
if (end > begin) {
int pivot = begin;
int l = begin;
int r = end;
while(l < r) {
if (cmp(tab, l, pivot) <= 0) {
++l;
} else if ( cmp(tab, r, pivot) > 0 ) {
--r;
} else if ( l < r ) {
swap(tab, l, r);
}
}
--l;
swap(tab, begin, l);
sort(tab, begin, l);
sort(tab, r, end);
}
}
int main(void) {
const int N = 3;
Matrix matrix;
int row[N] = { 1 , 1 , 0 };
int col[N] = { 3 , 2 , 1 };
matrix.row = row;
matrix.col = col;
sort( &matrix, 0, N );
for(int i = 0; i < N; ++i)
printf("%d %d\n", matrix.row[i], matrix.col[i]);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct Matrix {
int* row;
int* col;
} Matrix;
Matrix *mat_cmp;//see from the comparison function
int cmp(const void *a, const void *b){
int ia = *(int *)a;
int ib = *(int *)b;
int ra = mat_cmp->row[ia];
int rb = mat_cmp->row[ib];
if(ra == rb){
int ca = mat_cmp->col[ia];
int cb = mat_cmp->col[ib];
return (ca > cb) - (ca < cb);
} else
return (ra > rb) - (ra < rb);
}
#define N 3
int main(void) {
int row[N] = { 1 , 1 , 0 };
int col[N] = { 3 , 2 , 1 };
int i, index[N];
Matrix mat = { .row=row, .col=col};
for(i=0; i<N; ++i)
index[i] = i;//set index(0..N-1)
mat_cmp = &mat;
qsort(index, N, sizeof(*index), cmp);
for(i=0;i<N;i++){
printf("%d,%d\n", mat.row[index[i]], mat.col[index[i]]);
}
return 0;
}