Order array of struct by one chosen attribute in C - c

I'm having trouble while ordering an array of a struct that contains 3 infos types. I want to order using one of the info, then organize the other 2 infos, but I'm using heapsort and don't know how I would change the code to automatically reorganize. There is any logical hint that would help me? here's the struct
typedef struct{
int orig;
int dest;
float cost;
}infos;
thanks. i can add any info that help you people help me!
[EDIT]
void build ( Armaz x[], int n ){
int i;
float val;
int s;
int f;
for (i = 1; i<n; i++){
val = x[i].cost;
s = i;
f = (s-1)/2;
while (s>0 && x[f].cost<val){
x[s].cost = x[f].cost;
s = f;
f = (s-1) / 2;
}
x[s].cost = val;
}
}
void heapsort (infos x[], int n){
build(x,n);
int i;
int s;
int f;
float vali ;
for (i = n - 1 ; i > 0 ; i--){
vali = x[i].cost;
x[i].cost = x[0].cost;
f = 0 ;
if (i == 1){
s = -1;
}
else s = 1;
if ( i > 2 && x[2].cost > x[1].cost) s = 2 ;
while ( s >= 0 && vali < x[s].cost){
x[f].cost = x[s].cost;
f = s;
s = 2 * f + 1;
if ( s + 1 <= i - 1 && x[s].cost < x[s + 1].cost ) s++;
if (s > i-1) s = -1;
}
x[f].cost = vali;
}
}

Even if you implement your own sorting functions, I recommend you take a closer look at how the standard qsort function works.
In short: It has an argument that is a pointer to a function used for comparison. That function receives pointers to two "objects" that should be compared, and can do whatever it wants to compare the two "objects". That means one could have three different comparison functions, one for each member of your structure, and pass the appropriate one when needed.

Related

Problem organizing a data set chronologically

