Kruskal alghoritm - working but difficult - c

I was working on Kruskal algorithm that will read input and based on this information it will find the shortest path between every two nodes.
Let me explain:
There are numbers on the input, for example:
7 6 1 5
1 7 20
7 2 5
2 3 9
4 2 4
5 2 7
6 5 3
On the first line there are 4 numbers = number of nodes, number of edges, beginning node (where to start), end node (where to end).
On the rest of lines are 3 numbers = one node(lets say x), second node(y), length between them.
The input will give me shortest path between the start and end node.
In this example case it would be number 32.
I have a fully working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct edge{
int goal, length;
struct edge *p_next;
} EDGE;
typedef struct node{
int name;
EDGE *p_edges, *last;
} NODE;
int helper;
int getDist(int size, NODE *nodes[size+1], int from, int act, int goal)
{
EDGE *p_act;
for(p_act = nodes[act]->p_edges; p_act != 0; p_act = p_act->p_next)
{
if (p_act->goal == goal)
{
return p_act->length;
}
if (p_act->goal != from)
{
helper = getDist(size, nodes, act, p_act->goal, goal);
}
if (helper != 0)
{
return helper + p_act->length;
}
}
return 0;
}
int main()
{
int numV, numH, start, goal, i, length, a, b;
EDGE *p_newEdge, *p_newEdge2;
scanf("%d %d %d %d", &numV , &numH, &start, &goal);
NODE *nodes [numV+1];
for(i = 0; i <= numV; i++)
{
nodes[i] = (NODE*)malloc(sizeof(NODE));
}
for(i = 0; i < numH; i++)
{
scanf("%d %d %d",&a,&b,&length);
p_newEdge = (EDGE*)malloc(sizeof(EDGE));
p_newEdge->length = length;
p_newEdge->goal = b;
p_newEdge2 = (EDGE*)malloc(sizeof(EDGE));
p_newEdge2->length = length;
p_newEdge2->goal = a;
if (nodes[a]->p_edges == 0)
{
nodes[a]->p_edges = p_newEdge;
nodes[a]->last = p_newEdge;
}
else if (nodes[a]->p_edges != 0)
{
nodes[a]->last->p_next = p_newEdge;
nodes[a]->last = nodes[a]->last->p_next;
}
if (nodes[b]->p_edges != 0)
{
nodes[b]->last->p_next = p_newEdge2;
nodes[b]->last = nodes[b]->last->p_next;
}
else if (nodes[b]->p_edges == 0)
{
nodes[b]->p_edges = p_newEdge2;
nodes[b]->last = p_newEdge2;
}
}
printf("%d\n",getDist(numV ,nodes, 0, start, goal));
return 0;
}
But my professor told me that it is very long and I should make it more simple (this was my third attempt and for my professor it is still too long and "complex").
I have no idea how to make it more simple.
Can someone help me with this?

Related

Pthread data race that drives me crazy

