Skip to content
Snippets Groups Projects
Commit 9df79d44 authored by Florian Burgener's avatar Florian Burgener
Browse files

Huge refactoring

parent c0240b1a
Branches
No related tags found
No related merge requests found
main.c 0 → 100644
#include <stdio.h>
#include <stdlib.h>
#include "Directory.h"
#include "DirectoryRecord.h"
void clear_buffer() {
int c;
while ((c = getchar()) != '\n' && c != EOF) {
}
}
void append_record(Directory *directory) {
char phone_number[PHONE_NUMBER_MAXLEN];
printf("Enter the phone number: ");
scanf("%10s", phone_number);
clear_buffer();
char name[NAME_MAXLEN];
printf("Enter the name: ");
scanf("%20s", name);
clear_buffer();
char surname[SURNAME_MAXLEN];
printf("Enter the surname: ");
scanf("%20s", surname);
clear_buffer();
int birth_date_year, birth_date_month, birth_date_day;
do {
printf("Enter the birth date (Y-m-d): ");
} while (scanf("%d-%d-%d", &birth_date_year, &birth_date_month, &birth_date_day) != 3);
clear_buffer();
printf("\nIs the information entered correct? (Y/n) ");
char choice = getchar();
if (choice != '\n') {
getchar();
}
if (choice == 'n') {
printf("\n===>The procedure has been cancelled.\n");
} else {
DirectoryRecord *record = DirectoryRecord_init(false, phone_number, name, surname, birth_date_year, birth_date_month, birth_date_day);
if (Directory_append(directory, record)) {
printf("\n===>The record has been saved in the directory.\n");
} else {
printf("\n===>This phone number is already associated with a record. The record has not been saved.\n");
}
DirectoryRecord_destroy(&record);
}
}
void search_record(Directory *directory) {
printf("Enter the phone number that corresponds to the record you are looking for: ");
char phone_number[PHONE_NUMBER_MAXLEN];
scanf("%10s", phone_number);
clear_buffer();
DirectoryRecord *record = Directory_search(directory, phone_number);
printf("\n");
if (record == NULL) {
printf("===>No records were found for this phone number.\n");
} else {
printf("========================\n");
DirectoryRecord_print(record);
DirectoryRecord_destroy(&record);
printf("========================\n");
}
}
void delete_record(Directory *directory) {
printf("Enter the phone number that corresponds to the record you wish to delete: ");
char phone_number[PHONE_NUMBER_MAXLEN];
scanf("%10s", phone_number);
clear_buffer();
DirectoryRecord *record = Directory_search(directory, phone_number);
printf("\n");
if (record == NULL) {
printf("===>No records were found for this phone number.\n");
} else {
printf("========================\n");
DirectoryRecord_print(record);
DirectoryRecord_destroy(&record);
printf("========================\n");
printf("\nAre you sure you want to delete this record? (Y/n) ");
char choice = getchar();
if (choice != '\n') {
getchar();
}
if (choice == 'n') {
printf("\n===>The procedure has been cancelled.\n");
} else {
Directory_delete(directory, phone_number);
printf("Delete done\n");
}
}
}
int main() {
Directory *directory = Directory_init("directory_database");
while (true) {
BPTree_print(directory->index, 0);
printf("Enter 1 to add a member.\n");
printf("Enter 2 to search for a member via their phone number.\n");
printf("Enter 3 to delete a member.\n");
printf("Enter 4 to display all members.\n");
printf("Enter 5 to exit the program.\n");
printf("What do you want to do? ");
int action;
scanf("%d", &action);
clear_buffer();
if (action < 1 || action > 5) {
system("clear");
continue;
}
if (action == 5) {
break;
}
printf("\n");
switch (action) {
case 1:
append_record(directory);
break;
case 2:
search_record(directory);
break;
case 3:
delete_record(directory);
break;
case 4:
Directory_print(directory);
break;
}
printf("\nPress enter to continue...");
getchar();
system("clear");
}
Directory_destroy(&directory);
return EXIT_SUCCESS;
}
...@@ -7,34 +7,19 @@ ...@@ -7,34 +7,19 @@
#include "Array.h" #include "Array.h"
static bool has_maximum_keys(BPTreeNode *node); // BPTreeNode
static BPTreeNode *find_leaf(BPTreeNode *root, uint64_t key, BPTreeNodeArray **parents);
static bool has_maximum_keys(BPTreeNode *node) {
return node->keys->size == 2 * node->order;
}
static BPTreeNode *find_leaf(BPTreeNode *root, uint64_t key, BPTreeNodeArray **parents) {
BPTreeNode *current = root;
// CAUTION : 10 is not enough.
*parents = BPTreeNodeArray_init(10);
while (!current->is_leaf) {
BPTreeNodeArray_append(*parents, current);
int child_index = lower_bound(current->keys, key);
if (child_index < current->keys->size && current->keys->items[child_index] == key) {
child_index += 1;
}
current = current->children->items[child_index];
}
return current; static BPTreeNode *BPTreeNode_init(int order, bool is_leaf) {
BPTreeNode *root = (BPTreeNode *)malloc(sizeof(BPTreeNode));
root->order = order;
root->is_leaf = is_leaf;
root->keys = IntegerArray_init(2 * root->order);
root->data = IntegerArray_init(2 * root->order);
root->children = BPTreeNodeArray_init(2 * root->order + 1);
root->next = NULL;
return root;
} }
// BPTreeNode
static void BPTreeNode_destroy(BPTreeNode **node) { static void BPTreeNode_destroy(BPTreeNode **node) {
IntegerArray_destroy(&(*node)->keys); IntegerArray_destroy(&(*node)->keys);
IntegerArray_destroy(&(*node)->data); IntegerArray_destroy(&(*node)->data);
...@@ -46,14 +31,7 @@ static void BPTreeNode_destroy(BPTreeNode **node) { ...@@ -46,14 +31,7 @@ static void BPTreeNode_destroy(BPTreeNode **node) {
// BPTree // BPTree
BPTreeNode *BPTree_init(int order) { BPTreeNode *BPTree_init(int order) {
BPTreeNode *root = (BPTreeNode *)malloc(sizeof(BPTreeNode)); return BPTreeNode_init(order, true);
root->order = order;
root->is_leaf = true;
root->keys = IntegerArray_init(2 * root->order);
root->data = IntegerArray_init(2 * root->order);
root->children = BPTreeNodeArray_init(2 * root->order + 1);
root->next = NULL;
return root;
} }
void BPTree_destroy(BPTreeNode **root) { void BPTree_destroy(BPTreeNode **root) {
...@@ -102,6 +80,18 @@ bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data) { ...@@ -102,6 +80,18 @@ bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data) {
return BPTree_search(root->children->items[child_index], key, data); return BPTree_search(root->children->items[child_index], key, data);
} }
// "traverse" function for insertion and deletion.
static BPTreeNode *traverse(BPTreeNode *node, uint64_t key) {
int virtual_insertion_index = lower_bound(node->keys, key);
if (virtual_insertion_index < node->keys->size && node->keys->items[virtual_insertion_index] == key) {
virtual_insertion_index += 1;
}
return node->children->items[virtual_insertion_index];
}
// BPTree : Insertion // BPTree : Insertion
static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node) { static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node) {
...@@ -119,47 +109,47 @@ static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTre ...@@ -119,47 +109,47 @@ static void insert_non_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTre
static void redistribute_keys(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index) { static void redistribute_keys(BPTreeNode *left_node, BPTreeNode *right_node, int left_index, int right_index) {
for (int i = right_index; i < left_node->keys->size; i++) { for (int i = right_index; i < left_node->keys->size; i++) {
IntegerArray_append(right_node->keys, left_node->keys->items[i]); IntegerArray_append(right_node->keys, left_node->keys->items[i]);
if (left_node->is_leaf) {
IntegerArray_append(right_node->data, left_node->data->items[i]);
}
} }
left_node->keys->size = left_index; left_node->keys->size = left_index;
if (left_node->is_leaf) { for (int i = right_index; i < left_node->data->size; i++) {
IntegerArray_append(right_node->data, left_node->data->items[i]);
}
if (left_node->data->size > 0) {
left_node->data->size = left_index; left_node->data->size = left_index;
} }
} }
static uint64_t split_leaf(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode **right_node) { static uint64_t split_leaf(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode **split_right_node) {
int virtual_insertion_index = lower_bound(node->keys, key); int virtual_insertion_index = lower_bound(node->keys, key);
int median_index = node->keys->size / 2; int median_index = node->keys->size / 2;
uint64_t median_value; uint64_t median_value;
*right_node = BPTree_init(node->order); *split_right_node = BPTreeNode_init(node->order, true);
if (virtual_insertion_index < median_index) { if (virtual_insertion_index < median_index) {
median_value = node->keys->items[median_index - 1]; median_value = node->keys->items[median_index - 1];
redistribute_keys(node, *right_node, median_index - 1, median_index - 1); redistribute_keys(node, *split_right_node, median_index - 1, median_index - 1);
int insertion_index = IntegerArray_insert_sorted(node->keys, key); int insertion_index = IntegerArray_insert_sorted(node->keys, key);
IntegerArray_insert_at_index(node->data, insertion_index, data); IntegerArray_insert_at_index(node->data, insertion_index, data);
} else if (virtual_insertion_index > median_index) { } else if (virtual_insertion_index > median_index) {
median_value = node->keys->items[median_index]; median_value = node->keys->items[median_index];
redistribute_keys(node, *right_node, median_index, median_index); redistribute_keys(node, *split_right_node, median_index, median_index);
int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); int insertion_index = IntegerArray_insert_sorted((*split_right_node)->keys, key);
IntegerArray_insert_at_index((*right_node)->data, insertion_index, data); IntegerArray_insert_at_index((*split_right_node)->data, insertion_index, data);
} else { } else {
median_value = key; median_value = key;
redistribute_keys(node, *right_node, median_index, median_index); redistribute_keys(node, *split_right_node, median_index, median_index);
int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); int insertion_index = IntegerArray_insert_sorted((*split_right_node)->keys, key);
IntegerArray_insert_at_index((*right_node)->data, insertion_index, data); IntegerArray_insert_at_index((*split_right_node)->data, insertion_index, data);
} }
if (node->next != NULL) { if (node->next != NULL) {
(*right_node)->next = node->next; (*split_right_node)->next = node->next;
} }
node->next = *right_node; node->next = *split_right_node;
return median_value; return median_value;
} }
...@@ -171,108 +161,98 @@ static void redistribute_children(BPTreeNode *left_node, BPTreeNode *right_node, ...@@ -171,108 +161,98 @@ static void redistribute_children(BPTreeNode *left_node, BPTreeNode *right_node,
left_node->children->size = left_index; left_node->children->size = left_index;
} }
static uint64_t split_internal(BPTreeNode *node, uint64_t key, BPTreeNode *right_child_node, BPTreeNode **right_node) { static uint64_t split_internal(BPTreeNode *node, uint64_t key, BPTreeNode *previous_split_right_node, BPTreeNode **split_right_node) {
int virtual_insertion_index = lower_bound(node->keys, key); int virtual_insertion_index = lower_bound(node->keys, key);
int median_index = node->keys->size / 2; int median_index = node->keys->size / 2;
uint64_t median_value; uint64_t median_value;
*right_node = BPTree_init(node->order); *split_right_node = BPTreeNode_init(node->order, false);
(*right_node)->is_leaf = false;
if (virtual_insertion_index < median_index) { if (virtual_insertion_index < median_index) {
median_value = node->keys->items[median_index - 1]; median_value = node->keys->items[median_index - 1];
redistribute_keys(node, *right_node, median_index - 1, median_index); redistribute_keys(node, *split_right_node, median_index - 1, median_index);
redistribute_children(node, *right_node, median_index, median_index); redistribute_children(node, *split_right_node, median_index, median_index);
int insertion_index = IntegerArray_insert_sorted(node->keys, key); int insertion_index = IntegerArray_insert_sorted(node->keys, key);
BPTreeNodeArray_insert_at_index(node->children, insertion_index + 1, right_child_node); BPTreeNodeArray_insert_at_index(node->children, insertion_index + 1, previous_split_right_node);
} else if (virtual_insertion_index > median_index) { } else if (virtual_insertion_index > median_index) {
median_value = node->keys->items[median_index]; median_value = node->keys->items[median_index];
redistribute_keys(node, *right_node, median_index, median_index + 1); redistribute_keys(node, *split_right_node, median_index, median_index + 1);
redistribute_children(node, *right_node, median_index + 1, median_index + 1); redistribute_children(node, *split_right_node, median_index + 1, median_index + 1);
int insertion_index = IntegerArray_insert_sorted((*right_node)->keys, key); int insertion_index = IntegerArray_insert_sorted((*split_right_node)->keys, key);
BPTreeNodeArray_insert_at_index((*right_node)->children, insertion_index + 1, right_child_node); BPTreeNodeArray_insert_at_index((*split_right_node)->children, insertion_index + 1, previous_split_right_node);
} else { } else {
median_value = key; median_value = key;
redistribute_keys(node, *right_node, median_index, median_index); redistribute_keys(node, *split_right_node, median_index, median_index);
redistribute_children(node, *right_node, median_index + 1, median_index + 1); redistribute_children(node, *split_right_node, median_index + 1, median_index + 1);
BPTreeNodeArray_insert_at_index((*right_node)->children, 0, right_child_node); BPTreeNodeArray_insert_at_index((*split_right_node)->children, 0, previous_split_right_node);
} }
return median_value; return median_value;
} }
static uint64_t insert_full(BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node, BPTreeNode **split_right_node) {
if (node->is_leaf) {
return split_leaf(node, key, data, split_right_node);
}
return split_internal(node, key, previous_split_right_node, split_right_node);
}
static void grow(BPTreeNode *root, uint64_t median_value, BPTreeNode *split_right_node) { static void grow(BPTreeNode *root, uint64_t median_value, BPTreeNode *split_right_node) {
BPTreeNode *left_node = BPTree_init(root->order); BPTreeNode *left_node = BPTreeNode_init(root->order, split_right_node->is_leaf);
left_node->is_leaf = split_right_node->is_leaf;
root->is_leaf = false; root->is_leaf = false;
IntegerArray_copy(root->keys, left_node->keys); IntegerArray_copy(root->keys, left_node->keys);
IntegerArray_clear(root->keys);
IntegerArray_append(root->keys, median_value);
IntegerArray_copy(root->data, left_node->data); IntegerArray_copy(root->data, left_node->data);
IntegerArray_clear(root->data);
BPTreeNodeArray_copy(root->children, left_node->children); BPTreeNodeArray_copy(root->children, left_node->children);
IntegerArray_clear(root->keys);
IntegerArray_clear(root->data);
BPTreeNodeArray_clear(root->children); BPTreeNodeArray_clear(root->children);
IntegerArray_append(root->keys, median_value);
BPTreeNodeArray_append(root->children, left_node); BPTreeNodeArray_append(root->children, left_node);
BPTreeNodeArray_append(root->children, split_right_node); BPTreeNodeArray_append(root->children, split_right_node);
} }
static void insert_full(BPTreeNode *root, BPTreeNodeArray *parents, BPTreeNode *node, uint64_t key, uint64_t data, BPTreeNode *previous_split_right_node) { static bool _BPTree_insert(BPTreeNode *parent, BPTreeNode *root, uint64_t *key, uint64_t data, BPTreeNode **split_right_node) {
uint64_t median_value; BPTreeNode *previous_split_right_node = NULL;
BPTreeNode *split_right_node; if (!root->is_leaf && !_BPTree_insert(root, traverse(root, *key), key, data, &previous_split_right_node)) {
return false;
}
if (node->is_leaf) { int index;
median_value = split_leaf(node, key, data, &split_right_node); bool is_found = IntegerArray_binary_search(root->keys, *key, &index);
} else { if (root->is_leaf && is_found) {
median_value = split_internal(node, key, previous_split_right_node, &split_right_node); return false;
} }
if (node == root) { if (!root->is_leaf && previous_split_right_node == NULL) {
grow(root, median_value, split_right_node); *split_right_node = NULL;
} else { return true;
BPTreeNode *parent = BPTreeNodeArray_pop(parents); }
if (has_maximum_keys(parent)) { if (root->keys->size < 2 * root->order) {
// 0 is passed instead of data because the recursion is necessarily done on an internal node. insert_non_full(root, *key, data, previous_split_right_node);
insert_full(root, parents, parent, median_value, 0, split_right_node); *split_right_node = NULL;
} else { return true;
insert_non_full(parent, median_value, data, split_right_node);
}
} }
}
void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data) { *key = insert_full(root, *key, data, previous_split_right_node, split_right_node);
BPTreeNodeArray *parents;
BPTreeNode *leaf = find_leaf(root, key, &parents);
int index; if (parent == NULL) {
if (IntegerArray_binary_search(leaf->keys, key, &index)) { grow(root, *key, *split_right_node);
BPTreeNodeArray_destroy(&parents);
return;
} }
if (has_maximum_keys(leaf)) { return true;
insert_full(root, parents, leaf, key, data, NULL); }
} else {
insert_non_full(leaf, key, data, NULL);
}
BPTreeNodeArray_destroy(&parents); bool BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data) {
BPTreeNode *previous_split_right_node;
return _BPTree_insert(NULL, root, &key, data, &previous_split_right_node);
} }
// BPTree : Deletion // BPTree : Deletion
static BPTreeNode *traverse(BPTreeNode *node, uint64_t key) {
int virtual_insertion_index = lower_bound(node->keys, key);
if (virtual_insertion_index < node->keys->size && node->keys->items[virtual_insertion_index] == key) {
virtual_insertion_index += 1;
}
return node->children->items[virtual_insertion_index];
}
static uint64_t find_smallest_key(BPTreeNode *root) { static uint64_t find_smallest_key(BPTreeNode *root) {
if (root->is_leaf) { if (root->is_leaf) {
return root->keys->items[0]; return root->keys->items[0];
...@@ -390,7 +370,7 @@ static void steal_internal(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sib ...@@ -390,7 +370,7 @@ static void steal_internal(BPTreeNode *parent, BPTreeNode *node, BPTreeNode *sib
} }
} }
static void deletion_rebalance(BPTreeNode *node, BPTreeNode *parent) { static void deletion_rebalance(BPTreeNode *parent, BPTreeNode *node) {
BPTreeNode *sibling = find_sibling(parent, node); BPTreeNode *sibling = find_sibling(parent, node);
if (sibling->keys->size == sibling->order) { if (sibling->keys->size == sibling->order) {
...@@ -406,8 +386,8 @@ static void deletion_rebalance(BPTreeNode *node, BPTreeNode *parent) { ...@@ -406,8 +386,8 @@ static void deletion_rebalance(BPTreeNode *node, BPTreeNode *parent) {
} }
} }
static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent) { static bool _BPTree_delete(BPTreeNode *parent, BPTreeNode *root, uint64_t key) {
if (!root->is_leaf && !_BPTree_delete(traverse(root, key), key, root)) { if (!root->is_leaf && !_BPTree_delete(root, traverse(root, key), key)) {
return false; return false;
} }
...@@ -429,12 +409,12 @@ static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent) { ...@@ -429,12 +409,12 @@ static bool _BPTree_delete(BPTreeNode *root, uint64_t key, BPTreeNode *parent) {
} }
if (parent != NULL && root->keys->size < root->order) { if (parent != NULL && root->keys->size < root->order) {
deletion_rebalance(root, parent); deletion_rebalance(parent, root);
} }
return true; return true;
} }
bool BPTree_delete(BPTreeNode *root, uint64_t key) { bool BPTree_delete(BPTreeNode *root, uint64_t key) {
return _BPTree_delete(root, key, NULL); return _BPTree_delete(NULL, root, key);
} }
...@@ -20,7 +20,7 @@ void BPTree_destroy(BPTreeNode **root); ...@@ -20,7 +20,7 @@ void BPTree_destroy(BPTreeNode **root);
void BPTree_print(BPTreeNode *root, int depth); void BPTree_print(BPTreeNode *root, int depth);
bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data); bool BPTree_search(BPTreeNode *root, uint64_t key, uint64_t *data);
void BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data); bool BPTree_insert(BPTreeNode *root, uint64_t key, uint64_t data);
bool BPTree_delete(BPTreeNode *root, uint64_t key); bool BPTree_delete(BPTreeNode *root, uint64_t key);
#endif #endif
#include <stdio.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include "Directory.h" #include "Array.h"
#include "DirectoryRecord.h" #include "BPTree.h"
void clear_buffer() { int main() {
int c; BPTreeNode *root = BPTree_init(2);
while ((c = getchar()) != '\n' && c != EOF) {
}
}
void append_record(Directory *directory) {
char phone_number[PHONE_NUMBER_MAXLEN];
printf("Enter the phone number: ");
scanf("%10s", phone_number);
clear_buffer();
char name[NAME_MAXLEN];
printf("Enter the name: ");
scanf("%20s", name);
clear_buffer();
char surname[SURNAME_MAXLEN];
printf("Enter the surname: ");
scanf("%20s", surname);
clear_buffer();
int birth_date_year, birth_date_month, birth_date_day;
do {
printf("Enter the birth date (Y-m-d): ");
} while (scanf("%d-%d-%d", &birth_date_year, &birth_date_month, &birth_date_day) != 3);
clear_buffer();
printf("\nIs the information entered correct? (Y/n) ");
char choice = getchar();
if (choice != '\n') {
getchar();
}
if (choice == 'n') {
printf("\n===>The procedure has been cancelled.\n");
} else {
DirectoryRecord *record = DirectoryRecord_init(false, phone_number, name, surname, birth_date_year, birth_date_month, birth_date_day);
if (Directory_append(directory, record)) {
printf("\n===>The record has been saved in the directory.\n");
} else {
printf("\n===>This phone number is already associated with a record. The record has not been saved.\n");
}
DirectoryRecord_destroy(&record);
}
}
void search_record(Directory *directory) {
printf("Enter the phone number that corresponds to the record you are looking for: ");
char phone_number[PHONE_NUMBER_MAXLEN];
scanf("%10s", phone_number);
clear_buffer();
DirectoryRecord *record = Directory_search(directory, phone_number);
printf("\n");
if (record == NULL) { uint64_t input[] = {8, 12, 11, 47, 22, 95, 86, 40, 33, 78, 28, 5, 75, 88, 21, 56, 82, 51, 93, 66, 48, 70, 57, 65, 35, 4, 60, 41, 49, 55, 68, 72, 23, 31, 30, 42, 18, 87, 24, 58};
printf("===>No records were found for this phone number.\n"); IntegerArray *keys = IntegerArray_init(40);
} else { for (int i = 0; i < 30; i++) {
printf("========================\n"); IntegerArray_append(keys, input[i]);
DirectoryRecord_print(record);
DirectoryRecord_destroy(&record);
printf("========================\n");
} }
}
void delete_record(Directory *directory) {
printf("Enter the phone number that corresponds to the record you wish to delete: ");
char phone_number[PHONE_NUMBER_MAXLEN];
scanf("%10s", phone_number);
clear_buffer();
DirectoryRecord *record = Directory_search(directory, phone_number);
printf("\n");
if (record == NULL) { IntegerArray_print(keys);
printf("===>No records were found for this phone number.\n");
} else {
printf("========================\n");
DirectoryRecord_print(record);
DirectoryRecord_destroy(&record);
printf("========================\n");
printf("\nAre you sure you want to delete this record? (Y/n) "); for (int i = 0; i < keys->size; i++) {
BPTree_insert(root, keys->items[i], keys->items[i] * 1000);
char choice = getchar();
if (choice != '\n') {
getchar();
}
if (choice == 'n') {
printf("\n===>The procedure has been cancelled.\n");
} else {
Directory_delete(directory, phone_number);
printf("Delete done\n");
}
} }
}
int main() {
Directory *directory = Directory_init("directory_database");
while (true) {
BPTree_print(directory->index, 0);
printf("Enter 1 to add a member.\n");
printf("Enter 2 to search for a member via their phone number.\n");
printf("Enter 3 to delete a member.\n");
printf("Enter 4 to display all members.\n");
printf("Enter 5 to exit the program.\n");
printf("What do you want to do? ");
int action;
scanf("%d", &action);
clear_buffer();
if (action < 1 || action > 5) {
system("clear");
continue;
}
if (action == 5) {
break;
}
printf("\n");
switch (action) { for (int i = 0; i < keys->size; i++) {
case 1: uint64_t data;
append_record(directory); bool found = BPTree_search(root, keys->items[i], &data);
break;
case 2:
search_record(directory);
break;
case 3:
delete_record(directory);
break;
case 4:
Directory_print(directory);
break;
}
printf("\nPress enter to continue..."); assert(found == true);
getchar(); assert(data == keys->items[i] * 1000);
system("clear");
} }
Directory_destroy(&directory); BPTree_delete(root, 65);
BPTree_delete(root, 57);
BPTree_delete(root, 47);
BPTree_delete(root, 28);
BPTree_delete(root, 51);
BPTree_insert(root, 100, 100 * 1000);
BPTree_delete(root, 48);
BPTree_delete(root, 41);
BPTree_delete(root, 60);
BPTree_delete(root, 5);
BPTree_delete(root, 8);
BPTree_delete(root, 21);
BPTree_delete(root, 86);
BPTree_delete(root, 100);
BPTree_delete(root, 88);
BPTree_delete(root, 95);
BPTree_delete(root, 49);
BPTree_delete(root, 56);
BPTree_delete(root, 55);
BPTree_print(root, 0);
IntegerArray_destroy(&keys);
BPTree_destroy(&root);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/**
* @file BPTreeTests.c
* @author Florian Burgener (florian.burgener@etu.hesge.ch)
* @brief Unit tests of the BPTree data structure.
* @version 1.0
* @date 2022-06-07
*/
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "../Array.h" #include "../Array.h"
...@@ -10,18 +16,13 @@ ...@@ -10,18 +16,13 @@
#define RANDOM_MIN 0 #define RANDOM_MIN 0
#define RANDOM_MAX 1000 #define RANDOM_MAX 1000
BPTreeNode *tree; void setUp() {
void setUp(void) {
} }
void tearDown(void) { void tearDown() {
if (tree != NULL) {
BPTree_destroy(&tree);
}
} }
// BEGIN : Compliance with B+ Tree rules // BEGIN : Functions that check that a B+ Tree is compliant with the rules
static BPTreeNode *find_first_leaf(BPTreeNode *root) { static BPTreeNode *find_first_leaf(BPTreeNode *root) {
if (root->is_leaf) { if (root->is_leaf) {
...@@ -218,7 +219,7 @@ static bool check_BPTree_compliance(BPTreeNode *root) { ...@@ -218,7 +219,7 @@ static bool check_BPTree_compliance(BPTreeNode *root) {
return is_compliant; return is_compliant;
} }
// END : BPTree Compliance // END : Functions that check that a B+ Tree is compliant with the rules
/** /**
* @brief Performs a linear search for an item in an array. * @brief Performs a linear search for an item in an array.
...@@ -271,7 +272,7 @@ static uint64_t transform_key_to_data(uint64_t key) { ...@@ -271,7 +272,7 @@ static uint64_t transform_key_to_data(uint64_t key) {
// **** BEGIN : test_BPTree_insert // **** BEGIN : test_BPTree_insert
static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(BPTreeNode **root, int order) { static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(int order) {
int size = 1; int size = 1;
// Test 10 times, variable i being the seed. // Test 10 times, variable i being the seed.
...@@ -282,16 +283,16 @@ static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_g ...@@ -282,16 +283,16 @@ static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_g
// will have the size of 1 then 2, 4, 8, 16, 32, ... // will have the size of 1 then 2, 4, 8, 16, 32, ...
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX); IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX);
*root = BPTree_init(order); BPTreeNode *root = BPTree_init(order);
for (int i = 0; i < keys->size; i++) { for (int i = 0; i < keys->size; i++) {
BPTree_insert(*root, keys->items[i], transform_key_to_data(keys->items[i])); BPTree_insert(root, keys->items[i], transform_key_to_data(keys->items[i]));
// After each insertion is verified that the B+ Tree is compliant with the rules. // After each insertion is verified that the B+ Tree is compliant with the rules.
TEST_ASSERT(check_BPTree_compliance(*root)); TEST_ASSERT(check_BPTree_compliance(root));
} }
IntegerArray_destroy(&keys); IntegerArray_destroy(&keys);
BPTree_destroy(root); BPTree_destroy(&root);
size *= 2; size *= 2;
} }
...@@ -301,34 +302,34 @@ static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_g ...@@ -301,34 +302,34 @@ static void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_g
} }
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_1() { void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_1() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 1); test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(1);
} }
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_2() { void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_2() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 2); test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(2);
} }
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_3() { void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_3() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 3); test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(3);
} }
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_4() { void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_4() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 4); test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(4);
} }
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_8() { void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_8() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 8); test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(8);
} }
void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_16() { void test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_order_16() {
test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 16); test_BPTree_insert_should_comply_with_BPTree_rules_using_BPTree_of_given_order(16);
} }
// **** END : test_BPTree_insert // **** END : test_BPTree_insert
// **** BEGIN : test_BPTree_delete // **** BEGIN : test_BPTree_delete
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(BPTreeNode **root, int order) { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(int order) {
int size = 1; int size = 1;
// Test 10 times, variable i being the seed. // Test 10 times, variable i being the seed.
...@@ -339,20 +340,20 @@ void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_or ...@@ -339,20 +340,20 @@ void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_or
// will have the size of 1 then 2, 4, 8, 16, 32, ... // will have the size of 1 then 2, 4, 8, 16, 32, ...
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX); IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX);
*root = BPTree_init(order); BPTreeNode *root = BPTree_init(order);
for (int i = 0; i < keys->size; i++) { for (int i = 0; i < keys->size; i++) {
BPTree_insert(*root, keys->items[i], transform_key_to_data(keys->items[i])); BPTree_insert(root, keys->items[i], transform_key_to_data(keys->items[i]));
} }
while (keys->size > 0) { while (keys->size > 0) {
int index = rand() % keys->size; int index = rand() % keys->size;
BPTree_delete(*root, keys->items[index]); BPTree_delete(root, keys->items[index]);
IntegerArray_delete_at_index(keys, index); IntegerArray_delete_at_index(keys, index);
} }
IntegerArray_destroy(&keys); IntegerArray_destroy(&keys);
BPTree_destroy(root); BPTree_destroy(&root);
size *= 2; size *= 2;
} }
...@@ -362,34 +363,34 @@ void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_or ...@@ -362,34 +363,34 @@ void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_or
} }
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_1() { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_1() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 1); test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(1);
} }
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_2() { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_2() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 2); test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(2);
} }
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_3() { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_3() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 3); test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(3);
} }
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_4() { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_4() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 4); test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(4);
} }
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_8() { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_8() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 8); test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(8);
} }
void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_16() { void test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_order_16() {
test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(&tree, 16); test_BPTree_delete_should_comply_with_BPTree_rules_using_BPTree_of_given_order(16);
} }
// **** END : test_BPTree_delete // **** END : test_BPTree_delete
// **** BEGIN : test_BPTree_search // **** BEGIN : test_BPTree_search
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(BPTreeNode **root, int order) { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(int order) {
int size = 256; int size = 256;
// Test 10 times, variable i being the seed. // Test 10 times, variable i being the seed.
...@@ -397,47 +398,47 @@ void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTr ...@@ -397,47 +398,47 @@ void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTr
srand(i); srand(i);
IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX); IntegerArray *keys = generate_random_numbers_array(size, RANDOM_MIN, RANDOM_MAX);
*root = BPTree_init(order); BPTreeNode *root = BPTree_init(order);
for (int i = 0; i < keys->size; i++) { for (int i = 0; i < keys->size; i++) {
BPTree_insert(*root, keys->items[i], transform_key_to_data(keys->items[i])); BPTree_insert(root, keys->items[i], transform_key_to_data(keys->items[i]));
} }
for (int i = 0; i < keys->size; i++) { for (int i = 0; i < keys->size; i++) {
uint64_t data; uint64_t data;
bool is_found = BPTree_search(*root, keys->items[i], &data); bool is_found = BPTree_search(root, keys->items[i], &data);
TEST_ASSERT(is_found); TEST_ASSERT(is_found);
TEST_ASSERT_EQUAL_UINT64(transform_key_to_data(keys->items[i]), data); TEST_ASSERT_EQUAL_UINT64(transform_key_to_data(keys->items[i]), data);
} }
IntegerArray_destroy(&keys); IntegerArray_destroy(&keys);
BPTree_destroy(root); BPTree_destroy(&root);
} }
} }
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_1() { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_1() {
test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(&tree, 1); test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(1);
} }
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_2() { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_2() {
test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(&tree, 2); test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(2);
} }
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_3() { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_3() {
test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(&tree, 3); test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(3);
} }
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_4() { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_4() {
test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(&tree, 4); test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(4);
} }
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_8() { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_8() {
test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(&tree, 8); test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(8);
} }
void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_16() { void test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_order_16() {
test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(&tree, 16); test_BPTree_search_should_find_the_keys_that_exist_in_the_BPTree_using_BPTree_of_given_order(16);
} }
// **** END : test_BPTree_search // **** END : test_BPTree_search
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment