Sorting a structure - c

I wanted to sort this problem in C with something like bubble sort ... anyone can help
Implement a list with 5 struct Point (Being this a point w/ X, y);
Sort the 5 struct point (first evaluate x then y).
Example:
// The points
p[0]={2,3}
p[1]={4,5}
p[2]={1,5}
p[3]={4,3}
p[4]={1,2}
// Should become
p[0]={1,2}
p[1]={1,5}
p[2]={2,3}
p[3]={4,3}
p[4]={4,5}

If you want to sort structures, you still have to break it down into comparing numeric types. With this in mind, let's take your example with the points:
struct tagPoint
{
int x;
int y;
};
typedef struct tagPoint Point;
Now, let's suppose you have an array of Point and you want it sorted. You can take two approaches:
1. Straightforward function which sorts the array:
Just make the function to sort the array:
void SortPointArray(Point* Points, unsigned int n)
{
/* This will sort the points with priority on the x and then the y value in ascending order. */
for(unsigned int i = 0; i < n-1; i++)
for(unsigned int j = i+1; j < n; j++)
{
if (Points[i].x > Points[j].x)
{
Point aux = Points[i];
Points[i] = Points[j];
Points[j] = aux;
}
else if ((Points[i].x == Points[j].x) && (Points[i].y > Points[j].y))
{
Point aux = Points[i];
Points[i] = Points[j];
Points[j] = aux;
}
}
}
2. Wrap the algorithm in a generic function and use callbacks for each type you want to sort:
This is a little more complicated, but it will save you some time if you use it frequently. Here, this function uses the same algorithm as the one above, but can sort any types.
void Sort(void* lpArray, unsigned int n, size_t cbSize, int (*Cmp)(void*, void*), void (*Swap)(void*, void*))
{
for(unsigned int i = 0; i < n-1; i++)
for(unsigned int j = i+1; j < n; j++)
/* Cast void* to char* to get rid of warning with pointer arithmetic... */
if ( Cmp( ((char*)lpArray) + i*cbSize, ((char*)lpArray) + j*cbSize) )
Swap( ((char*)lpArray) + i*cbSize, ((char*)lpArray) + j*cbSize );
}
As you can see, it requires 2 more functions passed as parameters. If you want this Sort function to know how to sort the Point array, you must define a Comparrison function and a Swapping function and tell the Sort function to use them.
Here is how i implemented them:
/** This function return 1 if p1 should be swapped with p2. */
int ComparePoints(void* vp1, void* vp2)
{
Point *p1, *p2;
p1 = vp1;
p2 = vp2;
if (p1->x > p2->x)
return 1;
else if ((p1->x == p2->x) && (p1->y > p2->y))
return 1;
return 0;
}
/** This will swap 2 points. */
void SwapPoints(void* vp1, void* vp2)
{
Point p = *(Point*)vp1;
*(Point*)vp1 = *(Point*)vp2;
*(Point*)vp2 = p;
}
How do you use them?
If you only want to use the first SortPointArray function, this is enough:
int main()
{
Point Array[10];
/* Read the points. */
for(unsigned int i = 0; i < 10; i++)
scanf("%d %d", &Array[i].x, &Array[i].y);
SortPointArray(Array, 10);
/*Print the points.*/
for(unsigned int i = 0; i < 10; i++)
printf("%d %d\n", Array[i].x, Array[i].y);
return 0;
}
But if you want to use the generic Sort function (which i recommend only if you have multiple types you want to sort like Points, Lines etc) you have to define the two callbacks (ComparePoints and SwapPoints)
int main()
{
Point Array[10];
/* Read the points. */
for(unsigned int i = 0; i < 10; i++)
scanf("%d %d", &Array[i].x, &Array[i].y);
Sort(Array, 10, sizeof(Point), ComparePoints, SwapPoints);
/*Print the points.*/
for(unsigned int i = 0; i < 10; i++)
printf("%d %d\n", Array[i].x, Array[i].y);
return 0;
}