I posted a similar question to this one a few weeks ago where I had trouble finding the data race in my N-queens program using pthreads in C. Why is my multithreaded C program not working on macOS, but completely fine on Linux?
I got a few suggestions in the comments sections of the post and I really tried my best to make corrections based on them. I sat with the suggestions a few days, changed some parts but the data race persisted and I just cannot understand why. There are counters inside critical sections for the number of productions and consumptions. I feel completely blind when looking through the code and analyzing it, I'm aware that consumptions are too many but the synchronization around that code fragment should with my knowledge be correct, but obviously something's not right. External input would be greatly appreciated.
This is the code I'm using and I'm not sure how to reduce its size to still reproduce the issue. I compile it with gcc (clang-1205.0.22.11) on macOS Monterey (12.1) using a MacBook Pro 2020 x86_64 architecture.
compile: gcc -o 8q 8q.c*
run: ./8q <consumers> <N>, NxN chess board, N queens to place
parameters: ./8q 2 4 Enough to highlight the problem (should yield 2 solutions, but every other run yields 3+ solutions, i.e duplicate solutions exist
note: running the program with ./8q 2 4 should give 2 solutions, 1820 productions and 1820 consumptions.
#ifndef _REENTRANT
#define _REENTRANT
#endif
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
typedef struct stack_buf {
int positions[8];
int top;
} stack_buf;
typedef struct global_buf {
int positions[8];
int buf_empty;
long prod_done;
int last_done;
} global_buf;
typedef struct print_buf {
int qpositions[100][8];
int top;
} print_buf;
stack_buf queen_comb = { {0}, 0 };
print_buf printouts = { {{0}}, 0 };
global_buf global = { {0}, 1, 0, 0 };
int N; //NxN board and N queens to place
long productions = 0;
long consumptions = 0;
pthread_mutex_t buffer_mutex, print_mutex;
pthread_cond_t empty, filled;
/* ##########################################################################################
################################## VALIDATION FUNCTIONS ##################################
########################################################################################## */
/* Validate that no queens are placed on the same row */
int valid_rows(int qpositions[]) {
int rows[N];
memset(rows, 0, N*sizeof(int));
int row;
for (int i = 0; i < N; i++) {
row = qpositions[i] / N;
if (rows[row] == 0) rows[row] = 1;
else return 0;
}
return 1;
}
/* Validate that no queens are placed in the same column */
int valid_columns(int qpositions[]) {
int columns[N];
memset(columns, 0, N*sizeof(int));
int column;
for (int i = 0; i < N; i++) {
column = qpositions[i] % N;
if (columns[column] == 0) columns[column] = 1;
else return 0;
}
return 1;
}
/* Validate that left and right diagonals aren't used by another queen */
int valid_diagonals(int qpositions[]) {
int left_bottom_diagonals[N];
int right_bottom_diagonals[N];
int row, col, temp_col, temp_row, fill_value, index;
for (int queen = 0; queen < N; queen++) {
row = qpositions[queen] / N;
col = qpositions[queen] % N;
/* position --> left down diagonal endpoint (index) */
fill_value = col < row ? col : row; // closest to bottom or left wall
temp_row = row - fill_value;
temp_col = col - fill_value;
index = temp_row * N + temp_col; // board position
for (int i = 0; i < queen; i++) { // check if interference occurs
if (left_bottom_diagonals[i] == index) return 0;
}
left_bottom_diagonals[queen] = index; // no interference
/* position --> right down diagonal endpoint (index) */
fill_value = (N-1) - col < row ? N - col - 1 : row; // closest to bottom or right wall
temp_row = row - fill_value;
temp_col = col + fill_value;
index = temp_row * N + temp_col; // board position
for (int i = 0; i < queen; i++) { // check if interference occurs
if (right_bottom_diagonals[i] == index) return 0;
}
right_bottom_diagonals[queen] = index; // no interference
}
return 1;
}
/* ##########################################################################################
#################################### HELPER FUNCTION(S) ####################################
########################################################################################## */
/* print the collected solutions */
void print(print_buf printouts) {
static int solution_number = 1;
int placement;
pthread_mutex_lock(&print_mutex);
for (int sol = 0; sol < printouts.top; sol++) { // all solutions
printf("Solution %d: [ ", solution_number++);
for (int pos = 0; pos < N; pos++) {
printf("%d ", printouts.qpositions[sol][pos]+1);
}
printf("]\n");
printf("Placement:\n");
for (int i = 1; i <= N; i++) { // rows
printf("[ ");
placement = printouts.qpositions[sol][N-i];
for (int j = (N-i)*N; j < (N-i)*N+N; j++) { // physical position
if (j == placement) {
printf(" Q ");
} else printf("%2d ", j+1);
}
printf("]\n");
}
printf("\n");
}
pthread_mutex_unlock(&print_mutex);
}
/* ##########################################################################################
#################################### THREAD FUNCTIONS ####################################
########################################################################################## */
/* entry point for each worker (consumer) workers will
check each queen's row, column and diagonal to evaluate
satisfactory placements */
void *eval_positioning(void *id) {
long thr_id = (long)id;
int qpositions[N]; // on stack (thread-private)
while (1) {
pthread_mutex_lock(&buffer_mutex);
while (global.buf_empty == 1) { // no element
if (global.last_done) { // last done, no combinations left
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_signal(&filled);
return NULL;
}
if (global.prod_done) {
global.last_done = 1;
break;
}
pthread_cond_wait(&filled, &buffer_mutex);
}
memcpy(qpositions, global.positions, N*sizeof(int)); // copy to local scope
global.buf_empty = 1;
consumptions++;
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_signal(&empty);
if (valid_rows(qpositions) && valid_columns(qpositions) && valid_diagonals(qpositions)) {
pthread_mutex_lock(&print_mutex);
memcpy(printouts.qpositions[printouts.top], qpositions, N*sizeof(int)); /* save for printing later */
printouts.top++;
pthread_mutex_unlock(&print_mutex);
}
}
return NULL;
}
/* recursively generate all possible queen_combs */
void rec_positions(int pos, int queens) {
if (queens == 0) { // base case
pthread_mutex_lock(&buffer_mutex);
while (global.buf_empty == 0) { // while production hasn't been consumed
pthread_cond_wait(&empty, &buffer_mutex);
}
memcpy(global.positions, queen_comb.positions, N*sizeof(int));
productions++;
global.buf_empty = 0;
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_signal(&filled);
return;
}
for (int i = pos; i <= N*N - queens; i++) {
queen_comb.positions[queen_comb.top++] = i;
rec_positions(i+1, queens-1);
queen_comb.top--;
}
}
/* binomial coefficient | without order, without replacement
8 queens on 8x8 board: 4'426'165'368 queen combinations */
void *generate_positions(void *arg) {
rec_positions(0, N);
pthread_mutex_lock(&buffer_mutex);
global.prod_done = 1;
pthread_mutex_unlock(&buffer_mutex);
pthread_cond_broadcast(&filled); //wake all to
return NULL;
}
/* ##########################################################################################
########################################## MAIN ##########################################
########################################################################################## */
/* main procedure of the program */
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("usage: ./8q <workers> <board width/height>\n");
exit(1);
}
int workers = atoi(argv[1]);
N = atoi(argv[2]);
if (N < 2 || N > 8) {
printf("Wrong input! 2 <= N <= 8\n");
return 0;
}
struct timeval start, stop;
double elapsed;
pthread_t consumers[workers];
pthread_t producer;
printf("\n");
gettimeofday(&start, NULL);
pthread_create(&producer, NULL, generate_positions, NULL);
for (long i = 0; i < workers; i++) {
pthread_create(&consumers[i], NULL, eval_positioning, (void*)i+1);
}
pthread_join(producer, NULL);
for (int i = 0; i < workers; i++) {
pthread_join(consumers[i], NULL);
char id[2];
sprintf(id, "%d", i+1);
write(1, id, strlen(id));
write(1, " done\n\n", 6);
}
gettimeofday(&stop, NULL);
elapsed = stop.tv_sec - start.tv_sec;
elapsed += (stop.tv_usec - start.tv_usec) / (double)1000000;
/* go through all valid solutions and print */
print(printouts);
printf("board: %dx%d, workers: %d (+1), exec time: %fs, solutions: %d\n", N, N, workers, elapsed, printouts.top);
printf("productions: %ld\nconsumptions: %ld\n", productions, consumptions);
return 0;
}
You're not initializing your mutexes and condition variables. The result is UB when used in pthread APIs. Two ways to do this, the simplest is just use the proper initializer:
pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t filled = PTHREAD_COND_INITIALIZER;
Unrelated, but worth mentioning, the last_done ideology is not necessary. This can be done with just the buf_empty and prod_done states. Specifically:
void *eval_positioning(void *tid)
{
int qpositions[N]; // on stack (thread-private)
while (1)
{
pthread_mutex_lock(&buffer_mutex);
// while still producing *and* the buffer is empty
while (!global.prod_done && global.buf_empty)
pthread_cond_wait(&filled, &buffer_mutex);
// if both are true, we're done. nothing to process, and
// there never will be (e.g. prod_done)
if (global.prod_done && global.buf_empty)
{
// signal anyone else waiting on that mutex+cvar
pthread_cond_signal(&filled);
break;
}
// if we have a buffer to process (even if prod_done is true)
else if (!global.buf_empty)
{
// make local copy of buffer
memcpy(qpositions, global.positions, sizeof qpositions);
++consumptions;
// mark global buffer as ready-to-receive
global.buf_empty = 1;
pthread_cond_signal(&empty);
pthread_mutex_unlock(&buffer_mutex);
// if validated...
if (valid_rows(qpositions) && valid_columns(qpositions) && valid_diagonals(qpositions))
{
// record and bump the printout counter.
pthread_mutex_lock(&print_mutex);
int row = printouts.top++;
pthread_mutex_unlock(&print_mutex);
// this need not be protected by the mutex. we "own"
// this now, and can just blast away.
memcpy(printouts.qpositions[row], qpositions, sizeof qpositions);
}
}
else
{
pthread_mutex_unlock(&buffer_mutex);
}
}
// make sure we unlock this
pthread_mutex_unlock(&buffer_mutex);
return tid;
}
With proper initialization of the concurrency materials, and the above eval processor, this is the consistent output:
Output
1 done
2 done
Solution 1: [ 2 8 9 15 ]
Placement:
[ 13 14 Q 16 ]
[ Q 10 11 12 ]
[ 5 6 7 Q ]
[ 1 Q 3 4 ]
Solution 2: [ 3 5 12 14 ]
Placement:
[ 13 Q 15 16 ]
[ 9 10 11 Q ]
[ Q 6 7 8 ]
[ 1 2 Q 4 ]
board: 4x4, workers: 2 (+1), exec time: 0.013001s, solutions: 2
productions: 1820
consumptions: 1820
Apologies for the puny laptop performance numbers

