I have a struct:
struct points{
int i;
int x;
int y;
};
And I made an array of the struct and put elements in it. The i element indicates the label of a certain point. Suppose I have 1 2 3 as an input in the array. 1 corresponds to the label of the point (2, 3). Then I tried to sort the x elements:
for (a=0; a < i; a++){
for (b = 0; b < i; b++){
if (pt[b].x > pt[b+1].x){
temp1 = pt[b].x;
pt[b].x = pt[b+1].x;
pt[b+1].x = temp1;
}
}
}
It was sorted correctly. Now when I printed the i (label), it did not correspond with the x element when sorted. In short, only the x element moved. I want to make the i and y move with the x as it is sorted. What should I do?
Instead of just swapping x you need to swap all the data so that the entire array of structures gets sorted.
You could do this with a separate function, for clarity:
void swap_points(struct points *pa, struct points *pb)
{
const struct points tmp = *pa;
*pa = *pb;
*pb = tmp;
}
Then call that instead of the three inner-most lines of code in your sort.
You really should just use qsort() to do this, it's much simpler:
static int compare_points(const void *va, const void *vb)
{
const struct points *pa = va, *pb = vb;
return pa->i < pb->i ? -1 : pa->i > pb->i;
}
qsort(pt, i, sizeof pt[0], compare_points);
You are actually sorting the array, but only the values for i, not the whole structure!
You'll want to use C's qsort here:
#include <stdlib.h>
#include <stdio.h>
struct points
{
int i;
int x;
int y;
};
int compare(const struct points *a, const struct points *b)
{
if (a->i < b->i) return -1;
if (a->i == b->i) return 0;
if (a->i > b->i) return 1;
}
int main(void)
{
int i;
struct points p[3] = { { 4, 2, 1 }, { 1, 3, 5 }, { 2, 8, 1 } };
qsort(p, 3, sizeof(struct points),
(int (*)(const void*, const void*)) compare);
printf("{ ");
for (i=0; i<3; ++i)
{
printf("{ %d, %d, %d }", p[i].i, p[i].x, p[i].y);
if (i < 2) printf(", ");
}
printf(" }\n");
}
See http://www.cplusplus.com/reference/cstdlib/qsort/
You have to copy the other elements in the struct too.
I suppose you to write a function which replace the values of an element, like this:
void copyPoints(point1* a, point2* b)
{
int temp = a->i;
a->i = b->i;
b->i = temp;
temp = a->x;
a->x = b->x;
b->x = temp;
temp = a->y;
a->y = b->y;
b->y = temp;
}
Then modify the code like this:
for (a=0; a < i; a++)
{
for (b = 0; b < i; b++)
{
if (pt[b].x > pt[b+1].x)
copyPoints(&(pt[b]),&(pt[b+1]));
}
}
Related
I have this project where I need to create an array, split it into two, and then sort each array using its own thread, then merge the two arrays back into a single array. Thankfully, the final array doesn't need to be sorted itself.
I wrote this code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
//Change length of main input array
const int arrLen = 20;
const int mid = arrLen/2;
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void *sort(void *arg){
int min_pos;
for(int a=0; a<arrLen-1; a++){
min_pos = a;
for(int b=a+1; b<arrLen; b++){
if(array[b] < array[min_pos]){
min_pos = b;
}
}
swap(&array[min_pos], &array[a]);
}
}
void printResult(int array[]){
for(int k=0; k<arrLen/2; k++){
printf("Num%d: %d\n", k, array[k]);
}
}
//Adds random values to each position in a given array
void arrayCreator(int array[]){
int random;
for(int i=0; i<arrLen; i++){
random = rand() % 100;
array[i] = random;
}
}
void main(){
printf("Program Initialized...\n");
int mainArray [arrLen], firstHalf[mid], secondHalf[mid], random;
time_t t;
srand((unsigned) time(&t));
//Populate mainArray
for(int i=0; i<arrLen; i++){
mainArray[i] = rand()%100;
}
printf("Array created...\n");
//Split mainArray[] into two seperate arrays
for(int p=0; p<arrLen; p++){
if(p<mid){
firstHalf[p]=mainArray[p];
}
else{
secondHalf[p-mid]=mainArray[p];
}
}
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1, NULL, sort, (void*)firstHalf);
//pthread_create(&tid2, NULL, sort, secondHalf);
printResult(firstHalf);
//printResult(secondHalf);
}
How can I get the sort function to access my array?
First, I would look at the signature of the standard function qsort and provide the same interface for your sort function. I'd also rename it into bubble_sort since it's doing bubble sorting. Your function would then look like this:
void bubble_sort(void *ptr, size_t arrLen, size_t elem_size,
int (*comp)(const void *, const void *)) {
char *array = ptr; // to be able to do pointer arithmetic
for (size_t a = 0; a < arrLen - 1; a++) {
for (size_t b = a + 1; b < arrLen; b++) {
if (comp(array + a * elem_size, array + b * elem_size) > 0) {
swap(array + a * elem_size, array + b * elem_size, elem_size);
}
}
}
}
elem_size is the size of the elements you want to sort, which will be set to sizeof(int) later.
comp is a function taking two void* and returns an int where ...
< 0 means *a < *b
> 0 means *a > *b
== 0 means *a == *b
swap also takes the elem_size parameter to be able to swap objects of any size. Implemented, it could look like this:
void swap(void *a, void *b, size_t elem_size) {
char tmp[elem_size];
memcpy(tmp, a, elem_size);
memcpy(a, b, elem_size);
memcpy(b, tmp, elem_size);
}
Now, you can't start a thread by calling bubble_sort directly. A thread start routine only takes a single void* as an argument so we need some way of passing all the necessary arguments on. We can package them in a struct like this:
struct sort_thread_args {
pthread_t tid;
void *array;
size_t arrLen;
size_t elem_size;
int (*comp_func)(const void *, const void *);
};
void *sort_thread(void *arg) { // the thread start routine
struct sort_thread_args *ta = arg;
bubble_sort(ta->array, ta->arrLen, ta->elem_size, ta->comp_func);
return NULL;
}
As can be seen above, the struct contains all the necessary information to call bubble_sort + the thread id, which I've stored there for convenience only. It's not needed by the thread itself.
The above functions are type agnostic so you can use these to sort any contiguous array, either by calling bubble_sort directly or in a thread.
Since you'll be using this to sort arrays of int, we need a comparison function for ints which does what was described above:
int comp_int(const void *va, const void *vb) {
const int *a = va;
const int *b = vb;
if (*a < *b) return -1;
if (*a > *b) return 1;
return 0;
}
Then for sorting half the array in one thread and the other half in another thread, I suggest that you don't copy the contents of mainArray to new arrays. Just leave the content in mainArray and tell each thread where to start sorting and how many elements it should sort.
Example:
#define Size(x) (sizeof(x) / sizeof *(x))
int main() {
srand((unsigned)time(NULL));
puts("Program Initialized...");
int arrLen = 35; // just an example to show that it handes uneven amounts too
int mainArray[arrLen];
// Populate mainArray
for (size_t i = 0; i < Size(mainArray); i++) {
mainArray[i] = rand() % 100;
}
puts("Array created...");
// print the created array
for (size_t i = 0; i < Size(mainArray); ++i) printf("%2d ", mainArray[i]);
putchar('\n');
puts("Running sorting threads...");
struct sort_thread_args ta[2]; // 2 for 2 threads
for (size_t i = 0; i < Size(ta); ++i) {
// element index for where this thread should start sorting:
size_t base = i * Size(mainArray) / Size(ta);
// prepare the arguments for this thread:
ta[i] = (struct sort_thread_args) {
.array = mainArray + base, // points at the first element for this thread
.arrLen = (i + 1) * Size(mainArray) / Size(ta) - base,
.elem_size = sizeof(int),
.comp_func = comp_int // the comparison function we made above
};
// and start the thread:
pthread_create(&ta[i].tid, NULL, sort_thread, &ta[i]);
}
puts("Joining threads");
for (size_t i = 0; i < Size(ta); ++i) {
pthread_join(ta[i].tid, NULL);
}
puts("Result:");
for (size_t i = 0; i < Size(mainArray); ++i) printf("%2d ", mainArray[i]);
putchar('\n');
}
Demo
Simply assign arg to your array variable in order to convert from void * to int *.
void *sort(void *arg){
int min_pos;
int *array = arg;
for(int a=0; a<arrLen-1; a++){
min_pos = a;
for(int b=a+1; b<arrLen; b++){
if(array[b] < array[min_pos]){
min_pos = b;
}
}
swap(&array[min_pos], &array[a]);
}
}
I have two arrays side by side, one lists the different teams and the other lists the scores. I am able to sort the order of scores in descending order. Can this order then be used to move the corresponding team to the correct position of the leader board? eg. move the two teams with 100 points (USA and Germany) to the top of the board
#include <stdio.h>
int main()
{
char teams[18][20]={"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[18]={43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
int i;
int j;
int a;
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
printf("\n");
for (i = 0; i < 18; ++i)
{
for (j = i + 1; j < 18; ++j)
{
if (points[i] < points[j])
{
a = points[i];
points[i] = points[j];
points[j] = a;
}
}
}
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
return 0;
}
As mentioned in a comment, the typical solution is to model your data as an array of structures, rather than separate arrays. This makes sense, since the data is associated with each other.
You'd have something like:
struct score {
const char *name;
int points;
} scores[] = {
{ "England", 43 },
{ "Ireland", 5 },
/* and so on */
};
Then you can use qsort() (or your own sorting code, if that's of interest) to sort entire structure instances, and the all the data will remain together since entire structures are being moved around.
Also arrange your teams array when sorting;
a = points[i];
b = teams[i];
points[i] = points[j];
teams[i] = teams[j];
points[j] = a;
teams[j] = b;
The obvious way (as pointed out by others) is embedding your arrays into a struct, but if you are forced to use parallel arrays you can build your own function and sort both arrays at once:
#include <stdio.h>
static int comp(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
static void swap(int v1[], char *v2[], int a, int b)
{
int temp1;
char *temp2;
temp1 = v1[a];
v1[a] = v1[b];
v1[b] = temp1;
temp2 = v2[a];
v2[a] = v2[b];
v2[b] = temp2;
}
static void sort(int v1[], char *v2[], int left, int right, int (*comp)(const void *, const void *))
{
int i, last;
if (left >= right) return;
swap(v1, v2, left, (left + right) / 2);
last = left;
for (i = left + 1; i <= right; i++) {
if (comp(&v1[i], &v1[left]) < 0)
swap(v1, v2, ++last, i);
}
swap(v1, v2, left, last);
sort(v1, v2, left, last - 1, comp);
sort(v1, v2, last + 1, right, comp);
}
int main(void)
{
char *teams[] = {"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[] = {43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
size_t i, n = sizeof(points) / sizeof(*points);
sort(points, teams, 0, n - 1, comp);
for (i = 0; i < n; i++) {
printf("%s->%d\n", teams[i], points[i]);
}
return 0;
}
Output:
Italy->0
Ireland->5
Sweden->11
Scotland->23
South Africa->26
Belize->32
Japan->37
England->43
Mexico->45
Uraguay->46
Australia->55
Denmark->65
Wales->77
Algeria->78
France->89
Belgium->94
Germany->100
USA->100
Suppose I have the following struct:
struct Pair {
int x;
int y;
}
I want to sort the array by the first element in the pair, i.e. x and then by the second element so if we are given the following:
input: [(1,2), (1,0), (2,3), (1,4), (2,2)]
output: [(1,0), (1,2), (1,4), (2,2), (2,3)]
Right now I have two functions, one of them sorts the array by first element and the second one sorts it by second element but this is less efficient. How can I iterate through the array once and achieve the desired result?
void sort1(Pair ps[], int size) {
int i, j;
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++) {
if (ps[j].x > ps[j+1].x) {
Pair temp = ps[j+1];
ps[j+1] = ps[j];
ps[j] = temp;
}
}
}
}
void sort2(Pair ps[], int size) {
int i, j;
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++) {
if (ps[j].y > ps[j+1].y) {
Pair temp = ps[j+1];
ps[j+1] = ps[j];
ps[j] = temp;
}
}
}
}
Also, is there a quick way to do this using a built-in sorting function?
You can use qsort() which is a C library implementation of quicksort.
In order to use this function, you need to design a cmp function which compares two x values against one another, and if their are ties, then sort by y.
In order for this to not be cluttered into one cmp function, you can firstly make a smaller function which tests equality of two integers:
int compare_int(const int a , const int b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
}
return 0;
}
Then you can integrate this into your main cmp function, which qsort() will be calling. This function can simply be:
int cmp_func(const void *a, const void *b) {
const pair_t *num1 = (pair_t *)a;
const pair_t *num2 = (pair_t *)b;
if (num1->x == num2->x) {
return compare_int(num1->y, num2->y);
} else if (num1->x > num2->x) {
return +1;
}
return -1;
}
Then you can simply call qsort() as the following:
qsort(ps, sizeof(ps)/sizeof(ps[0]), sizeof(pair_t), cmp_func);
Here is some example code which does this:
#include <stdio.h>
#include <stdlib.h>
#define ARRAYSIZE(x) ((sizeof(x))/sizeof(x[0]))
typedef struct {
int x;
int y;
} pair_t;
int compare_int(const int a , const int b) {
if ( a < b ) {
return -1;
} else if ( a > b ) {
return 1;
}
return 0;
}
int cmp_func(const void *a, const void *b) {
const pair_t *num1 = (pair_t *)a;
const pair_t *num2 = (pair_t *)b;
if (num1->x == num2->x) {
return compare_int(num1->y, num2->y);
} else if (num1->x > num2->x) {
return +1;
}
return -1;
}
void print_array(pair_t ps[], size_t n) {
printf("[");
for (size_t i = 0; i < n; i++) {
printf("(%d,%d)", ps[i].x, ps[i].y);
if (i != n-1) {
printf(", ");
}
}
printf("]\n");
}
int main(void) {
pair_t ps[] = {{1,2}, {1,0}, {2,3}, {1,4}, {2,2}};
printf("Input: ");
print_array(ps, ARRAYSIZE(ps));
qsort(ps, ARRAYSIZE(ps), sizeof(pair_t), cmp_func);
printf("Output: ");
print_array(ps, ARRAYSIZE(ps));
return 0;
}
Which outputs:
Input: [(1,2), (1,0), (2,3), (1,4), (2,2)]
Output: [(1,0), (1,2), (1,4), (2,2), (2,3)]
Note: your original code, which is implementing bubble sort, has O(n^2) run-time on average. However, if you use qsort() instead, you will be able to achieve a much faster average of O(logN) run-time. This difference will help achieve quicker results if n grows larger.
You just need a proper function to compare two pairs:
int comparePairs (const void * a, const void * b)
{
const Pair* A = (const Pair*) a;
const Pair* B = (const Pair*) b;
return (A.x == B.x) ? (A.y - B.y) : (A.x - B.x);
}
Then you can use the built-in function qsort.
This struct allows representing arbitrary size matrices, where M is the number of rows, N is the number of columns and data is a pointer to M*N values of type double stored by rows.
struct matrix {
size_t M, N;
double *data;
};
struct matrix *mat_directsum(const struct matrix *a, const struct matrix *b);
The function mat_directsum accepts two pointers to arrays as a parameter and should return to the direct sum, dynamically allocated on the heap.
Example:
A.M = 2
A.N = 3
A.data = (1, 1, 2, 0, 1, -3)
Example of direct sum function
I just need a few tips on how to set the function, just to see how others work with arrays of this type, because the only way that comes to mind is an iterative methods with many loops, however, it is enough work long and ingenious, I would like to know if there are easier method to solve it. Thank you
ps.
(memory allocation is not a problem of course)
EDIT
I solved like that:
struct matrix *mat_directsum(const struct matrix *a, const struct matrix *b) {
struct matrix *c = malloc(sizeof(struct matrix));
c->M = a->M + b->M;
c->N = a->N + b->N;
int n = c->M * c->M;
double *dati = calloc(n, sizeof(double));
int t = 0;//index new array
int y = 0;//index first mat
int z = 0;//index second mat
for (int i = 0; i < c->N; i++) {
if (i < a->N) {//first mat
for (int j = 0; j < c->M; j++) {
if (j < a->M) {
dati[t] = a->data[y];
y++;
}
t++;
}
} else {//second mat
for (int j = 0; j < c->M; j++) {
if (j >= a->M) {
dati[t] = b->data[z];
z++;
}
t++;
}
}
}
c->data = dati;
return c;
}
I don't know how to do it which only one for loop
//macro which will point to an element indexed at [xe][ye]
#define ELEMENT(data,rows,columns,xe,ye) (data+((xe)*(columns)+(ye)))
struct matrix
{
size_t M, N;
double *data;
};
//won't mind changing the return type from "struct matrix*" to "struct matrix"
struct matrix mat_directsum(const struct matrix *a, const struct matrix *b)
{
int x;
struct matrix res;
res.M = a->M + b->M;
res.N = a->N + b->N;
//using calloc will set the memory to zero i.e all the bytes will be set to zero.
res.data = (double*)calloc(res.M * res.N, sizeof(double));
if(res.data == NULL)
{
return res;
}
for(x = 0; x < a->M; ++x)
{
memcpy(ELEMENT(res.data, res.M, res.N, x, 0), ELEMENT(a->data, a->M, a->N, x, 0), a->N * sizeof(double));
}
for(x = 0; x < b->M; ++x)
{
//note the offset by [a->M][a->N] while accessing elements of res.
memcpy(ELEMENT(res.data, res.M, res.N, x + a->M, a->N), ELEMENT(b->data, b->M, b->N, x, 0), b->N * sizeof(double));
}
return res;
}
struct matrix res = mat_directsum(&a, &b);
if(res.data != NULL)
{
free(res.data);
}
Besides the error n = c->M * c->M, spotted by M.M (what a coincidence of Ms!), your solution has another error in the for loops: You confused the row and column numbers M and N - since the values are stored by rows, the outer loop has to be for (int i = 0; i < c->M; i++) and the inner loops have to be for (int j = 0; j < c->N; j++), so all M and N in those loops (also in the ifs) have to be swapped. Apart from that and the missing allocation error checks, your solution is fine.
I don't know how to do it which only one for loop
If you want to see an alternative approach, here's one with a helper function to insert the matrices into the sum matrix:
#include <string.h>
void mat_insert(const struct matrix *s, struct matrix *d, int r, int c)
{ // copy source matrix s to destination matrix d at row r, column c
for (int i = 0; i < s->M; i++) // for each row
memcpy(d->data+(r+i)*d->N+c, s->data+i*s->N, s->N*sizeof*s->data);
}
struct matrix *mat_directsum(const struct matrix *a, const struct matrix *b)
{
struct matrix *c = malloc(sizeof *c); if (!c) return NULL;
c->M = a->M + b->M;
c->N = a->N + b->N;
int n = c->M * c->N;
c->data = calloc(n, sizeof *c->data); if (!c->data) return free(c), NULL;
mat_insert(a, c, 0, 0); // copy a to c at row 0, column 0
mat_insert(b, c, a->M, a->N); // copy b to c at row a->M, column a->N
return c;
}
I am trying to sort an array of pointers by the memory address:
#include <stdio.h>
#include <stdlib.h>
typedef struct flist {
int size;
struct flist *blink;
struct flist *flink;
} *Flist;
int compare(const void *x, const void *y)
{
Flist a = (Flist)x;
Flist b = (Flist)y;
if(a < b)
return -1;
else
return 1;
}
int main()
{
int a[] = {3, 1, 2, 4, 0};
Flist b[5];
int i;
for(i = 0; i < 5; i++)
b[a[i]] = (Flist)malloc(12);
printf("Here is the array before sorting:\n");
for(i = 0; i < 5; i++)
printf("%p\n", b[i]);
qsort(b, 5, sizeof(Flist), compare);
printf("Here is the array after sorting:\n");
for(i = 0; i < 5; i++)
printf("%p\n", b[i]);
}
However, the program has no effect on the order of the addresses:
Here is the array before sorting:
0x759090
0x759030
0x759050
0x759010
0x759070
Here is the array after sorting:
0x759090
0x759030
0x759050
0x759010
0x759070
Any suggestions would be much appreciated!
You are missing a level of indirection: qsort sends in addresses of elements being sorted, not the elements themselves.
In your case, you are seeing addresses of the addresses of your Flist elements being passed. You need to dereference the pointers passed in after casting to Flist* (which is a pointer to a pointer):
int compare(const void *x, const void *y) {
Flist a = *((Flist*)x);
Flist b = *((Flist*)y);
if(a < b)
return -1;
else
return 1;
}
compare receives the addresses of the array elements. These are of course already in sequence.
To sort by the values, you'd need to change compare to
int compare(const void *x, const void *y)
{
Flist a = *(Flist*)x;
Flist b = *(Flist*)y;
if(a < b)
return -1;
else if (a == b)
return 0;
else
return 1;
}
but since the pointers are not all pointing into the same array (or one past the end), it's technically undefined behaviour.