The OP is asking for a C solution, so here you go:
void bsortDesc(struct yourStruct list[80], int s)
{
int i, j;
struct yourStruct temp;
for (i = 0; i < s - 1; i++)
{
for (j = 0; j < (s - 1-i); j++)
{
if (list[j].marks < list[j + 1].marks)
{
temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
Also, here's what I got it from: here.

Related

Why am I getting a segfault in this genetic algorithm problem?

I'm trying to solve a CodeWars problem called "Training on Binary Genetic Algorithms." There is a fitness function that is preloaded. When the program is run, a test function creates a random 35-bit string and it uses my run function which is supposed to return the same 35-bit string. This string is supposed to be found using a genetic algorithm.
Here is my code:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
typedef double fitness_t (const char *, ...);
extern fitness_t fitness;
void generate (size_t length, char * s)
{
for (size_t i = 0; i < length; i++)
s[i] = rand() % 2 + 48;
}
double sum(size_t n, double ar[n])
{
double sum = 0;
for (int i = 0; i < n; i++)
sum += ar[i];
return sum;
}
void select (int size, char* population[size], double fitnesses[size])
{
double probabilities[size]; // normalized to 1
double r; // random number
int s1, s2;
int i;
for (i = 0; i < size; i++)
probabilities[i] = fitnesses[i] / sum(size, fitnesses);
// select first chromosome
r = (double)(rand() % 1000000) / 1000000; // generates a random float between 0 and 1
for (i = 0; i < size && r > 0; i++)
r -= probabilities[i];
s1 = i;
// select second chromosome
s2 = s1;
while (s2 == s1) // ensures the two chromosomes aren't the same
{
r = (double)(rand() % 1000000) / 1000000; // generates a random float between 0 and 1
for (i = 0; i < size && r > 0; i++)
r -= probabilities[i];
s2 = i;
}
// places these two chromosomes on top
char * temp = population[0];
population[0] = population[s1];
population[s1] = temp;
temp = population[1];
population[1] = population[s2];
population[s2] = temp;
}
void crossover (size_t n, char* s1, char* s2)
{
int r = rand() % n; // select a random bit to cross over at
char temp;
for (size_t i = r; i < n; i++) // swap every bit from bit r to bit n
{
temp = s1[i];
s1[i] = s2[i];
s2[i] = temp;
}
}
void mutate (size_t n, char* s, double p)
{
double r;
for (size_t i = 0; i < n; i++) // for each bit
{
r = (double)(rand() % 1000000) / 1000000; // random float between 0 and 1
if (r <= p) // if random number is less than probability
{
if (s[i] == '1') s[i] = '0'; // swap 0s and 1s
else s[i] = '1';
}
}
}
void bubbleSortPop(int size, char * population[size], double fitnesses[size])
{
int i, j;
char * temp_chrome;
double temp_fitness;
for (i = 0; i < size - 1; i++)
// Last i elements are already in place
for (j = 0; j < size - i - 1; j++)
if (fitnesses[j] < fitnesses[j + 1])
{
temp_chrome = population[j];
population[j] = population[j+1];
population[j+1] = temp_chrome;
temp_fitness = fitnesses[j];
fitnesses[j] = fitnesses[j+1];
fitnesses[j+1] = temp_fitness;
}
}
// this function changes the population.
// select, crossover, mutate
void evolve(fitness_t f, size_t size, int length, char * population[size],
double fitnesses[size], double p_c, double p_m)
{
char * s1, * s2;
double f1, f2;
char * temp_pop[size+2];
double temp_fit[size+2];
int i;
double r;
// moves two selected parents to the top
select(size, population, fitnesses);
// begin reproduction process; duplicate the chromosomes
s1 = population[0];
s2 = population[1];
// crossover
r = (double)(rand() % 1000000) / 1000000; // random float between 0 and 1
if (r < p_c) // probability of crossing over
crossover(length, s1, s2); // commences with crossover
// mutate
mutate(length, s1, p_m);
mutate(length, s2, p_m);
// calculate fitnesses
f1 = f(s1);
f2 = f(s2);
// merge fitneses
// copy original fitnesses into temp_fit
for (i = 0; i < size; i++)
temp_fit[i] = fitnesses[i];
// add new fitnesses
temp_fit[size] = f1;
temp_fit[size+1] = f2;
// merge children into population
// copy original population into temp_pop
for (i = 0; i < size; i++)
temp_pop[i] = population[i];
// add two children to temp_pop
temp_pop[size] = s1;
temp_pop[size+1] = s2;
// sort fitnesses and population
bubbleSortPop(size+2, temp_pop, temp_fit);
// add first 100 elements of temp_pop and fit to population and fitnesses
for (i = 0; i < size; i++)
{
population[i] = temp_pop[i];
fitnesses[i] = temp_fit[i];
}
}
char* runN (fitness_t f, int length, double p_c, double p_m, size_t iterations) {
}
char* run (fitness_t f, int length, double p_c, double p_m)
{
size_t size = 100;
char * population[size];
double fitnesses[size];
size_t i;
int r;
srand(time(0));
// initialize population array
for (i = 0; i < size; i++)
population[i] = malloc((length+1) * sizeof(char));
// generate original population
for (i = 0; i < size; i++)
{
generate(length, population[i]);
fitnesses[i] = f(population[i]);
printf("[%2d] %s %lf\n", i, population[i], fitnesses[i]);
}
// evolve the population
for (i = 0; i < 10; i++)
evolve(f, size, length, population, fitnesses, p_c, p_m);
// print result
printf("\nAFTER EVOLUTION\n");
for (i = 0; i < size; i++) // generates original population
printf("[%2d] %s %lf\n", i, population[i], fitnesses[i]);
// store best chromosome and free memory
char ret[length+1];
strcpy(ret, population[0]);
for (i = 0; i < size; i++)
free(population[i]);
return ret;
}
The issue is when I run my code, it nearly always comes out with a segfault at some point while printing the contents of population and fitness.
At least these problems:
Attempting to print a non-string with "%s"
Code uses "%s" and passes population[i] as if it points to a string. population[i] does not point to a string as it does not certainly have a null character. Result undefined behavior (UB). Perhaps attempting to access beyond allocated memory.
// Undefined behavior: population[i] not a string
printf("[%2d] %s %lf\n", i, population[i], fitnesses[i]);
Set the null character.
generate(length, population[i]);
population[i][length] = '\0'; // Add this here or equivalent in `generate()`.
Many compiler warnings (20+)
Enable all compiler warnings and fix those.
I found the solution. It was all the places where I tried to copy a string by making a string pointer and assigning it the same address as the pointer I wanted to copy. For example, in 'select', when I tried to move the two strings to the top, I did
char * temp = population[0];
population[0] = population[s1];
population[s1] = temp;
temp = population[1];
population[1] = population[s2];
population[s2] = temp;
I changed this to using strcpy(). I made the same mistake in 'evolve' where I tried to duplicate the chromosomes by just copying their address into variables, rather than the strings themselves:
char * s1, * s2;
// begin reproduction process; duplicate the chromosomes
s1 = population[0];
s2 = population[1];
I changed it to this:
char s1[length+1], s2[length+1];
strcpy(s1, population[0]);
strcpy(s2, population[1]);
After I made this change the segfault went away. Thanks for all your answers.

I want to know why this don't work the same(function definition outside-main and if inside-main function)

#include <stdio.h>
int generator(int n) {
int ten[6]; // array that saves digit number
int result = n;
for (int i = 0; i < 6; i++) {
ten[i] = n % 10; //saving digit number
n = n / 10;
result += ten[i];
}
return result;
}
void sort(int x, int y) { //the problem function. it didn't work
if (x > y) {
int temp;
temp = y;
y = x;
x = temp;
}
int main(void) {
int number[10000];
int selfNumber[10000];
int result[10000];
for (int i = 0; i < 100; i++) {
number[i] = generator(i+1); //generator function
}
for (int i = 0; i < 100; i++) {
printf("%d\n", number[i]);
}
for (int i = 0; i < 100; i++) {
if (number[i] > number[i + 1]) { //it worked.
int temp;
temp = number[i + 1];
number[i+1] = number[i];
number[i]=temp;
}
sort(number[i], number[i + 1]);
}
for (int i = 0; i < 100; i++) {
printf("%d\n", number[i]);
}
return 0;
I defined the void function sort to sort the numbers in size. But it didn't work.
So, I used if inside of main function to sort the numbers in size.
I don't know why it does work it different.
Your sort function takes parameters by value (pass-by-value), i.e. it use copy of the numbers you passed to it. sort exchange that copies successfully, but it's not the behaviour you expect.
Use pointers (or references in C++) when you want pass-by-reference semantics:
void sort(int* x, int* y) {
if (*x > *y) {
int temp = *y;
*y = *x;
*x = temp;
}
}
Read more about pointers here.
You are passing x & y by value to the sort function, so when you return any changes are lost. You might want to pass pointers instead:
void sort(int *x, int *y) {
if (*x > *y) {
int temp;
temp = *y;
*y = *x;
*x = temp;
}
}
This will cause the original values to be changed, not just the local copies.

Overflow happening because of addition?

Hello and sorry for lame title of this post, just couldn't find a better one.
So, I'm solving Codility exercise called NumberOfDiscIntersections. The solution requires some basic sorting and some minor arithmetic operations. I have achieved 93% result, and only one test is failing. The descripton that they provide is following:
For example, for the input [1, 2147483647, 0] the solution returned a wrong answer (got -1 expected 2).
Problem can be seen here.
And here is my solution:
typedef long long int my_type; //can't use unsigned!
#define LIMIT 10000000
//method used by qsort()
int comp(const void* left, const void* right) {
my_type arg1 = *(const my_type*)left;
my_type arg2 = *(const my_type*)right;
if(arg1 < arg2) return -1;
if(arg2 < arg1) return 1;
return 0;
}
int solution(int A[], int N) {
// write your code in C99 (gcc 6.2.0)
//allocate two arrays to hold beginning and ending points of each circle
my_type *lower = calloc(N, sizeof(my_type));
my_type *upper = calloc(N, sizeof(my_type));
int i;
my_type count = 0;
//initialize arrays
for(i = 0; i < N; i++) {
lower[i] = i - A[i];
upper[i] = i + A[i];
}
qsort(lower, N, sizeof(my_type), comp);
qsort(upper, N, sizeof(my_type), comp);
int open = 0;
int upper_index = 0;
for(i = 0; i < N; i++) {
while(lower[i] > upper[upper_index]) {
//printf("closing %d\n", upper[upper_index]);
upper_index++;
open--;
}
open++;
count += (open-1);
//printf("opening %d\n", lower[i]);
}
free(lower);
free(upper);
return ((int)count <= LIMIT) ? (int)count : -1;
}
The right hand side of these
lower[i] = i - A[i];
upper[i] = i + A[i];
performs int addition. You must cast one of the operands:
lower[i] = (my_type)i - A[i];
upper[i] = (my_type)i + A[i];
to prevent integer overflow.

2D arrays using arrays of pointers or pointers to pointers in C?

I'm writing a C for which I need to create a 2D array. I've found a solution to my problem using double pointers (pointers to pointers) in the following way:
#include <stdio.h>
#include <stdlib.h>
int d = 3;
#define DIM_MAX 9
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int **array = malloc(d*sizeof(int *));
for(int count = 0; count < d; count++)
{
array[count] = malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
The code above works pretty well (it seems), but I've read in the web that using pointer to pointer is not the correct way to create 2D arrays. So I've come up with the following code, which also works:
#include <stdio.h>
#include <stdlib.h>
#define DIM_MAX 9
int d = 3;
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int *array[DIM_MAX] = {0};
for(int count = 0; count < d; count++)
{
array[count] = (int *)malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
What is the difference in using any of the two ways above to write this code?
[Not an answer, but an alternative approach to achieve the desired result, namely defining a user-defined 2D array.]
Assuming the compiler in use supports VLAs you could do this:
#include <stddef.h> /* for size_t */
void init_a(size_t x, size_t y, int a[x][y]); /* Order matters here!
1st give the dimensions, then the array. */
{
for (size_t i = 0; i < x; ++i)
{
for (size_t j = 0; j < y; ++j)
{
a[i][j] = (int) (i * j); /* or whatever values you need ... */
}
}
}
int main(void)
{
size_t x, y;
/* Read in x and y from where ever ... */
{
int a[x][y]; /* Define array of user specified size. */
init_a(x, y, a); /* "Initialise" the array's elements. */
...
}
}
It is actually pretty simple. All you have to do is this:
int i[][];
You are overthinking it. Same as a normal array, but has two indexes.
Let's say you want to create a "table" of 4 x 4. You will need to malloc space for 4 pointers, first. Each of those index points will contain a pointer which references the location in memory where your [sub] array begins (in this case, let's say the first pointer points to the location in memory where your first of four arrays is). Now this array needs to be malloc for 4 "spaces" (in this case, let's assume of type INT). (so array[0] = the first array) If you wanted to set the values 1, 2, 3, 4 within that array, you'd be specifying array[0][0], array[0][1], array[0][2], array[0][3]. This would then be repeated for the other 3 arrays that create this table.
Hope this helps!

Manipulating a global array in a recursive function

I'm working through an algorithms MOOC and have a small program that takes an array A of ints in arbitrary order, counts the number of inversions (an inversion being the number of pairs (i,j) of array indices with i<j and A[i] > A[j]).
Below is the code I've written. I'm trying to tackle it using a "divide and conquer" approach where we recursively split the input array into two halves, sort each half individually while counting the inversions and then merge the two halves.
The trick is I need to keep track of the number of inversions and sort the arrays, so I pass the original array around the various recursive calls as an argument to the function and pass the count of inversions as a return value.
The code executes correctly through the first set of recursive calls that successively divide and sort [1,5,3], however when I get to the 3rd invocation of mergeAndCountSplitInv it crashes at the line:
sortedArrayLeft = realloc(sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
with the error:
malloc: *** error for object 0x100103abc: pointer being realloc'd was not allocated
I can't see where I'm not using malloc correctly and I've combed through this checking to see I'm doing the pointer arithmetic correctly and can't spot any errors, but clearly error(s) exist.
Any help is appreciated.
// main.c
// inversionInC
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// function to help with debugging array/pointer arithmetic
void logArrayLenAndContents (char *arrayName, int arrayToPrint[], int arrayLen){
printf("%s\n", arrayName);
printf("len:%d\n", arrayLen);
for (int idx = 0; idx < arrayLen; idx++) {
printf("array[%d]: %d\n", idx, arrayToPrint[idx]);
}
}
int mergeAndCountSplitInv(int sortedArrayLeft[], int leftLen, int sortedArrayRight[], int rightLen)
{
printf("Calling mergeAndCount with sortedArrayLeft:\n");
logArrayLenAndContents("left Array", sortedArrayLeft, leftLen);
printf("...and sortedArrayRight:\n");
logArrayLenAndContents("right Array", sortedArrayRight, rightLen);
int i = 0;
int j = 0;
int k = 0;
int v = 0; // num of split inversions
int* outArray;
outArray = malloc((leftLen + rightLen) * sizeof(int));
while (i < leftLen && j < rightLen) {
if (sortedArrayLeft[i] < sortedArrayRight[j]) {
outArray[k] = sortedArrayLeft[i];
i++;
} else{
outArray[k] = sortedArrayRight[j];
v += leftLen - i;
j++;
}
k++;
}
// if at the end of either array then append the remaining elements
if (i < leftLen) {
while (i < leftLen) {
outArray[k] = sortedArrayLeft[i];
i++;
k++;
}
}
if (j < rightLen) {
while (j < rightLen) {
outArray[k] = sortedArrayRight[j];
j++;
k++;
}
}
printf("Wrapping up mergeAndCount where outArray contains:\n");
logArrayLenAndContents("outArray", outArray, k);
sortedArrayLeft = realloc(sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
return v;
}
int sortAndCount(int inArray[], int inLen){
printf("Calling sortAndCount with:\n");
logArrayLenAndContents("inArray", inArray, inLen);
if (inLen < 2) {
return 0;
}
int inArrayLenPart1 = ceil(inLen/2.0);
int inArrayLenPart2 = inLen - inArrayLenPart1;
int* rightArray = malloc(sizeof(int) * inArrayLenPart2);
rightArray = &inArray[inArrayLenPart1];
int x = sortAndCount(inArray, inArrayLenPart1);
printf("sortAndCount returned x = %d\n\n", x);
int y = sortAndCount(rightArray, inArrayLenPart2);
printf("sortAndCount returned y = %d\n\n", y);
int z = mergeAndCountSplitInv(inArray, inArrayLenPart1, rightArray, inArrayLenPart2);
printf("mergeAndCount returned z = %d\n", z);
return x+y+z;
}
int main(int argc, const char * argv[])
{
static int* testArray;
testArray = malloc(5 * sizeof(int));
for (int i = 0; i<=4; i++) {
testArray[0] = 1;
testArray[1] = 5;
testArray[2] = 3;
testArray[3] = 2;
testArray[4] = 4;
}
int x = sortAndCount(testArray, 5);
printf("x = %d\n", x);
return 0;
}
This happens because the value of sortedArrayLeft gets lost as soon as the function returns. The realocated value does not make it to the caller, so inArray of the sortAndCount may be pointing to freed memory if realloc needs to reallocate and copy.
In order to fix this, pass a pointer to the pointer, letting sortedArrayLeft to propagate back to inArray of sortAndCount:
int mergeAndCountSplitInv(int **sortedArrayLeft, int leftLen, int sortedArrayRight[], int rightLen) {
...
*sortedArrayLeft = realloc(*sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
return v;
}
...
int sortAndCount(int **inArray, int inLen) {
...
int z = mergeAndCountSplitInv(inArray, inArrayLenPart1, rightArray, inArrayLenPart2);
}
...
int x = sortAndCount(&testArray, 5);

Resources