BST and Linked List C program stuck at large values

I'm doing a college work where the professor asked us to implement BST and linked list and count how many comparisons it makes to insert and search a large amount of randomly-generated values. We're supposed to start at 10 values, then 100, then 1000, up until 10^12. The thing is, it always gets stuck at 100000 (10^5). The RAM usage is low, but CPU is at max. I'm freeing both the tree and lists after each step. The code is found here (offsite) and below.
Just to sum up some important points: each value (the key to the node) is an unsigned it (max 65535), but up to 10^12 values should be inserted and another 10^12 searched.
Is it supposed to take this long? My processor is an i5-7200u
Is there a chance it's a memory problem and GCC is blocking it somehow?
Thanks a lot
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef long long ll;
typedef unsigned long long ull;
// BST
typedef struct no_A_struct {
unsigned int chave;
struct no_A_struct *esquerda;
struct no_A_struct *direita;
} no_A;
// new node
no_A *novo_no_A(unsigned int chave) {
no_A *no = (no_A *) malloc(sizeof(no_A));
no->chave = chave;
no->esquerda = no->direita = NULL;
return no;
}
// insert note
no_A *insere_A(no_A *raiz, unsigned int chave, ull *cont) {
(*cont)++; if (raiz == NULL) return novo_no_A(chave);
(*cont)++; if (chave < raiz->chave) raiz->esquerda = insere_A(raiz->esquerda, chave, cont);
else {
(*cont)++; if (chave > raiz->chave) raiz->direita = insere_A(raiz->direita, chave, cont);
}
return raiz;
}
// search node
no_A *busca_A(no_A *raiz, unsigned int chave, ull *cont) {
(*cont)++; if (raiz == NULL) return NULL;
(*cont)++; if (chave == raiz->chave) return raiz;
(*cont)++; if (chave > raiz->chave) return busca_A(raiz->direita, chave, cont);
return busca_A(raiz->esquerda, chave, cont);
}
// free tree
void desaloca_A(no_A *raiz) { // TODO iterativa?
if (raiz == NULL) return;
desaloca_A(raiz->esquerda);
desaloca_A(raiz->direita);
free(raiz);
}
// LINKED LIST WITH IN ORDER INSERTION
typedef struct no_L_struct {
unsigned int chave;
struct no_L_struct *prox;
} no_L;
// new node
no_L *novo_no_L(unsigned int chave) {
no_L *no = (no_L *) malloc(sizeof(no_L));
no->chave = chave;
no->prox = NULL;
return no;
}
// insert node
void insere_L(no_L **inicio, unsigned int chave, ull *cont) {
no_L *novo_no = novo_no_L(chave);
(*cont)++; if (*inicio == NULL) { *inicio = novo_no; return; }
(*cont)++; if (novo_no->chave <= (*inicio)->chave) {
novo_no->prox = *inicio;
*inicio = novo_no;
} else {
no_L *atual = *inicio;
for (;;) {
(*cont)++; if (atual->prox == NULL) break;
(*cont)++; if (novo_no->chave <= atual->prox->chave) break;
atual = atual->prox;
}
novo_no->prox = atual->prox;
atual->prox = novo_no;
}
}
// search node
no_L *busca_L(no_L *atual, unsigned int chave, ull *cont) {
for (;;) {
(*cont)++; if (atual == NULL) break;
(*cont)++; if (atual->chave == chave) break;
atual = atual->prox;
}
return atual;
}
// void printa_L(no_L *atual) {
// if (atual == NULL) return;
// printf("%u", atual->chave);
// printa_L(atual->prox);
// }
// free list
void desaloca_L(no_L *atual) {
no_L *no_apagar;
while (atual != NULL) {
no_apagar = atual;
atual = atual->prox;
free(no_apagar);
}
}
int main() {
ll QTD_VALORES[] = {10, 100, 1000, // 10^: 1, 2, 3
10000, 100000, 1000000, // 4, 5, 6
1000000000, 10000000000, // 9, 10
100000000000, 1000000000000}; // 11, 12
int ITERACOES = 1; // TODO voltar pra 100
unsigned int VALOR_MAX = 65535;
int tamanho_qtd_valores = sizeof(QTD_VALORES)/sizeof(QTD_VALORES[0]);
srand(time(0));
for (int qtd_i=0; qtd_i<tamanho_qtd_valores; qtd_i++) {
ll qtd = QTD_VALORES[qtd_i];
printf("== QTD DE VALORES %lli ==\n", qtd);
for (int i=0; i<ITERACOES; i++) {
ull comp_A_insercao = 0, comp_A_busca = 0,
comp_L_insercao = 0, comp_L_busca = 0;
no_A *arvore = NULL;
no_L *lista = NULL;
// generates and insert values
unsigned int valores_busca[qtd];
for (ll v=0; v<qtd; v++) {
// // insert values
unsigned int valor_insercao = rand() % VALOR_MAX + 1;
arvore = insere_A(arvore, valor_insercao, &comp_A_insercao);
insere_L(&lista, valor_insercao, &comp_L_insercao);
valores_busca[v] = rand() % VALOR_MAX + 1;
}
// search values
for (ll v=0; v<qtd; v++) {
busca_A(arvore, valores_busca[v], &comp_A_busca);
busca_L(lista, valores_busca[v], &comp_L_busca);
}
// desaloca_A(arvore);
// desaloca_L(lista);
// TODO divisões retornar numero real?
printf("INTERACTION %d: \n", i+1);
printf("Tree insertion, total=%llu, avg=%llu\n", comp_A_insercao,
comp_A_insercao / qtd);
printf("Tree search, total=%llu, avg=%llu\n", comp_A_busca,
comp_A_busca / qtd);
printf("List insertion, total=%llu, avg=%llu\n", comp_L_insercao,
comp_L_insercao / qtd);
printf("List search, total=%llu, avg=%llu\n", comp_L_busca,
comp_L_busca / qtd);
}
printf("\n");
}
}
Are you sure you are supposed to insert items already in the list? I think you're suppose to avoid adding duplicates keys.
Inserting the first node in the linked list will requires 0 comparisons. The second, 1/2 (on avg). The third, 2/2, The fourth 3/2, etc. So inserting N times will have a average time proportional to (0+1+2+...+(N-2)+(N-1))/2 = N*(N-1)/4.
$ perl -e'printf "%d: %d\n", $_, (10**$_)*(10**$_-1)/4 for 1..5;'
1: 22
2: 2475
3: 249750
4: 24997500
5: 2499975000
That's an average time of 2.5 billion time units to insert 105 nodes. For example, if it takes 100 ns per comparison, it will take over 4 minutes to insert 105 nodes on average.
At that same rate, inserting 1012 nodes would take an average of 800 million years.
If, on the other hand, you avoid adding a key that's already in the list, the average time will be no more than 65,536*N/2
$ perl -e'printf "%d: %d\n", $_, 65536*(10**$_-1)/4 for 1..12;'
1: 147456
2: 1622016
3: 16367616
4: 163823616
5: 1638383616
6: 16383983616
7: 163839983616
8: 1638399983616
9: 16383999983616
10: 163839999983616
11: 1638399999983616
12: 16383999999983616
So instead of taking 800 million years, inserting 1012 nodes will take an average of "only" 19 days using the rate assumed above. Even if I'm off by an order of magnitude, we're still talking about 2 days.