I'm here asking for your help, not because I have an error, but simply because of this solution that in my head seemed quite credible despite not working.
I basically have a structure to make an appointment and I created a variable of this temporary structure to change the values ​​so that they are in ascending order, however when I show the query table in this case, but the queries appear in the order I registered them in the program.
My Struct:
typedef struct Consulta {
char nomeUtente[70];
int numSNS;
int dia;
int mes;
int ano;
int horasInicio;
int minutosInicio;
int horasFim;
int minutosFim;
} consulta;
My function that should order the values:
void organizarAgenda(int membroEscolhido, consulta agenda[][50][50], int clinicaSelecionada, int *nFuncionarios, int *nAgendas)
{
int i, j;
boolean substituir;
consulta temp;
for (i = 0; i < nAgendas[membroEscolhido]; i++)
{
for (j = 0; j < nAgendas[membroEscolhido]; j++)
if (agenda[j][membroEscolhido][clinicaSelecionada].ano > agenda[i][membroEscolhido][clinicaSelecionada].ano)
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes > agenda[i][membroEscolhido][clinicaSelecionada].mes))
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes == agenda[i][membroEscolhido][clinicaSelecionada].mes)
&& (agenda[j][membroEscolhido][clinicaSelecionada].dia > agenda[i][membroEscolhido][clinicaSelecionada].dia))
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes == agenda[i][membroEscolhido][clinicaSelecionada].mes)
&& (agenda[j][membroEscolhido][clinicaSelecionada].dia == agenda[i][membroEscolhido][clinicaSelecionada].dia
&& agenda[j][membroEscolhido][clinicaSelecionada].horasInicio >= agenda[i][membroEscolhido][clinicaSelecionada].horasInicio))
substituir = true;
if (substituir == true)
{
//Igualar a variavel temporario á variável agenda em i
temp.ano = agenda[i][membroEscolhido][clinicaSelecionada].ano;
temp.mes = agenda[i][membroEscolhido][clinicaSelecionada].mes;
temp.dia = agenda[i][membroEscolhido][clinicaSelecionada].dia;
temp.horasInicio = agenda[i][membroEscolhido][clinicaSelecionada].horasInicio;
temp.minutosInicio = agenda[i][membroEscolhido][clinicaSelecionada].minutosInicio;
temp.horasFim = agenda[i][membroEscolhido][clinicaSelecionada].horasFim;
temp.minutosFim = agenda[i][membroEscolhido][clinicaSelecionada].minutosFim;
//Igualar a variável agenda em i á variável agenda em j
agenda[i][membroEscolhido][clinicaSelecionada].ano = agenda[j][membroEscolhido][clinicaSelecionada].ano;
agenda[i][membroEscolhido][clinicaSelecionada].mes = agenda[j][membroEscolhido][clinicaSelecionada].mes;
agenda[i][membroEscolhido][clinicaSelecionada].dia = agenda[j][membroEscolhido][clinicaSelecionada].dia;
agenda[i][membroEscolhido][clinicaSelecionada].horasInicio = agenda[j][membroEscolhido][clinicaSelecionada].horasInicio;
agenda[i][membroEscolhido][clinicaSelecionada].minutosInicio = agenda[j][membroEscolhido][clinicaSelecionada].minutosInicio;
agenda[i][membroEscolhido][clinicaSelecionada].horasFim = agenda[j][membroEscolhido][clinicaSelecionada].horasFim;
agenda[i][membroEscolhido][clinicaSelecionada].minutosFim = agenda[j][membroEscolhido][clinicaSelecionada].minutosFim;
//Igualar a variável agenda em j á variavel temporaria
agenda[j][membroEscolhido][clinicaSelecionada].ano = temp.ano;
agenda[j][membroEscolhido][clinicaSelecionada].mes = temp.mes;
agenda[j][membroEscolhido][clinicaSelecionada].dia = temp.dia;
agenda[j][membroEscolhido][clinicaSelecionada].horasInicio = temp.horasInicio;
agenda[j][membroEscolhido][clinicaSelecionada].minutosInicio = temp.minutosInicio;
agenda[j][membroEscolhido][clinicaSelecionada].horasFim = temp.horasFim;
agenda[j][membroEscolhido][clinicaSelecionada].minutosFim = temp.minutosFim;
}
}
Thank you all in advance!
substituir is unitialized. You need to set it to false immediately after the for statement for j.
Your for loop for j is missing a trailing { so it will only iterate over the first if and not the others [as you would probably like]
As I mentioned in my comment, simplify [please ;-)]. Use pointers to simplify the code.
Your indexing is quite complex, so I can only guess at things.
I changed the comparison logic to something I understand.
Here's a simplified version. I just coded it, so it may not compile. But, it should give you some ideas how to proceed:
typedef struct Consulta {
char nomeUtente[70];
int numSNS;
int dia;
int mes;
int ano;
int horasInicio;
int minutosInicio;
int horasFim;
int minutosFim;
} consulta;
void
organizarAgenda(int membroEscolhido, consulta agenda[][50][50],
int clinicaSelecionada, int *nFuncionarios, int *nAgendas)
{
int i;
int j;
int lim = nAgendas[membroEscolhido];
int dif;
consulta temp;
for (i = 0; i < lim; i++) {
consulta *iptr = &agenda[i][membroEscolhido][clinicaSelecionada];
for (j = 0; j < lim; j++) {
consulta *jptr = &agenda[j][membroEscolhido][clinicaSelecionada];
do {
dif = iptr->ano - jptr->ano;
if (dif)
break;
dif = iptr->mes - jptr->mes;
if (dif)
break;
dif = iptr->dia - jptr->dia;
if (dif)
break;
} while (0);
if (dif <= 0)
continue;
temp = *iptr;
*iptr = *jptr;
*jptr = temp;
}
}
}
I'm [still] guessing but I think you can get a [significant] speedup by changing the for loop for j.
And, I think the for loop for i goes one too far.
So, consider:
for (i = 0; i < (lim - 1); i++) {
consulta *iptr = &agenda[i][membroEscolhido][clinicaSelecionada];
for (j = i + 1; j < lim; j++) {
consulta *jptr = &agenda[j][membroEscolhido][clinicaSelecionada];
UPDATE:
I didn't understand how a 3d array with only a 2d array assignment works int lim = nAgendas[membroEscolhido];
The value of nAgendas[membroEscolhido] is invariant across the function, so it can be "cached". I did this to simplify the code [mostly] but it also can help the compiler generate more efficient code.
I didn't notice the (-) in the middle of this line, and the -> works because it is a pointer pointing to the struct, right?
Right. The arrow operator (->) is a very powerful way to access individual struct members if you have a pointer to the given struct instance.
Note that the compiler's optimizer might be able to see that all the variables of the form: array[x][y][z].whatever could be reduced.
But, when we use intermediate pointers we're giving it a [better] clue as to what we want. And, the code is more readable by humans, so it has two good reasons to do it.
I don't understand why you put while (0)
This is a bit of a trick [of mine] to replace an if/else ladder with something that is cleaner.
It forms a "once through" loop. It would be the equivalent of:
while (1) {
if (something)
break;
if (something_else)
break;
break; // make the loop execute _only_ once
}
For a more detailed explanation, see my answer: About the exclusiveness of the cases of an if block

Segmentation Fault when returning integer

I recently joined Stackoverflow community because I had to ask this question. I've been searching for possible explanations and solutions on the website but so far nothing enlightened me as I wanted. My error is probably caused by a very specific line of code. I'm trying to create a function that reads an array of struct votes, (struct contains integer member number, char *category, char *nominee) and copies all the votes that contain the same number and category to another array of struct. Basically to show all the repeated votes.
typedef struct
{
int member;
char *categ;
char *nom;
}Vote
Vote vote(int member, char *categ, char *nom)
{
Vote result;
result.member = member;
result.categ = categ;
result.nom = nom;
return result;
}
int votes_count(Vote *v, int n, Vote *v1)
{
int result = 0;
int *index = malloc(sizeof(int) * 1000);
int a = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (a == 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0)
{
v1[result++] = vote(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
for (int b = 0; b < a; ++b)
{
if( a > 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0 && j != index[b])
{
v1[result++] = voto(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
}
}
}
return result;
}
Afterwads, it returns the number of elements of new array that contains all repetitions. I want to use an array of ints to save all line indexes so that the function doesn't read and copy the lines it already accounted.
Sorry if the code is hard to understand, if needed I can edit to be more understandable. Thanks for any answears.
P.S: I'm portuguese, sorry in advance for grammar mistakes
if your only intention is to harvest the duplicates, you only need to compare to the elements that came before an element
you don't need the index[] array
For simplicity, I used two integer arrays, you should change them to your struct arrays, also change the compare function.
unsigned fetchdups(int orig[], int dups[], unsigned count)
{
unsigned this, that, ndup=0;
for (this=1; this<count; this++){
for (that=0; that<this; that++){
/* change this to your compare() */
if(orig[that] == orig[this]) break;
}
if (this == that) continue; /* no duplicate */
dups[ndup++] = this;
}
return ndup;
}

Multiplying large numbers through strings

I'm trying to write a program that will receive 2 strings representing numbers of any length
(for instance, char *a = "10000000000000";, char *b = "9999999999999999";) and multiply them.
This is what I came up with so far, not sure how to continue (nullify simply fills the whole string with '0'):
char *multiply(char *hnum, const char *other)
{
int num1=0, num2=0, carry=0, hnumL=0, otherL=0, i=0, temp1L=0, temp2L=0, n=0;
char *temp1, *temp2;
if(!hnum || !other) return NULL;
for(hnumL=0; hnum[hnumL] != '\0'; hnumL++);
for(otherL=0; other[otherL] != '\0'; otherL++);
temp1 = (char*)malloc(otherL+hnumL);
if(!temp1) return NULL;
temp2 = (char*)malloc(otherL+hnumL);
if(!temp2) return NULL;
nullify(temp1);
nullify(temp2);
hnumL--;
otherL--;
for(otherL; otherL >= 0; otherL--)
{
carry = 0;
num1 = other[otherL] - '0';
for(hnumL; hnumL >= 0; hnumL--)
{
num2 = hnum[hnumL] - '0';
temp1[i+n] = (char)(((int)'0') + ((num1 * num2 + carry) % 10));
carry = (num1 * num2 + carry) / 10;
i++;
temp1L++;
}
if(carry > 0)
{
temp1[i+n] = (char)(((int)'0') + carry);
temp1L++;
}
p.s. Is there a library that handles this already? Couldn't find anything like it.
On paper, you would probably do as follows:
999x99
--------
8991
8991
========
98901
The process is to multiply individual digits starting from the right of each number and adding them up keeping a carry in mind each time ("9 times 9 equals 81, write 1, keep 8 in mind"). I'm pretty sure you covered that in elementary school, didn't you?.
The process can be easily put into an algorithm:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct result
{
int carry;
int res;
};
/*
* multiply two numbers between 0 and 9 into result.res. If there is a carry, put it into
* result.carry
*/
struct result mul(int a, int b)
{
struct result res;
res.res = a * b;
if (res.res > 9)
{
res.carry = res.res / 10;
res.res %= 10;
}
else
res.carry = 0;
return res;
}
/*
* add
* adds a digit (b) to str at pos. If the result generates a carry,
* it's added also (recursively)
*/
add(char str[], int pos, int b)
{
int res;
int carry;
res = str[pos] - '0' + b;
if (res > 9)
{
carry = res / 10;
res %= 10;
add(str, pos - 1, carry);
}
str[pos] = res + '0';
}
void nullify(char *numstr, int len)
{
while (--len >= 0)
numstr[len] = '0';
}
int main(void)
{
struct result res;
char *mp1 = "999";
char *mp2 = "999";
char sum[strlen(mp1) + strlen(mp2) + 1];
int i;
int j;
nullify(sum, strlen(mp1) + strlen(mp2));
for (i = strlen(mp2) - 1; i >= 0; i--)
{
/* iterate from right over second multiplikand */
for (j = strlen(mp1) - 1; j >= 0; j--)
{
/* iterate from right over first multiplikand */
res = mul((mp2[i] - '0'), (mp1[j] - '0'));
add(sum, i + j + 1, res.res); /* add sum */
add(sum, i + j, res.carry); /* add carry */
}
}
printf("%s * %s = %s\n", mp1, mp2, sum);
return 0;
}
This is just the same as on paper, except that you don't need to remember individual summands since we add up everything on the fly.
This might not bee the fastest way to do it, but it doesn't need malloc() (provided you have a C99 compiler, otherwise you would need to dynamically allocate sum) and works for arbitrarily long numbers (up to the stack limit since add() is implemented as recursive function).
Yes there are libraries that handle this. It's actually a pretty big subject area that a lot of research has gone into. I haven't looked through your code that closely, but I know that the library implementations of big num operations have very efficient algorithms that you're unlikely to discover on your own. FOr example, the multiplication routine we all learned in grade school (pre common-core) is a O(n^2) solution to multiplication, but there exist ways to solve it in ~O(n^1.5).
THe standard GNU c big num library is GNU MP
https://gmplib.org/

How to sort a group of structures in C

I made a 4 variables structures and assigned values just to age.
struct database {
int id_number;
int age;
float salary;
};
main()
{
struct database employee[4];
struct database current; // Used later in my attempted sorting
employee[1].age = 12;
employee[2].age = 112;
employee[3].age = 2;
employee[4].age = 22;
I tried various ways to attempt to sort these but all failed,
for example:
for(i = 0; i < 4; i++)
{
current = employee[i];//"current" was previously assigned to the same type of struct
j = i;
while(employee[j-1].age > current.age)
{
employee[j] = employee[j-1];
j = j-1;
}
employee[j] = current;
}
Many errors, as pointed by others in comments.
(Out of bound array access, sorting algorithm is not correct, etc. )
For sorting array of struct, simplest way would be to use qsort
where you need to define a custom comparator, something like following :
typedef struct database db;
int sort_by_age(void *a, void *b)
{
db *_a = (db *)a;
db *_b = (db *)b;
if( _a->age > _b->age ) return -1;
if( _a->age == _b->age ) return 0;
return 1;
}
And then use it like,
int no_of_employee = 4;
qsort( employee, no_of_employee, sizeof(db), sort_by_age );

What is the ideal way to make a unique list of values in C?

Say we have
typedef struct {
int value1;
int value2;
} values_t;
and
values_t* values;
is filled with values[i].value1 and values[i].value2 pairs that may or may not be unique.
and we want to fill
values_t* values_unique;
only with unique pairs from values, in the order they first appear in values.
What is the ideal way to do this in C?
EDIT: Assume they are properly malloced pointers; above is just pseudo code.
You probably use a hash of the values, maintaining a list of the hashes and the corresponding values, and only add a new pair to the values_unique array (which the question does originally did not declare as an array) if it is not found via the hash. If the list is large, the speed up from hashing instead of searching through the entire list sequentially can be quite significant.
It'll be something like this (Haven't been coding in C for long time, and code isn't tested):
#include<stdlib.h>
#include<stdio.h>
typedef struct {
int value1;
int value2;
} values_t;
values_t* values;
size_t values_size = 100;
values_t* values_unique;
size_t values_unique_size;
int valcmp(const values_t* a, const values_t* b)
{
//a < b -> -1
//a == b -> 0
//a > b -> 1
return (a->value1 == b->value1) ? ((a->value2 == b->value2) ? 0 : ((a->value2 < b->value2) ? -1 : 1)) : ((a->value1 < b->value1) ? -1 : 1);
}
int main(void)
{
values = malloc(values_size * sizeof(values_t));
values_unique = malloc(values_size * sizeof(values_t));
//fill the values table
memcpy(values_unique, values, values_size * sizeof(values_t));
qsort(values_unique, values_size, sizeof(values_t), valcmp);
int i;
//hopefully values_size > 0
for(i = 1, values_unique_size = 1; i < values_size; ++i)
if(valcmp(&values_unique[i], &values_unique[values_unique_size - 1]) != 0)
values_unique[values_unique_size] = values_unique[i];
}
Same in c++:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
vector<pair<int,int> > V, V_unique;
int main()
{
V_unique = V;
sort(V_unique.begin(), V_unique.end());
V_unique.resize(unique(V_unique.begin(), V_unique.end()) - V_unique.begin());
}
I know it's fairly annoying to suggest a different language but using C++ stl would be trivial.
set<values_t> mySet();
for(int i=0; i < number_of_values; i++)
{
mySet.insert(values[i]);
}
values_t * values_unique = new values_t[mySet.size()];
int j=0;
for(set<values_t>::iterator i = mySet.begin(); mySet.end() != i; i++)
{
values_unique[j] = *i;
j++
}

Resources