diff --git a/bp_tree.h b/bp_tree.h index 9190756da8b4caa074657e62510e83be5a8d84eb..085998876e70111bd4e6c9b027825702eff741c1 100644 --- a/bp_tree.h +++ b/bp_tree.h @@ -10,7 +10,7 @@ typedef struct date { uint8_t day; - uint8_t month; // 1 = January, 12 = December + uint8_t month; // 1 = January, 12 = December, 0 = Error uint8_t year; // value stored is year - 1900 } date; @@ -37,10 +37,26 @@ typedef struct node { */ void bp_print(node *root, int depth); +/** + * @brief Factored way to print a single entry + * + * @param person entry to print + */ void bp_print_entry(entry person); +/** + * @brief Prints every entries in the tree + * + * @param tree Tree to look into + */ void bp_print_everything(node *tree); +/** + * @brief Search an entry from a phone number + * + * @param tree Tree to look into + * @param phone search parameter + */ void bp_search(node *tree, char phone[11]); /** diff --git a/hash.h b/hash.h index 6496822328a20983758865e069bf85fab28f11f7..6f49ec1574340606f0ae7d9cbc622b4791d7e91c 100644 --- a/hash.h +++ b/hash.h @@ -4,5 +4,11 @@ #include <stdint.h> #include <stdio.h> +/** + * @brief Generate a 64-bits hash from a string + * + * @param string In this project, send the phone number + * @return uint64_t key + */ uint64_t generate_key(char *string); #endif \ No newline at end of file diff --git a/main.c b/main.c index 4a4220c64afe124100e4b418723bbc91c9baef87..845cb114d5c4281cbabc03b5999eeb59d4cbefe0 100644 --- a/main.c +++ b/main.c @@ -87,14 +87,14 @@ int main() { test.year = val - 1900; person.birth = test; - /* + printf("Est-ce valide ? ('y' pour oui)\n"); bp_print_entry(person); - scanf("%c", &select); - if (select != 'y') { + scanf("%s", select); + if (select[0] != 'y') { goto START; - }*/ + } tree = bp_insert_val(tree, person); break; diff --git a/showcase/makefile b/showcase/makefile new file mode 100644 index 0000000000000000000000000000000000000000..959275c392e111ca5fe5d389ecc160962a60b84d --- /dev/null +++ b/showcase/makefile @@ -0,0 +1,13 @@ +CC=gcc +FLAGS= -Werror +CFLAGS= -g -std=c99 +LDFLAGS= -fsanitize=address -fsanitize=leak + +exe: showcase + ./$^ + +showcase: showcase.o + $(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS) -lm + +showcase.o: showcase.c + $(CC) $(FLAGS) $(CFLAGS) $(LDFLAGS) -c $^ \ No newline at end of file diff --git a/showcase/showcase b/showcase/showcase new file mode 100755 index 0000000000000000000000000000000000000000..1764eaf4b94576facef276da61225d822be59fbd Binary files /dev/null and b/showcase/showcase differ diff --git a/showcase/showcase.c b/showcase/showcase.c new file mode 100644 index 0000000000000000000000000000000000000000..a0b401cc27a5cb58d94baf35bc6333afc3cf0aa8 --- /dev/null +++ b/showcase/showcase.c @@ -0,0 +1,419 @@ +#include <math.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +// UTILS ---------------------------------------------------------- + +#define M 4 +#include <stdlib.h> + +typedef struct node { + struct node *childs[M + 1]; + int data[M]; + int count; + struct node *next; +} node; + +typedef struct control { + int value; + node *lhs; + node *rhs; +} control; + +const control CONST_CONTR = {.value = 0, .lhs = NULL, .rhs = NULL}; + +node *bp_create_node() { + node *nd = malloc(sizeof(node)); + + for (int i = 0; i < M + 1; i++) + nd->childs[i] = NULL; + for (int i = 0; i < M; i++) + nd->data[i] = 0; + nd->count = 0; + nd->next = NULL; + return nd; +} + +control value_to_insert(int val) { + control c; + c.value = val; + c.lhs = c.rhs = NULL; + return c; +} + +bool bp_is_leaf(node *nd) { return nd->childs[0] == NULL; } + +void bp_node_shift(node *nd, int index) { + // as there is one more child than values, we must do one more iteration + // outside of the for + nd->childs[M] = nd->childs[M - 1]; + + for (int i = M - 1; i > index; i--) { + nd->data[i] = nd->data[i - 1]; + nd->childs[i + 1] = nd->childs[i]; + } +} + +node *bp_split(node *nd) { + node *new = bp_create_node(); + /* + this weird thing is for the for loop + up to how many loop do we want to do + we need it outside because if the order of the tree is odd, we must do + one more loop + */ + int upto = (int)floor(M / 2); + int index = upto; + + // update the new counts + nd->count = (int)floor(nd->count / 2); + new->count = upto; + + // as explained, do shit if the order is odd + if (M % 2 == 1) { + upto++; + new->count++; + } + // no need in this situation to reassign child pointers as there is no + // childs for leaves + for (int i = 0; i < upto; i++) { + new->data[i] = nd->data[index + i]; + nd->data[index + i] = 0; + } + + return new; +} + +node *bp_split_root(node *root) { + node *new = bp_create_node(); // will be the new root + node *rhs = bp_create_node(); // second child of the new root + + int index = (int)floor(M / 2); // index to the pivot + int looper = index; /* How many runs of our for loops we'll need to do + (different to index in the case our tree order is even)*/ + + new->count = 1; + root->count = index; + rhs->count = index; + + if (M % 2 == 0) { + looper--; + rhs->count--; + } + + // first assing the child pointers + for (int i = 0; i <= looper; i++) { + rhs->childs[i] = root->childs[index + i + 1]; + root->childs[index + i + 1] = NULL; + } + + // then assing the datas + for (int i = 0; i < looper; i++) { + rhs->data[i] = root->data[index + i + 1]; + root->data[index + i + 1] = 0; + } + + new->childs[0] = root; + new->childs[1] = rhs; + new->data[0] = root->data[index]; + + root->data[index] = 0; + + return new; +} + +control bp_split_unleaf(node *nd) { + // This one is used to split a node that is neither a leaf or a root + // it works exactly like the split of a root except it doesn't return a node + // that becomes the new root + // it instead returns a control value to send to the parent + control new; + node *rhs = bp_create_node(); + + int index = (int)floor(M / 2); + int looper = index; + + nd->count = index; + rhs->count = index; + + if (M % 2 == 0) { + looper--; + rhs->count--; + } + + for (int i = 0; i <= looper; i++) { + rhs->childs[i] = nd->childs[index + i + 1]; + nd->childs[index + i + 1] = NULL; + } + + for (int i = 0; i < looper; i++) { + rhs->data[i] = nd->data[index + i + 1]; + nd->data[index + i + 1] = 0; + } + + new.lhs = nd; + new.rhs = rhs; + new.value = nd->data[index]; + + nd->data[index] = 0; + + return new; +} + +void bp_do_the_insert(node *nd, control val) { + // look for a 0 in the node (it is guarenteed to exist in this version of + // the algorithm) + for (int i = 0; i < M; i++) { + // if we plainly find a 0 + if (nd->data[i] == 0) { + nd->data[i] = val.value; + nd->childs[i + 1] = val.rhs; + break; + } + + // if we need to insert the value between two values, we need to + // shift everything greater than our value one case further + if (nd->data[i] > val.value) { + bp_node_shift(nd, i); + nd->data[i] = val.value; + nd->childs[i + 1] = val.rhs; + break; + } + } + nd->count++; +} + +// INSERT ---------------------------------------------------------- + +control bp_insert_into(node *nd, control val) { + bp_do_the_insert(nd, val); + // if the node is now full, we split + if (nd->count == M) { + control v; + node *new = bp_split(nd); + v.lhs = nd; + v.rhs = new; + v.value = new->data[0]; + + // if the new node we created is a leaf, we must add it to the + // linked list + if (bp_is_leaf(new)) { + if (nd->next != NULL) + new->next = nd->next; + + nd->next = new; + } + return v; + } + return CONST_CONTR; +} + +control bp_insert(node *nd, control val, int depth) { + control c; // will help us to return the pivot, and the two pointers of the + // childs-to-be + + // if we are in a leaf, we found where to insert the value, so let's do it + if (bp_is_leaf(nd)) + c = bp_insert_into(nd, val); + else // otherwise let's keep looking + { + for (int i = 0; i < M; i++) { + if (nd->data[i] > val.value || nd->data[i] == 0) { + c = bp_insert(nd->childs[i], val, depth + 1); + break; + } + } + // treat the control return here + // if a split happened and we are not the root + if (c.value != 0 && depth != 0) { + bp_do_the_insert(nd, c); + + // if after the child split, the node is full, split the node + if (nd->count == M) + return bp_split_unleaf(nd); + + return CONST_CONTR; + } + } + + // if a split happened + if (c.value != 0) { + return c; + } + return CONST_CONTR; +} + +node *bp_insert_val(node *tree, int val) { + // Parse the val into a control struct then insert it in the tree + control test = bp_insert(tree, value_to_insert(val), 0); + /* + depending on the control item, we act differently + if the control has pointers to node, then we had a split in the direct + childs of the root. We must add the values upringed to the root + */ + if (test.rhs != NULL) { + + // if the root isn't a leaf, first we add the value into the node + if (!bp_is_leaf(tree)) { + bp_do_the_insert(tree, test); + // If the root is full, we must split it + if (tree->count == M) { + return bp_split_root(tree); + } + + // if not, we can simply return the root + return tree; + } + + // if, after a split, the root was a leaf, we must create a new + // node which will contain the values from the control + tree = bp_create_node(); + tree->childs[0] = test.lhs; + tree->childs[1] = test.rhs; + tree->data[0] = test.value; + tree->count = 1; + } + return tree; +} + +// MEMORY ---------------------------------------------------------- + +void bp_destroy(node *root) { + if (root == NULL) + return; + + // free the childs first + if (!bp_is_leaf(root)) { + for (int i = 0; i < M; i++) { + bp_destroy(root->childs[i]); + } + } + + // then free the root + free(root); +} + +// PRINTING ---------------------------------------------------------- + +void bp_print_as_ll(node *root) { + // if we reached the end of the list + if (root == NULL) { + printf("NULL\n"); + return; + } + + // search for the first leaf on the tree + if (!bp_is_leaf(root)) { + return bp_print_as_ll(root->childs[0]); + } + + printf("|"); + // print every values in the node until hitting 0, then we can get on the + // next node + for (int i = 0; i < M; i++) { + printf(" %d |", root->data[i]); + if (root->data[i + 1] == 0) { + printf(" -> "); + return bp_print_as_ll(root->next); + } + } +} + +void bp_print(node *root, int depth) { + // if we are on a leaf, we can print the values directly next to each other + if (bp_is_leaf(root)) { + for (int i = 0; i < depth; i++) + printf(" "); + for (int i = 0; i < M; i++) { + printf(" %d |", root->data[i]); + // if we reach a 0, we have seen every values in the node + if (root->data[i + 1] == 0) + break; + } + return; + } + + for (int i = 0; i < M; i++) { + bp_print(root->childs[i], depth + 1); + printf("\n"); + + for (int i = 0; i < depth; i++) + printf(" "); + + printf(" %d |\n", root->data[i]); + + if (root->data[i + 1] == 0) + return bp_print(root->childs[i + 1], depth + 1); + } +} +int main() { + node *tree = bp_create_node(); + + tree = bp_insert_val(tree, 3); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 6); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 5); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 4); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 8); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 13); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 9); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 15); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 11); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 12); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 7); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 14); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 10); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 16); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 17); + bp_print(tree, 0); + + printf("\n|||||||||\n"); + tree = bp_insert_val(tree, 18); + bp_print(tree, 0); + printf("\n|||||||||\n"); + bp_print_as_ll(tree); + bp_destroy(tree); + return 0; +}