How to work out if a member of a struct was set or not?

Say I have the following struct:
struct cube {
int height;
int length;
int width;
};
I need to create a library that allows the user to enter values into the struct and then pass it into a function, which will determine whether the user wants either the area or the volume from the values provided.
For example:
int main() {
struct cube shape;
shape.height = 2;
shape.width = 3;
printf("Area: %d", calculate(shape)); // Prints 6
shape.length = 4;
printf("Volume: %d", calculate(shape)); // Prints 24
return 0;
}
int calculate(struct cube nums) {
if (is_present(nums.height, nums) && is_present(nums.width, nums)) {
return nums.height * nums.width;
}
else if (is_present(nums.height, nums) && is_present(nums.width, nums) && is_present(nums.length, nums)) {
return nums.height * nums.width * nums.length;
}
else {
return -1; // Error
}
}
This should work, if I can use a function (like is_present(), which I just made up) to work out if a value was given to a member of a struct.
Is there such a function and if not, how could this be implemented?
You should initialize your fields to something that is out of the domain of the possible values. For example, for such dimensions, which are positive numbers, a negative value could act as a "not assigned" value.
Also, I reordered your if statements: the one checking for all the fields should be the first.
Here's an example:
#include <stdio.h>
#define NOT_PRESENT -1
#define is_present(x) ((x) != NOT_PRESENT)
struct cube {
int height;
int length;
int width;
};
int calculate(struct cube);
int main() {
struct cube shape = {
.height = NOT_PRESENT,
.length = NOT_PRESENT,
.width = NOT_PRESENT,
};
shape.height = 2;
shape.width = 3;
printf("Area: %d\n", calculate(shape)); // Prints 6
shape.length = 4;
printf("Volume: %d\n", calculate(shape)); // Prints 24
return 0;
}
int calculate(struct cube nums) {
if (is_present(nums.height) && is_present(nums.width) && is_present(nums.length)) {
return nums.height * nums.width * nums.length;
} else if (is_present(nums.height) && is_present(nums.width)) {
return nums.height * nums.width;
} else {
return -1; // Error
}
}
First you have to clearly define what "a value was given" means to your domain. A member initialized to 0 means no value was given?
A simple solution is to initialize your struct with 0 (for example), and just compare each member against it. Example:
struct cube shape = {0};
shape.width = 3;
if (shape.width != 0)
printf("width was set");
Or simpler:
struct cube shape = {2,0,3};
if (shape.width != 0)
printf("width was set");

