From 4b95be1e31c6cc81b60797a2c6eb297cfd740728 Mon Sep 17 00:00:00 2001 From: VaclavT Date: Wed, 4 Aug 2021 23:10:13 +0200 Subject: [PATCH] some code experiments --- Readme.md | 2 - tmp/CMakeLists.txt | 23 +++ tmp/bTree.cpp | 431 +++++++++++++++++++++++++++++++++++++++++++++ tmp/bTree.h | 116 ++++++++++++ tmp/main.cpp | 45 +++++ wip.sql | 0 6 files changed, 615 insertions(+), 2 deletions(-) create mode 100644 tmp/CMakeLists.txt create mode 100644 tmp/bTree.cpp create mode 100644 tmp/bTree.h create mode 100644 tmp/main.cpp create mode 100644 wip.sql diff --git a/Readme.md b/Readme.md index 6b90f75..561db20 100644 --- a/Readme.md +++ b/Readme.md @@ -1,8 +1,6 @@ ### TODO -- support for distinct - command line interface -- better table print - support for order by, offset, limit (allow column name in order by, validate) - add count min and max functions, eg aggregate functions - support for uniqueue indexes diff --git a/tmp/CMakeLists.txt b/tmp/CMakeLists.txt new file mode 100644 index 0000000..f7ac3de --- /dev/null +++ b/tmp/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.0) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") + + +project(main) + +set(PROJECT_NAME main) + +include_directories(${CMAKE_SOURCE_DIR}}) + +set(SOURCE + main.cpp) + +add_executable(${PROJECT_NAME} ${SOURCE}) + +target_link_libraries(${PROJECT_NAME} stdc++ m) + +target_compile_options(main PRIVATE -g) diff --git a/tmp/bTree.cpp b/tmp/bTree.cpp new file mode 100644 index 0000000..c3fe951 --- /dev/null +++ b/tmp/bTree.cpp @@ -0,0 +1,431 @@ +/* B-Tree + * Author: Caleb Baker + * Date: 10/8/17 + * Summary: A B-Tree data structure. Supports lg(n) time search, insert, and delete. + */ + + + + +#include +#include +#include + + +using namespace std; + + +#define NEW_ROOT 2 +#define MODIFIED_NOT_ROOT 1 +#define NOT_MODIFIED 0 + + +// Constructor for b tree. +// t is the minimum degree of the tree. +// compare is the comparison function used for managing elements within the tree. +// printK is a function that prints keys. +template +BTree::BTree(unsigned t, bool (*compare)(T, T), void (*printK)(T)) { + minDegree = t; + lessThan = compare; + root = (BNode*) malloc(sizeof(BNode)); + initializeNode(root); + root->leaf = true; + printKey = printK; +} + + +// Destructor. +template +BTree::~BTree() { + freeNode(root); +} + + +// Inserts the key k into the tree. +template +void BTree::insert(T k) { + + // Grow upwards if the root is full. + if (root->size == 2 * minDegree - 1) { + BNode *newRoot = (BNode*) malloc(sizeof(BNode)); + initializeNode(newRoot); + newRoot->leaf = false; + newRoot->child[0] = root; + root = newRoot; + splitChild(newRoot, 0); + } + + // Work down the tree. + BNode *curr = root; + while (!curr->leaf) { + + // Find the proper child to go to. + int index = curr->size - 1; + while (index >= 0 && lessThan(k, curr->key[index])) { + index--; + } + index++; + + // Split child if full. + if (curr->child[index]->size == 2 * minDegree - 1) { + splitChild(curr, index); + if (lessThan(curr->key[index], k)) { + index++; + } + } + curr = curr->child[index]; + } + + nodeInsert(curr, k); +} + + +// Removes k from the tree. Returns the removed key. +// Throws a BTREE_EXCEPTION if key is not found. +template +T BTree::remove(T k) { + BNode *curr = root; + while (true) { + unsigned i = findIndex(curr, k); + + // If the item to be deleted has been found. + if (i < curr->size && !(lessThan(curr->key[i], k) || lessThan(k, curr->key[i]))) { + T toReturn = curr->key[i]; + + // If at a leaf, just delete it. + if (curr->leaf) { + nodeDelete(curr, i); + } + + // Otherwise replace with predecessor/successor or merge children. + else { + BNode *leftKid = curr->child[i]; + BNode *rightKid = curr->child[i + 1]; + + // Replace with predecessor. + if (leftKid->size >= minDegree) { + while (!(leftKid->leaf)) { + fixChildSize(leftKid, leftKid->size); + leftKid = leftKid->child[leftKid->size]; + } + curr->key[i] = nodeDelete(leftKid, leftKid->size - 1); + } + + // Replace with successor + else if (rightKid->size >= minDegree) { + while (!(rightKid->leaf)) { + fixChildSize(rightKid, 0); + rightKid = rightKid->child[0]; + } + curr->key[i] = nodeDelete(rightKid, 0); + } + + // Merge children and move down the tree. + else { + mergeChildren(curr, i); + curr = leftKid; + continue; + } + } + return toReturn; + } + + // If the item has not been found, move down the tree. + else { + + // If at a leaf, then the item isn't present. + if (curr->leaf) { + throw (BTREE_EXCEPTION) REMOVE_KEY_NOT_FOUND; + } + + // Adjust curr and move down the tree. + char result = fixChildSize(curr, i); + if (result == NEW_ROOT) { + curr = root; + } + else { + curr = curr->child[findIndex(curr, k)]; + } + } + } +} + + +// Function to find a key in the tree. +// returnValue.first is the node the item is in. +// returnValue.second is the correct index in that node's key array +template +pair*, unsigned> BTree::search(T k) { + + // Start at root. + BNode *x = root; + + // Work down the tree. + while (true) { + + // Find the proper index in the current node's array. + unsigned i = findIndex(x, k); + + // Found it! + if (i < x->size && !(lessThan(k, x->key[i]) || lessThan(x->key[i], k))) { + return pair*, unsigned>(x, i); + } + + // Hit the bottom of the tree. + else if (x->leaf) { + return pair*, unsigned>(NULL, 0); + } + + // Keep going. + else { + x = x->child[i]; + } + } +} + + +// Function to find a key in the tree. +// Returns the key. +// If the item was not found an exception is thrown. +template +T BTree::searchKey(T k) { + pair*, unsigned> node = search(k); + if (node.first == NULL) { + throw (BTREE_EXCEPTION) SEARCH_KEY_NOT_FOUND; + } + return node.first->key[node.second]; +} + + +// Function for printing a tree. +template +void BTree::print() { + if (printKey != NULL && root != NULL) { + printf("\n"); + printNode(root, 0); + printf("\n"); + } +} + + +// Initialize a b tree node. +// x is a pointer to the node +// t is the minimum degree of the tree. +template +void BTree::initializeNode(BNode *x) { + x->size = 0; + x->key = (T*) malloc((2 * minDegree - 1) * sizeof(T)); + x->child = (BNode**) malloc(2 * minDegree * sizeof(BNode*)); +} + + +// Recursively deletes the subtree rooted at x. +// Does the dirty work for the destructor. +template +void BTree::freeNode(BNode *x) { + if (!x->leaf) { + for (unsigned i = 0; i <= x->size; i++) { + freeNode(x->child[i]); + } + } + free(x->child); + free(x->key); + free(x); +} + + +// Finds the index of k in x->key. +// If k is not present, returns the index of the subtree +// that could contain k in x->child. +template +unsigned BTree::findIndex(BNode *x, T k) { + unsigned i = 0; + while (i < x->size && lessThan(x->key[i], k)) { + i++; + } + return i; +} + + +// Inserts k into x. +// Returns the index of k in x->key. +template +unsigned BTree::nodeInsert(BNode *x, T k) { + int index; + + // Make room for k. + for (index = x->size; index > 0 && lessThan(k, x->key[index - 1]); index--) { + x->key[index] = x->key[index - 1]; + x->child[index + 1] = x->child[index]; + } + + // Insert k. + x->child[index + 1] = x->child[index]; + x->key[index] = k; + x->size++; + + return index; +} + + +// Deletes the indexth element from x->key. +// Returns deleted key. +template +T BTree::nodeDelete(BNode *x, unsigned index) { + + T toReturn = x->key[index]; + + x->size--; + while (index < x->size) { + x->key[index] = x->key[index + 1]; + x->child[index + 1] = x->child[index + 2]; + index++; + } + return toReturn; +} + + +// Function for splitting nodes that are too full. +// x points to the parent of the node to splits. +// i is the index in x's child array of the node to split. +template +void BTree::splitChild(BNode *x, int i) { + + // z is the new node and y is the node to split. + BNode *toSplit = x->child[i]; + BNode* newNode = (BNode*) malloc(sizeof(BNode));; + initializeNode(newNode); + newNode->leaf = toSplit->leaf; + newNode->size = minDegree - 1; + + // Copy the second half of y's keys and children into z. + for (unsigned j = 0; j < minDegree - 1; j++) { + newNode->key[j] = toSplit->key[j + minDegree]; + } + if (!toSplit->leaf) { + for (unsigned j = 0; j < minDegree; j++) { + newNode->child[j] = toSplit->child[j + minDegree]; + } + } + toSplit->size = minDegree - 1; + + nodeInsert(x, toSplit->key[minDegree - 1]); + x->child[i + 1] = newNode; +} + + +// Merges the (i + 1)th child of parent with the ith child of parent. +// Returns an indicator of whether the change affected the root. +template +char BTree::mergeChildren(BNode *parent, unsigned i) { + + BNode *leftKid = parent->child[i]; + BNode *rightKid = parent->child[i + 1]; + + // Move item from parent to left child. + leftKid->key[leftKid->size] = nodeDelete(parent, i); + unsigned j = ++(leftKid->size); + + // Move everything from rightKid into leftKid + for (unsigned k = 0; k < rightKid->size; k++) { + leftKid->key[j + k] = rightKid->key[k]; + leftKid->child[j + k] = rightKid->child[k]; + } + leftKid->size += rightKid->size; + leftKid->child[leftKid->size] = rightKid->child[rightKid->size]; + + // Free the memory used by rightChild + free(rightKid->child); + free(rightKid->key); + free(rightKid); + + // If parent is empty, than it must have been the root. + if (parent->size == 0) { + root = leftKid; + free(parent->child); + free(parent->key); + free(parent); + return NEW_ROOT; + } + + return MODIFIED_NOT_ROOT; +} + + +// Makes sure parent->child[index] has at least minDegree items. +// If it doesn't, then things are changed to make sure it does. +// Returns a code indicating what action was taken. +template +char BTree::fixChildSize(BNode *parent, unsigned index) { + BNode *kid = parent->child[index]; + + // If things need fixed. + if (kid->size < minDegree) { + + // Borrow from left sibling if possible. + if (index != 0 && parent->child[index - 1]->size >= minDegree) { + BNode *leftKid = parent->child[index - 1]; + + // When there are numerous equivalent keys, + // nodeInsert can insert into an index other than 0. + // The for loop fixed child pointers if that happens. + for (unsigned i = nodeInsert(kid, parent->key[index - 1]); i != 0; i--) { + kid->child[i] = kid->child[i - 1]; + } + kid->child[0] = leftKid->child[leftKid->size]; + parent->key[index - 1] = nodeDelete(leftKid, leftKid->size - 1); + } + + // Borrow from right sibling if possible + else if (index != parent->size && parent->child[index + 1]->size >= minDegree) { + BNode *rightKid = parent->child[index + 1]; + // Move curr->key[i] into kid->key + nodeInsert(kid, parent->key[index]); + kid->child[kid->size] = rightKid->child[0]; + rightKid->child[0] = rightKid->child[1]; + // Move rightKid->key[0] into curr->key + parent->key[index] = nodeDelete(rightKid, 0); + } + + // If borrowing is not possible, then merge. + else if (index != 0) { + return mergeChildren(parent, index - 1); + } + else { + return mergeChildren(parent, index); + } + return MODIFIED_NOT_ROOT; + } + + // If things don't need fixed. + return NOT_MODIFIED; +} + + +// Recursize function for printing a tree or subtree. +// node is the root of the subtree to be printed. +// tab is how far to indent the subtree. +template +void BTree::printNode(BNode *node, unsigned tab) { + + // Indent + for (unsigned i = 0; i < tab; i++) { + printf("\t"); + } + + // Print the current node. + for (unsigned i = 0; i < node->size; i++) { + printKey(node->key[i]); + printf(" "); + } + printf("\n"); + + // Print all child nodes. + if (!node->leaf) { + tab++; + for (unsigned i = 0; i <= node->size; i++) { + printNode(node->child[i], tab); + } + } +} \ No newline at end of file diff --git a/tmp/bTree.h b/tmp/bTree.h new file mode 100644 index 0000000..16ae44c --- /dev/null +++ b/tmp/bTree.h @@ -0,0 +1,116 @@ +/* B-Tree + * Author: Caleb Baker + * Date: 10/8/17 + * Summary: A B-Tree data structure. + * Most standard operations run in O(lg(n)) time. + * Uses O(n) memory. + * Where n is the number of items in the tree. + */ + + +#pragma once + +#include + +// #define NULL 0 +#define SEARCH_KEY_NOT_FOUND 's' +#define REMOVE_KEY_NOT_FOUND 'r' + + +// struct for representing nodes of a b tree +template +struct BNode { + BNode **child; // Array of pointers to children. + T *key; // Array of keys. + unsigned size; // Number of keys. + bool leaf; // Whether the node is a leaf. +}; + + +typedef char BTREE_EXCEPTION; + + +// class for representing b trees. +template +class BTree { +public: + // Constructor + // First parameter is the minimum degree of the tree. + // Second parameter is the tree's key-comparison function. + // Third parameter is a function that prints keys. + // Constant time. + BTree(unsigned, bool (*)(T, T), void (*)(T) = NULL); + + // Destructor. + // Linear time. + ~BTree(); + + // Inserts a key into the tree. + // Logorithmic time. + void insert(T); + + // Removes a key from the tree. + // Throws a BTREE_EXCEPTION if no item was found to remove. + // Logorithmic time. + T remove(T); + + // Function to find a key in the tree. + // returnValue.first is the node the item is in. + // returnValue.second is the correct index in that node's key array + // Logorithmic time. + std::pair*, unsigned> search(T); + + // Uses search but just returns the key rather than the whole node. + // Useful when T is a key value pair and lessThan only looks at the key. + // Throws a BTREE_EXCEPTION if no item matching the parameter is found + // Logorithmic time. + T searchKey(T); + + // Prints the tree. + // Linear time + void print(); + +private: + + // Used for initializing nodes. + void initializeNode(BNode*); + + // Recursive function called by destructor. + void freeNode(BNode*); + + // Finds the index of a key in a node. + unsigned findIndex(BNode*, T); + + // Inserts a key into a node. + unsigned nodeInsert(BNode*, T); + + // Deletes the key at a given index from a node. + T nodeDelete(BNode*, unsigned); + + // Function for splitting nodes that are too full. + void splitChild(BNode*, int); + + // Merges two children of a node at a given index into one child. + char mergeChildren(BNode*, unsigned); + + // Makes sure the child of a node at a specified index has >= minDegree items. + char fixChildSize(BNode*, unsigned); + + // Recursively prints a subtree. + void printNode(BNode*, unsigned); + + // Root node. + BNode *root; + + // Comparison function used for managing element placement. + bool (*lessThan)(T, T); + + // Function used to print items in the tree. + void (*printKey)(T); + + // Minimum degree of the tree. + unsigned minDegree; +}; + + +#include "bTree.cpp" \ No newline at end of file diff --git a/tmp/main.cpp b/tmp/main.cpp new file mode 100644 index 0000000..ad19eb7 --- /dev/null +++ b/tmp/main.cpp @@ -0,0 +1,45 @@ +#include +#include "bTree.h" + +bool compare(int a, int b) { + return a < b; +}; + +void print(int a) { + std::cout << a << std::endl; +}; + +int main(int argc, char *argv[]) { + + BTree bt(4, compare, print); + + bt.insert(1); + bt.insert(2); + bt.insert(3); + bt.insert(3); + bt.insert(3); + bt.insert(3); + bt.insert(3); + bt.insert(3); + bt.insert(3); + bt.insert(3); + bt.insert(4); + bt.insert(5); + bt.insert(6); + bt.insert(7); + bt.insert(7); + bt.insert(7); + bt.insert(7); + bt.insert(7); + + + + bt.print(); + + auto r = bt.search(7); + auto r1 = bt.searchKey(3); + auto r2 = bt.remove(2); + auto r3 = bt.search(2); + + return 0; +} \ No newline at end of file diff --git a/wip.sql b/wip.sql new file mode 100644 index 0000000..e69de29