numbers.c bintree.c änderungen

This commit is contained in:
Kristin 2025-12-10 21:05:36 +01:00
parent d9222b83b4
commit 799667ed1c
7 changed files with 181 additions and 158 deletions

View File

@ -13,34 +13,50 @@
// ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores // ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores
// duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). // duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).
TreeNode *createTreeNode(const void *data, size_t dataSize) {
TreeNode *node =
malloc(sizeof(TreeNode)); // Speicher für neuen Knoten reservieren
if (node == NULL)
return NULL; // Abbrechen bei Fehler
node->data = malloc(dataSize); // Speicher für Daten reservieren
if (node->data == NULL) {
free(node);
return NULL;
}
memcpy(node->data, data, dataSize); // Standardfunktion string.h, kopiert
// size bytes von data nach node->data,
// daten dürfen sich nicht überschneiden
// speichern der Daten in node->data
node->left = NULL; // Kinder sind NULL
node->right = NULL;
return node;
}
TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize, TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
CompareFctType compareFct, int *isDuplicate) { CompareFctType compareFct, int *isDuplicate) {
// isDuplicate initialisieren (auf 0 setzen) // isDuplicate initialisieren (auf 0 setzen), verhindert Änderung am Baum
if (isDuplicate) { if (isDuplicate) {
*isDuplicate = 0; *isDuplicate = 0;
} } // bei 0: neuer Wert wurde eingefügt, bei 1: Wert war bereits im Baum
// leerer Baum // leerer Baum
if (root == NULL) { if (root == NULL) {
TreeNode *node = malloc(sizeof(TreeNode)); return createTreeNode(data, dataSize);
node->data = malloc(dataSize);
memcpy(node->data, data, dataSize);
node->left = NULL;
node->right = NULL;
return node;
} }
// mit compareFct <0 links >0 rechts =0 Duplikat // mit compareFct <0 links >0 rechts =0 Duplikat
int cmp = compareFct(data, root->data); int compare = compareFct(data, root->data);
if (cmp < 0) { if (compare < 0) { // Eintrag links
root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate); root->left = addToTree(root->left, data, dataSize, compareFct, isDuplicate);
} else if (cmp > 0) { } else if (compare > 0) { // Eintrag rechts
root->right = root->right =
addToTree(root->right, data, dataSize, compareFct, isDuplicate); addToTree(root->right, data, dataSize, compareFct, isDuplicate);
} else { } else { // Duplikat
// isDuplicate auf 1 setzen // isDuplicate auf 1 setzen, keine Änderung am Baum
if (isDuplicate) { if (isDuplicate) {
*isDuplicate = 1; *isDuplicate = 1;
} }
@ -54,40 +70,42 @@ TreeNode *addToTree(TreeNode *root, const void *data, size_t dataSize,
// the root node and all left nodes first. On returning the next element, push // the root node and all left nodes first. On returning the next element, push
// the top node and push all its left nodes. // the top node and push all its left nodes.
void *nextTreeData(TreeNode *root) { void *nextTreeData(TreeNode *root) {
static StackNode *stack = NULL; static StackNode *stack = NULL; // static -> behält Wert bei mehreren Aufrufen
// Neue Iteration starten // Neue Iteration starten
if (root != NULL) { if (root != NULL) {
clearStack(&stack); clearStack(&stack); // alte Stack-Inhalte werden gelöscht
TreeNode *curr = root; TreeNode *currentNode = root;
while (curr != NULL) { while (currentNode !=
NULL) { // alle linken Knoten werden vom root an auf den Stack gelegt
StackNode *oldStack = stack; StackNode *oldStack = stack;
StackNode *newStack = push(stack, curr); StackNode *newStack = push(stack, currentNode);
if (newStack == oldStack) if (newStack == oldStack)
return NULL; // push fehlgeschlagen return NULL; // push fehlgeschlagen
stack = newStack; stack = newStack;
curr = curr->left; currentNode = currentNode->left;
} }
} }
if (stack == NULL) if (stack == NULL)
return NULL; // alles durchlaufen return NULL; // wenn Stack leer ist sind keine Elemente mehr vorhanden,
// Iteration beendet
// Oberstes Element abrufen // oberster Knoten vom Stack
TreeNode *node = (TreeNode *)top(stack); TreeNode *node = top(stack);
stack = pop(stack); stack = pop(stack);
// Rechten Teilbaum pushen // Rechten Teilbaum pushen
TreeNode *curr = node->right; TreeNode *currentNode = node->right;
while (curr != NULL) { while (currentNode != NULL) {
StackNode *oldStack = stack; StackNode *oldStack = stack;
StackNode *newStack = push(stack, curr); StackNode *newStack = push(stack, currentNode);
if (newStack == oldStack) if (newStack == oldStack)
return NULL; // push fehlgeschlagen return NULL; // push fehlgeschlagen
stack = newStack; stack = newStack;
curr = curr->left; currentNode = currentNode->left;
} }
return node->data; return node->data; // Pointer auf Daten
} }
// Releases all memory resources (including data copies). // Releases all memory resources (including data copies).

View File

@ -11,6 +11,8 @@ typedef struct node {
struct node *right; struct node *right;
} TreeNode; } TreeNode;
TreeNode *createTreeNode(const void *data, size_t dataSize);
// Adds a copy of data's pointer destination to the tree using compareFct for // Adds a copy of data's pointer destination to the tree using compareFct for
// ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores // ordering. Accepts duplicates if isDuplicate is NULL, otherwise ignores
// duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added). // duplicates and sets isDuplicate to 1 (or to 0 if a new entry is added).

View File

@ -1,10 +1,10 @@
Kristin;49209 Kristin;49209
Kristin;9959 krisp;29797
Kristin;9944 krisp;29792
Kristin;7947 Kristin;29782
Kristin;6962 Kristin;19943
Kristin;5987 krisp;19934
Kristin;5975 krisp;19916
krisp;4986 kristin;19861
krisp;4985 Kristin;19858
Kristin;4972 krisp;19460

132
main.c
View File

@ -1,90 +1,88 @@
#include <stdlib.h> #include "highscore.h"
#include <stdio.h>
#include "numbers.h" #include "numbers.h"
#include "timer.h" #include "timer.h"
#include "highscore.h" #include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Read an unsigned integer from stdin with prompt (retries until valid). // Read an unsigned integer from stdin with prompt (retries until valid).
int inputNumber(const char *promptText) int inputNumber(const char *promptText) {
{ unsigned int number;
unsigned int number; int numberOfInputs = 0;
int numberOfInputs = 0;
while(numberOfInputs != 1) while (numberOfInputs != 1) {
{ printf("%s", promptText);
printf("%s", promptText); numberOfInputs = scanf("%u", &number);
numberOfInputs = scanf("%u", &number); while (getchar() != '\n') {
while(getchar() != '\n') {} // clear input buffer } // clear input buffer
} }
return number; return number;
} }
// Print an array of numbers. // Print an array of numbers.
void showNumbers(const unsigned int *numbers, unsigned int len) void showNumbers(const unsigned int *numbers, unsigned int len) {
{ if (numbers != NULL) {
if(numbers != NULL) printf("Numbers:");
{
printf("Numbers:");
for(int i = 0; i < len; i++) for (int i = 0; i < len; i++)
printf(" %5d", numbers[i]); printf(" %5d", numbers[i]);
printf("\n"); printf("\n");
} }
} }
// Main game loop: generate numbers, ask user for duplicate, measure time, update highscores. // Main game loop: generate numbers, ask user for duplicate, measure time,
int main(int argc, char *argv[]) // update highscores.
{ int main(int argc, char *argv[]) {
int exitCode = EXIT_FAILURE; srand(time(NULL)); // seed für srand
int exitCode = EXIT_FAILURE;
if(argc != 2) if (argc != 2) {
{ fprintf(stderr, "Usage: %s <player name>\n", argv[0]);
fprintf(stderr, "Usage: %s <player name>\n", argv[0]); exitCode = EXIT_FAILURE;
exitCode = EXIT_FAILURE; } else {
} const char *highscorePath = "highscores.txt";
else const char *playerName = argv[1];
{ unsigned int *numbers = NULL;
const char *highscorePath = "highscores.txt"; unsigned int duplicate = 0;
const char *playerName = argv[1]; double measuredSeconds;
unsigned int *numbers = NULL; unsigned int userInput;
unsigned int duplicate = 0; unsigned int numberOfElements = 0;
double measuredSeconds;
unsigned int userInput;
unsigned int numberOfElements = 0;
// ask until valid number of elements (3..1000) // ask until valid number of elements (3..1000)
while(numberOfElements < 3 || numberOfElements > 1000) while (numberOfElements < 3 || numberOfElements > 1000)
numberOfElements = inputNumber("Wie viele Zahlen sollen gezeigt werden: "); numberOfElements =
inputNumber("Wie viele Zahlen sollen gezeigt werden: ");
// create numbers and show them // create numbers and show them
numbers = createNumbers(numberOfElements); numbers = createNumbers(numberOfElements);
showNumbers(numbers, numberOfElements); showNumbers(numbers, numberOfElements);
// measure time while user guesses the duplicate // measure time while user guesses the duplicate
startTimer(); startTimer();
userInput = inputNumber("Welche Zahl kommt doppelt vor: "); userInput = inputNumber("Welche Zahl kommt doppelt vor: ");
measuredSeconds = stopTimer(); measuredSeconds = stopTimer();
duplicate = getDuplicate(numbers, numberOfElements); duplicate = getDuplicate(numbers, numberOfElements);
// check result and update highscores // check result and update highscores
if(userInput == duplicate) if (userInput == duplicate) {
{ int score = addHighscore(playerName, measuredSeconds, numberOfElements);
int score = addHighscore(playerName, measuredSeconds, numberOfElements); printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u "
printf("Sie haben die korrekte Zahl in %.6lf Sekunde(n) gefunden und %u Punkte erzielt.\n", measuredSeconds, score); "Punkte erzielt.\n",
} measuredSeconds, score);
else } else
printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n", userInput, duplicate); printf("Leider ist %u nicht korrekt. Richtig waere %u gewesen.\n",
userInput, duplicate);
loadHighscores(highscorePath); loadHighscores(highscorePath);
showHighscores(); showHighscores();
saveHighscores(highscorePath); saveHighscores(highscorePath);
clearHighscores(); clearHighscores();
exitCode = EXIT_SUCCESS; exitCode = EXIT_SUCCESS;
} }
return exitCode; return exitCode;
} }

102
numbers.c
View File

@ -3,18 +3,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
if (x < y)
return -1;
if (x > y)
return 1;
return 0;
}
// TODO: getDuplicate und createNumbers implementieren // TODO: getDuplicate und createNumbers implementieren
/**Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an /**Erzeugen eines Arrays mit der vom Nutzer eingegebenen Anzahl an
@ -27,65 +15,77 @@ int compareUnsignedInt(const void *a, const void *b) {
// different, except for two entries. Returns NULL on errors. Use your // different, except for two entries. Returns NULL on errors. Use your
// implementation of the binary search tree to check for possible duplicates // implementation of the binary search tree to check for possible duplicates
// while creating random numbers. // while creating random numbers.
// vergleicht zwei Werte: a<b: -1 a>b: 1 a=b: 0
int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b;
return (x < y) ? -1 : (x > y);
}
unsigned int *createNumbers(unsigned int len) { unsigned int *createNumbers(unsigned int len) {
if (len < 2) if (len < 2) // Duplikat bei zwei Einträgen sinnlos
return NULL; return NULL;
unsigned int *arr = malloc(sizeof(unsigned int) * len); unsigned int *numbersArray = malloc(
if (!arr) sizeof(unsigned int) * len); // Speicher für das Ausgabearray reservieren:
// Größe eines Eintrags * Größe des Arrays
if (!numbersArray) // Speicher konnte nicht reserviert werden
return NULL; return NULL;
TreeNode *root = NULL; TreeNode *root =
srand((unsigned int)time(NULL)); NULL; // Binärbaum zum Generieren der Zufallszahlen ohne Duplikate
for (unsigned int i = 0; i < len - 1; i++) { for (unsigned int i = 0; i < len; i++) {
unsigned int num; unsigned int currentNumber;
int isDuplicate; int isDuplicate;
do { // mindestens eine Zufallszahl erzeugen
do { currentNumber = (rand() % (2 * len)) + 1; // Zahlenbereich 1 bis 2*len
num = (rand() % (2 * len)) + 1;
isDuplicate = 0; isDuplicate = 0;
root = addToTree(root, &currentNumber, sizeof(unsigned int),
root = addToTree(root, &num, sizeof(unsigned int), compareUnsignedInt, compareUnsignedInt,
&isDuplicate); &isDuplicate); // compareUnsignedInt wird zum Verwenden
// bei Vergleichen übergeben
} while (isDuplicate); // nur akzeptieren, wenn eindeutig } while (isDuplicate); // wenn isDuplicate gesetzt wird, muss eine neue Zahl
// erzeugt werden, die Schleife wird wiederholt
arr[i] = num; numbersArray[i] = currentNumber;
} }
// Jetzt gezielt EIN Duplikat erzeugen // Ein zufälliges Duplikat erzeugen
unsigned int duplicateIndex = rand() % (len - 1); unsigned int duplicateIndex =
arr[len - 1] = arr[duplicateIndex]; rand() % len; // Index des Duplikats per Zufall bestimmen
unsigned int newIndex;
do {
newIndex = rand() % len;
} while (newIndex == duplicateIndex); // zweiten Index bestimmen, der nicht
// mit dem ersten übereinstimmt
clearTree(root); numbersArray[newIndex] =
return arr; numbersArray[duplicateIndex]; // Wert vom ersten Index kopieren
clearTree(root); // Speicher wieder freigeben, wird nicht mehr benötigt
return numbersArray;
} }
// Returns only the only number in numbers which is present twice. Returns zero // Returns only the only number in numbers which is present twice. Returns zero
// on errors. // on errors.
unsigned int getDuplicate(const unsigned int numbers[], unsigned int len) { unsigned int getDuplicate(const unsigned int *numbers, unsigned int len) {
if (!numbers || len < 2) if (!numbers || len < 2)
return 0; return NULL; // Fehlerhaftes Array
unsigned int *copy = malloc(sizeof(unsigned int) * len); TreeNode *root = NULL; // neuer Baum
if (!copy) unsigned int duplicateValue = 0;
return 0;
memcpy(copy, numbers, sizeof(unsigned int) * len); for (unsigned int i = 0; i < len; i++) {
int isDuplicate = 0;
// Sortierung root = addToTree(root, &numbers[i], sizeof(unsigned int),
qsort(copy, len, sizeof(unsigned int), compareUnsignedInt); compareUnsignedInt, &isDuplicate);
if (isDuplicate) {
// Duplikat finden: zwei gleiche nebeneinander duplicateValue = numbers[i];
unsigned int duplicate = 0;
for (unsigned int i = 0; i < len - 1; i++) {
if (copy[i] == copy[i + 1]) {
duplicate = copy[i];
break; break;
} }
} }
free(copy); clearTree(root);
return duplicate; return duplicateValue;
} }

View File

@ -1,12 +1,16 @@
#ifndef NUMBERS_H #ifndef NUMBERS_H
#define NUMBERS_H #define NUMBERS_H
// Returns len random numbers between 1 and 2x len in random order which are all different, except for two entries. int compareUnsignedInt(const void *a, const void *b);
// Returns NULL on errors. Use your implementation of the binary search tree to check for possible duplicates while
// creating random numbers. // Returns len random numbers between 1 and 2x len in random order which are all
// different, except for two entries. Returns NULL on errors. Use your
// implementation of the binary search tree to check for possible duplicates
// while creating random numbers.
unsigned int *createNumbers(unsigned int len); unsigned int *createNumbers(unsigned int len);
// Returns only the only number in numbers which is present twice. Returns zero on errors. // Returns only the only number in numbers which is present twice. Returns zero
// on errors.
unsigned int getDuplicate(const unsigned int *numbers, unsigned int len); unsigned int getDuplicate(const unsigned int *numbers, unsigned int len);
#endif #endif

View File

@ -4,6 +4,7 @@
#include <string.h> #include <string.h>
#include "bintree.h" #include "bintree.h"
int compareUnsignedInt(const void *a, const void *b) { int compareUnsignedInt(const void *a, const void *b) {
unsigned int x = *(unsigned int *)a; unsigned int x = *(unsigned int *)a;
unsigned int y = *(unsigned int *)b; unsigned int y = *(unsigned int *)b;