Algorithm in C - who is the winner team

I need to store data from a tournament. I need to know how many teams will play(n) and the number of games they will play (n!). Then, the team's names and their results. Something like this:
Input:
3 6
TeamX
TeamY
TeamZ
TeamX 0 - TeamY 3
TeamX 1 - TeamZ 0
TeamY 1 - TeamX 0
TeamY 0 - TeamZ 0
TeamZ 0 - TeamX 0
TeamZ 3 - TeamY 1
The output will be something like:
This winner is TeamY, with 7 point(s)
Won 2 game(s), tied 1 game(s) e lost 1 game(s)
Scored 5 goal(s) e suffered 3 goal(s)
EDIT2:
THIS is what I have until now. But it won't work at the scanf.... I can't type the team's names after the number of teams and games. Can you run it and try to understand?
Guide: I have game and team structs, first I add team names to theTeams array of structs, then I add the games to the games array of structs. Then, if/else blocks to do the maths of wins, losses, etc and finally see and printf the winner.
#include <stdio.h>
#include <string.h>
struct game {
const char *teamA;
int scoreA;
const char *teamB;
int scoreB;
};
struct team {
const char *teamA;
int score;
int wins;
int losses;
int ties;
int scored;
int suff;
};
struct team team_new(const char *teamA, int score, int wins, int losses, int ties, int scored, int suff)
{
struct team t;
t.teamA = strdup(teamA);
t.score = score;
t.wins = wins;
t.losses = losses;
t.ties = ties;
t.scored = scored;
t.suff = suff;
return t;
};
struct game game_new(const char *teamA, int scoreA, const char *teamB, int scoreB)
{
struct game g;
g.teamA = strdup(teamA);
g.scoreA = scoreA;
g.teamB = strdup(teamB);
g.scoreB = scoreB;
return g;
};
int main(void)
{
int i, j, teams, nrgames, biggestScore, whichTeam;
scanf("Teams and number of games %d %d", &teams, &nrgames);
//add team names to theTeamss struct
struct team theTeams[teams];
size_t num_teams = 0;
for (i = 0; i < teams; ++i)
{
char teamA[20];
if (scanf("%s", teamA) != 1)
exit(0);
theTeams[++num_teams] = team_new(teamA, 0, 0, 0, 0, 0, 0);
}
struct game games[nrgames]; //add games
size_t num_games = 0;
for (i = 0; i < sizeof games / sizeof *games; ++i)
{
char teamA[20], teamB[20];
int scoreA, scoreB;
if (scanf(" %s %d - %s %d", teamA, &scoreA, teamB, &scoreB) != 4)
exit(0);
games[++num_games] = game_new(teamA, scoreA, teamB, scoreB);
}
//run through games[] to change values of theTeams[] scores
//games - A against B
for (i = 0; i < sizeof games / sizeof *games; ++i)
{
for (j = 0; j < sizeof theTeams / sizeof *theTeams; ++j)
{
if ((games[i].teamA == theTeams[j].teamA)) //team(A)
{
//if A wins
if(games[i].scoreA > games[i].scoreB)
{
theTeams[j].score += 3;
theTeams[j].wins += 1;
theTeams[j].scored = games[i].scoreA;
}
//if A loses
else if (games[i].scoreA < games[i].scoreB)
{
theTeams[j].score += 0;
theTeams[j].losses += 1;
theTeams[j].suff = games[i].scoreB;
}
else //tied
{
theTeams[j].score += 1;
theTeams[j].ties += 1;
theTeams[j].suff = games[i].scoreA;
}
}
if ((games[i].teamB == theTeams[j].teamA))//team(B)
{
//if B wins
if(games[i].scoreB > games[i].scoreA)
{
theTeams[j].score += 3;
theTeams[j].wins += 1;
theTeams[j].scored = games[i].scoreB;
}
//if B loses
else if (games[i].scoreB < games[i].scoreA)
{
theTeams[j].score += 0;
theTeams[j].losses += 1;
theTeams[j].suff = games[i].scoreA;
}
else //tied
{
theTeams[j].score += 1;
theTeams[j].ties += 1;
theTeams[j].suff = games[i].scoreB;
}
}
}
}
//accessing to the winner team
biggestScore = theTeams[0].score;
whichTeam = 0;
for (i = 0; i < sizeof theTeams / sizeof *theTeams; ++i){
if (theTeams[i].score > biggestScore){
biggestScore = theTeams[i].score;
whichTeam = i;
}
}
//output
printf("\n This winner is %s, with %d point(s), Won %d game(s), tied %d game(s) and lost %d game(s), Scored %d goal(s) e suffered %d goal(s)\n", theTeams[whichTeam].teamA, theTeams[whichTeam].score, theTeams[whichTeam].wins, theTeams[whichTeam].losses, theTeams[whichTeam].ties, theTeams[whichTeam].scored, theTeams[whichTeam].suff);
return 0;
}
There are no "problems" with C language and strings; you can do whatever you want. It's just a bit more responsibility than in other languages.
You seem to need an array of structures, yes. I would recommend modelling it as just an array of games played, where each game records the teams that took part, and their scores. No need to first record a list of "available" teams, it's easier to just extract that from the game data afterwards.
struct game {
const char *teamA;
int scoreA;
const char *teamB;
int scoreB;
};
struct game game_new(const char *teamA, int scoreA, const char *teamB, int scoreB)
{
struct game g;
g.teamA = strdup(teamA);
g.scoreA = scoreA;
g.teamB = strdup(teamB);
g.scoreB = scoreB;
return g;
}
and then in the man program:
int main(void)
{
struct game games[100];
size_t num_games = 0;
for (size_t i = 0; i < sizeof games / sizeof *games; ++i)
{
char teamA[100], teamB[100];
int scoreA, scoreB;
if (scanf(" %s %d - %s %d", teamA, &scoreA, teamB, &scoreB) != 4)
break;
games[++num_games] = game_new(teamA, scoreA, teamB, scoreB);
}
}
C like all programming languages is only as good as the plan you have laid out to model the data
For this, an array of arrays that stores the data can work.
Might want to also consider a database for relationships based on teams. Then you can also add metadata and the like (for example, timestamps). Though its only good if you don't mind externalising application beyond C.

