├── LICENSE ├── README.md ├── src ├── BT_Impl │ ├── BTImplementation.c │ ├── BTInit.h │ └── make.inc └── CBT_Impl │ ├── CBTImplementation.c │ ├── CBTInit.h │ └── make.inc └── test ├── Init_ptr.h ├── Main.c └── Makefile /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Spiros Chalkias 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Complete Binary Tree 2 | 3 | ### A Generic Complete Binary Tree implementation , with O(1) [Amortized Complexity](https://en.wikipedia.org/wiki/Amortized_analysis) in : 4 | > - #### Insertion 5 | 6 | ### & O(1) Complexity in : 7 | 8 | > - #### Removal of last node 9 | > - #### Getting the last node 10 | 11 | ## Usage 12 | ### Run with Default Arguments 13 | ```c 14 | $ cd ~/O1-CompleteBT/CBT_Impl 15 | ``` 16 | #### Set Strings as tree items (Default): 17 | ```c 18 | $ make run 19 | ``` 20 | or 21 | ```c 22 | $ make run ITEM_TYPE=str 23 | ``` 24 | #### Set Integers as tree items: 25 | ```c 26 | $ make run ITEM_TYPE=int 27 | ``` 28 | ### Run with Custom Arguments 29 | 30 | ```c 31 | $ cd ~/O1-CompleteBT/CBT_Impl 32 | 33 | $ make 34 | 35 | $ ./O1_cbt 36 | ``` 37 | 38 | **Note :** *Running with default arguments, will create and print a Complete Binary Tree consisting of 22 nodes. 39 | (size_of_tree = 22). 40 | Then, there will be 100.000 , 1.000.000 and 10.000.000 insertions and removals in order to demonstrate O(1) Amortized Complexity. 41 | (minimum_num_of_elements = 100.000 , maximum_num_of_elements = 10.000.000)* 42 | 43 | 44 | 45 | ### Clean 46 | 47 | ```c 48 | $ make clean 49 | ``` 50 | 51 | ### Check for memory leaks (Requires [Valgrind](https://valgrind.org/) installation) 52 | 53 | ```c 54 | $ make check 55 | ``` 56 | -------------------------------------------------------------------------------- /src/BT_Impl/BTImplementation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "BTInit.h" 5 | 6 | bool BTIsNil (BTNode p) { return p == NULL; } 7 | 8 | BTree BTCreate (DestroyFunc destroyVal , PrintFunc printVal) { 9 | BTree newTree; /* Create a main tree block */ 10 | assert ((newTree = malloc (sizeof(struct main_tree)))); 11 | newTree->tree = NULL; 12 | newTree->last = NULL; 13 | newTree->size = 0; 14 | newTree->destroyValue = destroyVal; 15 | newTree->printValue = printVal; 16 | printf("Tree created successfully!\n\n"); 17 | 18 | return newTree; 19 | } 20 | 21 | static void BTsetNode (BTNode node ,BTItem item, BTNode left, BTNode right, BTNode parent, BTNode back) { 22 | /* Set given node's interior */ 23 | assert(node); 24 | node->item = item; 25 | node->left = left; 26 | node->right = right; 27 | node->parent = parent; 28 | node->back = back; 29 | } 30 | 31 | uint32_t BTSize (BTree p) { return p->size; } 32 | 33 | BTNode BTGetRoot(BTree p) { return p->tree; } /* Return the root */ 34 | 35 | BTNode BTGetParent(BTree head ,BTNode node) { 36 | /* If node's parent exists return it */ 37 | return ( (BTIsNil(BTGetRoot(head)) ) || ( BTIsNil(node) )) ? NULL : node->parent; 38 | } 39 | 40 | BTNode BTGetChildLeft(BTree head, BTNode node) { 41 | /* If the tree or the given node is NULL, return NULL */ 42 | /* If the left child exists, return it */ 43 | return ( (BTIsNil(BTGetRoot(head)) ) || ( BTIsNil(node) )) ? NULL : node->left; 44 | } 45 | 46 | BTNode BTGetChildRight(BTree head, BTNode node) { 47 | /* If the tree or the given node is NULL, return NULL */ 48 | /* If the right child exists, return it */ 49 | return ( (BTIsNil(BTGetRoot(head)) ) || ( BTIsNil(node) )) ? NULL : node->right; 50 | } 51 | 52 | BTItem BTGetItem(BTNode node) { return node->item; } 53 | 54 | void BTInsertRoot(BTree head, BTItem item) { 55 | assert(head); 56 | if (BTIsNil(BTGetRoot(head))) { 57 | assert((head->tree = malloc(sizeof(BTNodes )))); /* Allocate memory for new node */ 58 | 59 | BTsetNode(head->tree , item , NULL , NULL , NULL , NULL); 60 | 61 | head->last = BTGetRoot(head); 62 | head->size++; 63 | return; 64 | } 65 | printf("Tree has already a root.\nRoot insertion failed.\n"); 66 | } 67 | 68 | void BTInsertLeft(BTree head, BTNode node, BTItem item) { 69 | assert(head); 70 | /* If the tree doesn't exist, inform the user. */ 71 | if (BTIsNil( BTGetRoot(head ))) 72 | printf("Tree is empty.\n"); 73 | /* If the node's left child doesn't exist, create one */ 74 | else if (!BTIsNil(node) && BTIsNil(BTGetChildLeft(head,node))) { 75 | 76 | assert((node->left = malloc(sizeof(BTNodes)))); 77 | 78 | BTsetNode(node->left , item , NULL , NULL , node , head->last); 79 | 80 | head->last = node->left; 81 | head->size++; 82 | } 83 | /* If the node has already a left child, inform the user. */ 84 | else printf("Attempt to insert a left child to a non-empty position.\n"); 85 | } 86 | 87 | void BTInsertRight(BTree head, BTNode node, BTItem item) { 88 | assert(head); 89 | /* If the tree doesn't exist, inform the user. */ 90 | if (BTIsNil( BTGetRoot(head ))) 91 | printf("Tree is empty.\n"); 92 | /* If the node's right child doesn't exist, create one */ 93 | else if (!BTIsNil(node) && BTIsNil(BTGetChildRight(head,node))) { 94 | 95 | assert((node->right=malloc(sizeof(BTNodes)))); 96 | 97 | BTsetNode(node->right , item , NULL , NULL , node , head->last); 98 | 99 | head->last = node->right; 100 | head->size++; 101 | } 102 | /* If the node has already a right child, inform the user. */ 103 | else printf("Attempt to insert a right child to a non-empty position.\n"); 104 | } 105 | 106 | void BTRemoveLeaf(BTree head , BTNode node ) { 107 | /* If the tree is empty, return */ 108 | if (head == NULL || BTIsNil(BTGetRoot(head))) return; 109 | 110 | /* Check whether the given node is a leaf */ 111 | if (BTGetChildLeft(head,node) || BTGetChildRight(head,node)) { 112 | printf("Used function to remove a non-leaf node.\nRemoval failed.\n"); 113 | return; 114 | } 115 | 116 | BTNode parent = BTGetParent(head,node); 117 | if (!BTIsNil(parent)) { 118 | 119 | if (parent->left == node) 120 | parent->left = NULL; 121 | 122 | else parent->right = NULL; 123 | 124 | head->destroyValue(BTGetItem(node)); 125 | free(node); 126 | } else { 127 | 128 | head->destroyValue(BTGetItem(BTGetRoot(head))); 129 | free(BTGetRoot(head)); 130 | head->tree = NULL; 131 | } 132 | head->size--; 133 | } 134 | 135 | /* Pretty print tree */ 136 | void BTreePrint(BTree tree ,BTNode node ,int indent) 137 | { 138 | if (tree == NULL || BTIsNil(node)) return ; 139 | /* If tree is not empty */ 140 | if (!BTIsNil(BTGetRoot(tree))) { 141 | /* Print right subtree 4 places right of root node */ 142 | BTreePrint(tree ,BTGetChildRight(tree,node) ,indent + 4); 143 | 144 | for (unsigned int i = 0 ; i < indent ; i++) 145 | printf(" "); /* Take care for indentation */ 146 | tree->printValue(BTGetItem(node)); /* Print root node */ 147 | /* Print left subtree 4 places right of root node */ 148 | BTreePrint(tree ,BTGetChildLeft(tree,node) ,indent + 4); 149 | } 150 | } 151 | /*=======================================|| E N D O F F I L E ||=======================================*/ -------------------------------------------------------------------------------- /src/BT_Impl/BTInit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Init_ptr.h" 4 | 5 | /*===================================|| S T R U C T S ||===================================*/ 6 | 7 | typedef struct tnode *BTNode; /* Our nodes are called BTNodes */ 8 | typedef void (*DestroyFunc) (void *); 9 | typedef void (*PrintFunc) (void *); 10 | 11 | typedef struct tnode 12 | { 13 | BTItem item; 14 | BTNode left; /* Left child */ 15 | BTNode right; /* Right child */ 16 | BTNode back; /* Brother */ 17 | BTNode parent; /* Parent of node */ 18 | } BTNodes; 19 | 20 | typedef struct main_tree 21 | { 22 | uint32_t size; /* Number of treenodes */ 23 | BTNode last; 24 | BTNode tree; 25 | DestroyFunc destroyValue; 26 | PrintFunc printValue; 27 | 28 | } mainTree; 29 | 30 | typedef struct main_tree* BTree; 31 | 32 | /*===================================|| F U N C T I O N S ||===================================*/ 33 | 34 | BTree BTCreate ( DestroyFunc , PrintFunc ); 35 | 36 | BTItem BTGetItem ( BTNode ); 37 | 38 | BTNode BTGetRoot ( BTree ); 39 | 40 | uint32_t BTSize ( BTree ); 41 | 42 | bool BTIsNil ( BTNode ); 43 | 44 | void BTRemoveLeaf ( BTree , BTNode ); 45 | 46 | void BTInsertRoot ( BTree , BTItem ); 47 | 48 | BTNode BTGetParent ( BTree , BTNode ); 49 | 50 | BTNode BTGetChildLeft ( BTree , BTNode ); 51 | 52 | void BTreePrint ( BTree , BTNode , int ); 53 | 54 | BTNode BTGetChildRight ( BTree , BTNode ); 55 | 56 | void BTInsertLeft ( BTree , BTNode , BTItem ); 57 | 58 | void BTInsertRight ( BTree , BTNode , BTItem ); 59 | 60 | /*=======================================|| E N D O F F I L E ||=======================================*/ -------------------------------------------------------------------------------- /src/BT_Impl/make.inc: -------------------------------------------------------------------------------- 1 | # Makefile of BT Implementation in Modules 2 | 3 | CFLAGS+= -I$(MODULES)/BT_Impl 4 | 5 | OBJS += $(MODULES)/BT_Impl/BTImplementation.o 6 | 7 | ifeq ($(ITEM_TYPE),int) 8 | CFLAGS += -D INT 9 | else 10 | CFLAGS += -D STR 11 | endif 12 | -------------------------------------------------------------------------------- /src/CBT_Impl/CBTImplementation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "CBTInit.h" 4 | #include "BTInit.h" 5 | 6 | static void InsertFarLeft (CBTree tree ,CBTNode node ,CBTItem item) { 7 | 8 | if (BTIsNil(BTGetChildLeft(tree,node))){ /* We've found the far left node */ 9 | BTInsertLeft (tree,node,item); 10 | return; 11 | } 12 | InsertFarLeft(tree,BTGetChildLeft(tree,node),item); /* Continue to the left */ 13 | } 14 | 15 | static void RecInsert (CBTree tree ,CBTNode parent ,CBTNode last ,CBTItem item) { 16 | 17 | if (BTIsNil(parent)) InsertFarLeft(tree,BTGetRoot(tree),item); /* If the tree is full, insert the node far left */ 18 | else if (BTGetChildRight(tree,parent) == last) /* If the last node is a right child */ 19 | RecInsert(tree,BTGetParent(tree,parent),parent,item); /* Go up to its parent */ 20 | else { /* If the last node is a left child */ 21 | (BTIsNil(BTGetChildRight(tree,parent)))? BTInsertRight(tree,parent,item) : /* If its right brother in NULL, insert right */ 22 | InsertFarLeft(tree,BTGetChildRight(tree,parent),item); /* Else, insert the node as left as possible */ 23 | } 24 | } 25 | 26 | void CBTInsertLast(CBTree tree ,BTItem item) { 27 | 28 | if (BTIsNil(BTGetRoot(tree))) BTInsertRoot(tree,item); /* If we have 0 nodes , we insert the item instantly */ 29 | else RecInsert( tree , BTGetParent(tree,CBTGetLast(tree)) , CBTGetLast(tree),item ); 30 | } 31 | 32 | CBTNode CBTGetLast (CBTree head) { return head->last; } 33 | 34 | void CBTRemove(CBTree head,CBTNode node) { 35 | head->last=node->back; /* Update the last tree node */ 36 | BTRemoveLeaf(head , node); 37 | } 38 | /*=======================================|| E N D O F F I L E ||=======================================*/ -------------------------------------------------------------------------------- /src/CBT_Impl/CBTInit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BTInit.h" 4 | 5 | typedef BTNode CBTNode; 6 | 7 | typedef BTree CBTree; 8 | 9 | /*=======================================|| F U N C T I O N S ||=======================================*/ 10 | 11 | CBTNode CBTGetLast ( CBTree ); 12 | 13 | void CBTRemove ( CBTree , CBTNode ); 14 | 15 | void CBTInsertLast ( CBTree , CBTItem ); 16 | 17 | /*=======================================|| E N D O F F I L E ||=======================================*/ -------------------------------------------------------------------------------- /src/CBT_Impl/make.inc: -------------------------------------------------------------------------------- 1 | # Makefile of CBT Implementation in Modules 2 | 3 | include $(MODULES)/BT_Impl/make.inc 4 | 5 | CFLAGS+= -I$(MODULES)/CBT_Impl 6 | 7 | OBJS+= $(MODULES)/CBT_Impl/CBTImplementation.o -------------------------------------------------------------------------------- /test/Init_ptr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | typedef void * BTItem; /* Item can be anything ! */ 7 | 8 | typedef BTItem CBTItem; -------------------------------------------------------------------------------- /test/Main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "CBTInit.h" 5 | 6 | #ifdef INT 7 | 8 | void printItem(void * item) { 9 | printf("(%d)\n" , *(int *)item); 10 | } 11 | 12 | void destroyItem(void * item) { 13 | if (item != NULL) free((int *)item); 14 | } 15 | 16 | int* createItem(int value) { 17 | int* pointer = malloc(sizeof(int)); 18 | *pointer = value; 19 | return pointer; 20 | } 21 | 22 | #endif 23 | 24 | #ifdef STR 25 | 26 | #include 27 | 28 | static char * randomStrGen (void) { 29 | uint8_t size = rand()%10 + 1; 30 | char * str = malloc (size * sizeof(char)); 31 | for (uint8_t i = 0; i < size - 1; i++) { 32 | str[i] = (rand()%(122 - 65)) + 65; 33 | } 34 | str[size - 1] = '\0'; 35 | return str; 36 | } 37 | 38 | void printItem(void * item) { 39 | printf("(%s)\n" , (char *)item); 40 | } 41 | 42 | void destroyItem(void * item) { 43 | if (item != NULL) free((char *)item); 44 | } 45 | 46 | char* createItem(char * value) { 47 | char* pointer = strdup(value); 48 | return pointer; 49 | } 50 | 51 | #endif 52 | 53 | 54 | int main(int argc , char* argv[]) 55 | { 56 | if (argc != 4) { 57 | printf("Usage : ./O1_cbt \n"); 58 | exit(EXIT_FAILURE); 59 | } 60 | 61 | const uint32_t size = atoi(argv[1]); 62 | #define MINNUM atoi(argv[2]) 63 | #define MAXNUM atoi(argv[3]) 64 | 65 | clock_t t; 66 | 67 | const CBTree CBT = BTCreate(destroyItem , printItem); /* Create a tree */ 68 | 69 | for (uint32_t i = 0; i < size ; i++) 70 | #ifdef INT 71 | CBTInsertLast(CBT , createItem(rand()%50)); 72 | #else 73 | CBTInsertLast(CBT , createItem(randomStrGen())); 74 | #endif 75 | 76 | printf("Inserted %u elements in the tree.\n" , size); 77 | printf("Printing tree . .\n\n"); 78 | 79 | BTreePrint(CBT , BTGetRoot(CBT) , 2); 80 | 81 | for (uint32_t i = 0 ; i < size ; i++) 82 | CBTRemove(CBT , CBTGetLast(CBT)); 83 | printf("CBTree Destroyed.\n\n"); 84 | 85 | printf("Let's add some more elemets . . .\n\n\n"); 86 | 87 | for (uint32_t j=MINNUM ; j<=MAXNUM ; j*=10) { 88 | 89 | t = clock(); 90 | 91 | for (uint32_t i = 0 ; i < j ; i++) /* Insert elements */ 92 | #ifdef INT 93 | CBTInsertLast(CBT , createItem(rand()%1000000)); 94 | #else 95 | CBTInsertLast(CBT , createItem(randomStrGen())); 96 | #endif 97 | 98 | t = clock() - t; 99 | 100 | printf ("Took : %.3lf seconds to add %d elements.\n\n",((double) t) / CLOCKS_PER_SEC , BTSize(CBT)); 101 | 102 | t = clock(); 103 | 104 | for (uint32_t i = 0 ; i < j ; i++) /* Delete them */ 105 | CBTRemove(CBT , CBTGetLast(CBT)); 106 | 107 | t = clock() - t; 108 | 109 | printf ("Took : %.3lf seconds to delete them.\n\n",((double) t) / CLOCKS_PER_SEC); 110 | 111 | } 112 | 113 | free(CBT); 114 | 115 | return EXIT_SUCCESS; 116 | } -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile of CBT Implementation 2 | 3 | MODULES= ../src 4 | 5 | CFLAGS= -O3 -Wall -I . 6 | 7 | PROGRAM= O1_cbt 8 | 9 | OBJS= Main.o 10 | 11 | include $(MODULES)/CBT_Impl/make.inc 12 | 13 | $(PROGRAM): clean $(OBJS) 14 | gcc $(OBJS) -o $(PROGRAM) 15 | 16 | clean: 17 | rm -f $(PROGRAM) $(OBJS) 18 | 19 | run: $(PROGRAM) # Run with default arguments 20 | ./$(PROGRAM) 22 100000 10000000 21 | 22 | check: $(PROGRAM) # Check for memory leaks (Requires Valgrind Installation) 23 | valgrind ./$(PROGRAM) 22 10000 1000000 --------------------------------------------------------------------------------