I have a (150x150)2d array of structs that i'd like to sort in a row independent fashion. Because it is a struct, i do not believe (correct me if i'm wrong here) i cannot use qsort() or at least do not know how to due to the fact i'm paring structs and the element i am comparing is a double which goes against the compare prototype requirement of qsort(). At any rate i'd like to apply quicksort on
struct my_struct {
int x;
int y;
double d;
};
void quicksort(struct my_struct* array,int start, int end)
{
struct my_struct key, Pivot;
int i,j,PivotPoint;
if(start< end)
{
PivotPoint = (start+end)/2;
theswap(&array[start], &array[PivotPoint]);
key = array[start];
i= start+1;
j = end;
while (i<=j)
{
while((i<=end) && (array[i].d <= key.d))
++i;
while ((j>=start) && array[j].d> key.d) {
--j;
if (i<j) {
theswap(&array[i], &array[j]);
}
}
}
theswap(&array[start], &array[j]);
quicksort(array, start, j-1);
quicksort(array, j+1, end);
}
}
void theswap(struct my_struct *a, struct TourElement *b)
{
struct my_struct t;
t=*a;
*a=*b;
*b=t;
}
in my main function
i have something
like this:
for (i=0;i<150;++i)
{
for (j=0;j<150;++j)
{
My_array[i][j].x = somethingUseful;
My_Array[i][j].y = somethingEquallyUseful;
My_Array[i][j].d = CalcD(somethingUseful,somethingEquallyUseful);
}
qsort(My_Array[i],150,sizeof(my_struct),compare);
}
int compare(struct my_struct a , struct my_struct b)
{
return a.d -b.d;
}
When i execute quicksort, the application hangs, upon further investigation, there doesn't seem to be any elements in array within the quicksort function. (I added a for loop printf at the beginning of quicksort to itemize the struct's d values and nothing was printed)
Can anyone identify what i am doing wrong here? I'm getting no compile errors. And The "D"s are calculated correctly.
you can use std c qsort
void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) );
the compare function is something like this:
int my_struct_comp(const void *p1, const void *p2){
my_struct *mp1 = (my_Struct*)p1;
my_struct *mp2 = (my_Struct*)p2;
return mp1->d - mp2->d;
}
than you can call qsort (where len is the length of the array)
qsort(myarray, len, sizeof(my_struct), &my_struct_cmp);
Related
I have difficulty applying the pass by reference and pass by value separation in structs.How can I swap the elements of the fixed size struct array as below.
struct try{
int num;
char name[10];
};
int main(){
struct try book[3];
void swapper(/********/);// <-what should be the argument of this function
}
void swapper(/********/){//swap second and third element of struct array
/*how the swap may be done?
temp=book[2];
book[2]=book[3];
temp=book[3];*/
}
There are a lot of ways to do what you're asking. One approach:
#include <stdio.h>
struct try {
int num;
char name[10];
};
void
swapper(struct try *a, int b, int c)
{
struct try tmp = a[b];
a[b] = a[c];
a[c] = tmp;
}
void
display(const struct try *t, size_t count)
{
while( count-- ){
printf("%d: %s\n", t->num, t->name);
t += 1;
}
}
int
main(void) {
struct try book[] = {
{ 1, "foo"},
{ 2, "bar"},
{ 3, "baz"}
};
display(book, sizeof book / sizeof *book);
swapper(book, 1, 2);
display(book, sizeof book / sizeof *book);
return 0;
}
I need a code that sorts an array of structs in ascending order by name or age using the bubblesort algorithm.
I read all the elements and I understand the part of sorting. The problem is that I should only declare one bubblesort algorithm to be able to sort according to name or age. Also when two names or ages are the same then I should compare the elements that are not the same. For this I should use a function pointer. I have just starting using function pointers and I can't see a way out here. A little help would be much appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person {
char name [30];
int age;
};
void bubblesort(struct person *prs, int n)
{
struct person temp;
int i, j , a,b;
for(i=0;i<n; i++)
{
for(j=0; j <n-1; j++)
{
a=strcmp(prs[j].name, prs[j+1].name);
b=prs[j+1].age - prs[j].age;
if(a>0)
{
temp=prs[j];
prs[j]=prs[j+1];
prs[j+1]=temp;
}
else if(a==0 && b<0)
{
temp=prs[j];
prs[j]=prs[j+1];
prs[j+1]=temp;
}
}
}
}
int main()
{
int n, i;
struct person *prs;
scanf("%d", &n);
getchar();
prs=(struct person *)malloc(sizeof(struct person)*n);
for(i=0;i<n;i++)
{
fgets(prs[i].name, 30, stdin);
prs[i].name[strlen(prs[i].name)-1]='\0';
scanf("%d", &prs[i].age);
getchar();
}
bubblesort(prs,n);
for(i=0;i<n;i++)
{
printf("{%s, %d};", prs[i].name, prs[i].age);
}
return 0;
}
You can use an approach similar to the approach used by the standard C function qsort.
Add a third parameter to the function bubble_sort. For example
void bubble_sort( struct person *p,
int n,
int comp( const struct person *p1, const struct person *p2 ) );
Though it would be much better to declare the second parameter of the function as having type size_t
void bubble_sort( struct person *p,
size_t n,
int comp( const struct person *p1, const struct person *p2 ) );
Then define two functions that compare objects of the type struct person. Each function has to return a negative value if the first item is less than the second item, positive value if the first item is greater than the second item and zero otherwise.
The functions can look like
int comp_by_name( const struct person *p1, const struct person *p2 )
{
int str_cmp = strcmp( p1->name, p2->name );
int int_cmp = ( p2->age < p1->age ) - ( p1->age < p2->age );
return str_cmp != 0 ? str_cmp : int_cmp;
}
int comp_by_age( const struct person *p1, const struct person *p2 )
{
int str_cmp = strcmp( p1->name, p2->name );
int int_cmp = ( p2->age < p1->age ) - ( p1->age < p2->age );
return int_cmp != 0 ? int_cmp : str_cmp;
}
And inside the bubble_sort write the following if statement
if ( comp( &prs[j+1], &prs[j] ) < 0 )
{
struct person tmp = prs[j+1];
prs[j+1] = prs[j];
prs[j] = tmp;
}
And at last call the function bubble_sort either like
bubble_sort( prs, n, comp_by_name );
if you want to sort the array by names or
bubble_sort( prs, n, comp_by_age );
if you want to sort the array by ages.
Use this function prototype for bubblesort:
void bubblesort(struct person *prs, int n, int (*cmp)(struct person *a, struct person *b)) {...}
Now create a comparison function to compare two persons:
int cmpTwoPersons(struct person *a, struct person *b) {...}
This function should return a number larger than 0 if a>b, smaller than 0 if a
Call your bubblesort using this comparison function:
bubblesort(prs, n, cmpTwoPersons);
Now you use cmp inside your bubblesort:
void bubblesort(...) {
...
int cmpResult = cmp(prs[j], prs[j+1]);
if (cmpResult > 0) {
// j is large than j+1
} else {
// j is smaller than or equal to j+1
}
...
}
Your bubble sort signature can be:
void bubblesort(void **prs, int n, int (*cmp)(void *p1, void *p2))
You now compare in bubble sort as:
int cmpResult = cmp(prs[j], prs[j+1]);
The compare routine's signature is:
int cmpTwoPersons(struct person *a, struct person *b);
and call bubble sort as:
bubblesort(prs, n, cmpTwoPersons);
By using void * as data type, you make the bubble sort algorithm indpendent of the data to be sorted and the compare function says how to compare two elements. However, the data to be sorted must be an array of pointers so the bubble only needs to swap pointers and not whole structures as it doesn't know their size.
I am trying to sort an array of pointers to structs (definition below) based on the value stored in the void* of the "bucket" struct that I know are ints. It compiles and prints out my array of buckets and their values just fine with no errors or warnings but it isn't actually sorting the array. I have used asserts to try to find anywhere that could cause an error with qsort.
Struct definitions:
typedef struct _bucket{
void* val;
char *word;
}bucket;
typedef struct _root{
bucket **list;
int hashTableLength;
}root;
Sort Function to be passed to the qsort function:
int sortFunc(const void *a, const void *b){
bucket *bucketA=(bucket*)a;
bucket *bucketB=(bucket*)b;
int bucketAVal = *((int*)bucketA->val);
int bucketBVal = *((int*)bucketB->val);
assert((bucketAVal&&bucketBVal)!=0);
return bucketAVal-bucketBVal;
}
Sort the array and print:
void sort(root* inRoot, int(*sortFunc)(const void *a, const void *b)){
int length = inRoot->hashTableLength;
assert(length==11); //known length of hash array
for (int i = 0; i<length; i++)
assert(inRoot->list[i] != NULL);
qsort(inRoot->list, length, sizeof(bucket*), sortFunc);
for(int i =0; i<length; i++)
printf("%s was found %d times\n", inRoot->list[i]->word, *((int*)(inRoot->list[i]->val)));
return;
}
The compare function sortFunc() receives a pointer to each object. The array inRoot->list is an array of bucket * so sortFunc() is receiving pointers to bucket *: bucket **.
Also the int subtraction is subject to possible overflow. Use the idiomatic 2 compares to solved that.
int sortFunc(const void *a, const void *b) {
bucket **bucketA = (bucket**) a;
bucket **bucketB = (bucket**) b;
void *vA = (*bucketA)->val;
void *vB = (*bucketB)->val;
int iA = *((int*) vA);
int iB = *((int*) vB);
return (iA > iB) - (iA < iB);
}
Having trouble getting my head around implementing the qsort() built into C to sort an array of structs by a stored int value (hitCount).
My struct:
typedef struct words {
const char *word;
int hitCount;
} words;
I'm trying to use the example given by Microsoft (http://support.microsoft.com/kb/73853).
So I've got at the top:
typedef int (*compfn)(const void*, const void*);
and the comparision method:
int compare (words *a, words *b) {
if (a->hitCount > b->hitCount) {
return -1;
} else if (a->hitCount < b->hitCount) {
return 1;
} else {
return 0;
}
}
then within another method I call qsort with my array name and other details replacing the Microsoft example:
qsort((void *) &output, outputLength, sizeof(words), (compfn)compare);
This gives a segmentation fault.
I don't fully understand how to use qsort so I assume where I've adapted it from Microsoft's example I've done it incorrectly.
I hope I've included the mistake and can get some enlightenment as to what I should be doing in order for this to work correctly.
Many Thanks!
You have to pass the array not the address of the array to qsort.
qsort( output, ... );
Also your compare function must return an int and accept two const void* arguments.
Casting your function int compare (words *a, words *b) to a different( yet correct ) type which is then called by qsort() will cause undefined behaviour.
The compare function must be:
int compare (const void *a, const void *b)...
Then you cast a and b to correct types:
((words*)a)->hitCount < ((words*)b)->hitCount
I suspect that outputLength is computed incorrectly. A complete working example:
#include <stdio.h>
#include <stdlib.h>
typedef struct words {
const char *word;
int hitCount;
} words;
int compare(const void * left, const void * right) {
const words * a = (const words *) left;
const words * b = (const words *) right;
if (a->hitCount > b->hitCount) {
return -1;
} else if (a->hitCount < b->hitCount) {
return 1;
} else {
return 0;
}
}
int main() {
struct words output[] = {
{ "hello", 314 },
{ "world", 42 },
{ "answer", 42 }
};
int outputLength = sizeof(output) / sizeof(output[0]);
int i;
output[0].word = "hello";
output[0].hitCount = 314;
output[1].word = "world";
output[1].hitCount = 42;
qsort(output, outputLength, sizeof(words), compare);
for (i = 0; i < outputLength; ++i) {
printf("%d %s\n", output[i].hitCount, output[i].word);
}
return 0;
}
The prototype of the standard library function qsort is
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Note the signature of the compare function. You cannot typecast a pointer to a function of different signature and make it work correctly. Therefore, typecasting your compare function will not work. It must have the same signature as declared in the prototype of qsort. Change your compare function to -
int compare(const void *a, const void *b) {
int c = ((words *) a)->hitCount;
int d = ((words *) b)->hitCount;
if(c > d) return -1;
if(c < d) return 1;
return 0;
}
The first argument base of qsort is the base address of the buffer which contains the elements to be sorted. Also, any pointer type is assignment compatible to a void * variable and as such you don't need to cast the base address. Therefore, you should call the qsort function as -
qsort(output, outputLength, sizeof output[0], compare);
Got it working with:
int compare (const void *a, const void *b) {
if (((words *)a)->hitCount > ((words *)b)->hitCount) {
return -1;
} else if (((words *)a)->hitCount < ((words *)b)->hitCount) {
return 1;
} else {
return 0;
}
}
and call to sort:
qsort(output, outputLength, sizeof(words), compare);
Thanks to everyone's help but majority credit to "self".
Lets say I have the following code (the array* function are what we use for resizable arrays and they operate on pointers-to-arrays that are null initialized):
typedef struct MyStruct
{
int i;
} MyStruct;
MyStruct* GetNewMyStruct(int i)
{
MyStruct* s = malloc(sizeof(MyStruct));
s->i = i;
return s;
}
int SomeFunction(int number, MyStruct *elem)
{
MyStruct **structs = NULL;
int i;
for (i = 0; i < number; i++)
arrayPush(&structs, GetNewMyStruct(i));
arrayPush(&structs, elem);
return arraySize(&structs);
}
I decide that SomeFunction is too large and I want refactor it. Currently where I work we use VisualAssist X, which has some refactoring capabilities, but when I use it on this it does not work correctly. If I attempt to use it to refactor out the loop, this is what I get:
void MyMethod( int number, MyStruct ** structs )
{
int i;
for (i = 0; i < number; i++)
arrayPush(&structs, GetNewMyStruct(i));
}
int SomeFunction(int number, MyStruct *elem)
{
MyStruct **structs = NULL;
MyMethod(number, structs);
arrrayPush(&structs, elem);
return arraySize(&structs);
}
This is not correct. MyMethod should take a MyStruct ***, not a MyStruct **. This is because the code I'm refactoring takes the address of structs. The result is that the refactored version will always return 1 (since only one object has been pushed into my array) rather than number+1. Are there other tools out there that do this type of refactoring correctly?
Eclipse CDT does this correctly (at least the current version Juno). Selecting the declaration of i and the loop and doing Refactor > Extract Function, and setting structs to be an output parameter, produces:
void MyMethod(int number, MyStruct*** structs) {
int i;
for (i = 0; i < number; i++)
arrayPush(&*structs, GetNewMyStruct(i));
}
int SomeFunction(int number, MyStruct *elem)
{
MyStruct **structs = NULL;
MyMethod(number, &structs);
arrayPush(&structs, elem);
return arraySize(&structs);
}