C: insert element in empty heap

i'm supposed to write a code, that inserts numbers from stdin into an at first empty max-heap. my code just doesn't get the order of elements right, i found out, that it doesnt even enter the while loop before the third number. Anybody willing to help? Thanks in advance!
int heap_insert(heap* h, int key) {
if (h->size==MAX_HEAP_SIZE){
return(-1);
}
h->size=h->size+1;
int i=h->size-1;
h->array[i]=key;
int parent=(i-1)/2;
while (i>1 && h->array[parent]< key) {
h->array[i]= h->array[parent];
i = parent;
h->array[i]=key;
}
return(0);
}
it doesnt even enter the while loop before the third number
That part can be answered. Your loop won't go until i is 2 or greater...
while (i > 1 && h->array[parent]< key) {
^^^^^
Here's the code that sets i.
h->size = h->size+1;
int i = h->size-1;
That code is easier to understand like so:
int i = h->size;
h->size++;
First time through, i will be 0 (assuming h->size is initialized to 0, you didn't show your heap init code). Second time it will be 1. Third time it will be 2 and then finally the loop can run.
I'm guessing you want i >= 1 in the while loop so it will go on the second call.
As for why it's not working, the primary problem is you're forgetting to change parent in the loop.
/* i and parent initialized */
int i=h->size-1;
...
int parent=(i-1)/2;
while (i>1 && h->array[parent]< key) {
h->array[i]= h->array[parent];
/* i is changed, but where's parent? */
i = parent;
h->array[i]=key;
}
Here's what it should look like. I've changed i, which should only be used in loop indexes, to the more descriptive new.
/* new and parent initialized */
int new = h->size;
...
int parent = (new-1)/2;
while( new != 0 && h->array[parent] < key ) {
h->array[new] = h->array[parent];
h->array[parent] = key;
/* new AND parent changed */
new = parent;
parent = (new-1)/2;
}
Here's the complete code, plus I made the heap size dynamic because fixed size structures are a crutch best avoided.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int size;
int max_size;
int *array;
} heap;
#define INIT_HEAP_SIZE 4
static heap *heap_init() {
heap *h = calloc(1, sizeof(heap));
h->max_size = INIT_HEAP_SIZE;
h->array = calloc(h->max_size, sizeof(int));
return h;
}
static void heap_destroy(heap *h) {
free(h->array);
free(h);
}
static void heap_grow(heap *h) {
h->max_size *= 2;
h->array = realloc( h->array, h->max_size * sizeof(int) );
}
static void heap_insert(heap* h, int key) {
if (h->size >= h->max_size) {
heap_grow(h);
}
int new = h->size;
h->size++;
h->array[new] = key;
int parent = (new-1)/2;
while( new != 0 && h->array[parent] < key ) {
h->array[new] = h->array[parent];
h->array[parent] = key;
new = parent;
parent = (new-1)/2;
}
return;
}
int main(void) {
heap *h = heap_init();
heap_insert(h, 23);
heap_insert(h, 11);
heap_insert(h, 42);
heap_insert(h, 5);
heap_insert(h, 99);
for( int i = 0; i < h->size; i++ ) {
printf("%d: %d\n", i, h->array[i]);
}
heap_destroy(h);
}
It doesn't enter the while loop before the 3rd number because your i is not greater than 1 until the 3rd number is entered. At 1st number i = 0, then 1 then 2.
For the loop, here's my advice on figuring out the problem: Suppose you enter the values 3, 5, 7. As soon as 5 is entered, you need a swap. 5 should become the new root, and 3 should be a child. (So maxheap property is kept) Then, when 7 is entered, another swap is in order. This time with 5. 7 becomes root, 3 and 5 are children. What does this tell you about the indexes? What happens if we insert 10, 16, 1 as well? More swaps? If you answer these properly the while loop should be easy to solve. (Hint: You need to keep swapping by starting from the child, and move to next parent until everything is in order)

Resources