# Different Data Structure Insertion and Search Time Test: ## B-tree (或B+tree)、treap、skip list、array of sorted arrays、hash table 程式碼: --- ### B+tree ```cpp= // Searching on a B+ tree in C++ // Searching on a B+ tree in C++ #include <climits> #include <fstream> #include <iostream> #include <sstream> #include <random> #include <chrono> using namespace std; int MAX = 3; // BP node class Node { bool IS_LEAF; int *key, size; Node **ptr; friend class BPTree; public: Node(); }; // BP tree class BPTree { Node *root; void insertInternal(int, Node *, Node *); Node *findParent(Node *, Node *); public: BPTree(); void search(int); void insert(int); void display(Node *); Node *getRoot(); }; Node::Node() { key = new int[MAX]; ptr = new Node *[MAX + 1]; } BPTree::BPTree() { root = NULL; } // Search operation void BPTree::search(int x) { if (root == NULL) { cout << "Tree is empty\n"; } else { Node *cursor = root; while (cursor->IS_LEAF == false) { for (int i = 0; i < cursor->size; i++) { if (x < cursor->key[i]) { cursor = cursor->ptr[i]; break; } if (i == cursor->size - 1) { cursor = cursor->ptr[i + 1]; break; } } } for (int i = 0; i < cursor->size; i++) { if (cursor->key[i] == x) { cout << "Found\n"; return; } } cout << "Not found\n"; } } // Insert Operation void BPTree::insert(int x) { if (root == NULL) { root = new Node; root->key[0] = x; root->IS_LEAF = true; root->size = 1; } else { Node *cursor = root; Node *parent; while (cursor->IS_LEAF == false) { parent = cursor; for (int i = 0; i < cursor->size; i++) { if (x < cursor->key[i]) { cursor = cursor->ptr[i]; break; } if (i == cursor->size - 1) { cursor = cursor->ptr[i + 1]; break; } } } if (cursor->size < MAX) { int i = 0; while (x > cursor->key[i] && i < cursor->size) i++; for (int j = cursor->size; j > i; j--) { cursor->key[j] = cursor->key[j - 1]; } cursor->key[i] = x; cursor->size++; cursor->ptr[cursor->size] = cursor->ptr[cursor->size - 1]; cursor->ptr[cursor->size - 1] = NULL; } else { Node *newLeaf = new Node; int virtualNode[MAX + 1]; for (int i = 0; i < MAX; i++) { virtualNode[i] = cursor->key[i]; } int i = 0, j; while (x > virtualNode[i] && i < MAX) i++; for (int j = MAX + 1; j > i; j--) { virtualNode[j] = virtualNode[j - 1]; } virtualNode[i] = x; newLeaf->IS_LEAF = true; cursor->size = (MAX + 1) / 2; newLeaf->size = MAX + 1 - (MAX + 1) / 2; cursor->ptr[cursor->size] = newLeaf; newLeaf->ptr[newLeaf->size] = cursor->ptr[MAX]; cursor->ptr[MAX] = NULL; for (i = 0; i < cursor->size; i++) { cursor->key[i] = virtualNode[i]; } for (i = 0, j = cursor->size; i < newLeaf->size; i++, j++) { newLeaf->key[i] = virtualNode[j]; } if (cursor == root) { Node *newRoot = new Node; newRoot->key[0] = newLeaf->key[0]; newRoot->ptr[0] = cursor; newRoot->ptr[1] = newLeaf; newRoot->IS_LEAF = false; newRoot->size = 1; root = newRoot; } else { insertInternal(newLeaf->key[0], parent, newLeaf); } } } } // Insert Operation void BPTree::insertInternal(int x, Node *cursor, Node *child) { if (cursor->size < MAX) { int i = 0; while (x > cursor->key[i] && i < cursor->size) i++; for (int j = cursor->size; j > i; j--) { cursor->key[j] = cursor->key[j - 1]; } for (int j = cursor->size + 1; j > i + 1; j--) { cursor->ptr[j] = cursor->ptr[j - 1]; } cursor->key[i] = x; cursor->size++; cursor->ptr[i + 1] = child; } else { Node *newInternal = new Node; int virtualKey[MAX + 1]; Node *virtualPtr[MAX + 2]; for (int i = 0; i < MAX; i++) { virtualKey[i] = cursor->key[i]; } for (int i = 0; i < MAX + 1; i++) { virtualPtr[i] = cursor->ptr[i]; } int i = 0, j; while (x > virtualKey[i] && i < MAX) i++; for (int j = MAX + 1; j > i; j--) { virtualKey[j] = virtualKey[j - 1]; } virtualKey[i] = x; for (int j = MAX + 2; j > i + 1; j--) { virtualPtr[j] = virtualPtr[j - 1]; } virtualPtr[i + 1] = child; newInternal->IS_LEAF = false; cursor->size = (MAX + 1) / 2; newInternal->size = MAX - (MAX + 1) / 2; for (i = 0, j = cursor->size + 1; i < newInternal->size; i++, j++) { newInternal->key[i] = virtualKey[j]; } for (i = 0, j = cursor->size + 1; i < newInternal->size + 1; i++, j++) { newInternal->ptr[i] = virtualPtr[j]; } if (cursor == root) { Node *newRoot = new Node; newRoot->key[0] = cursor->key[cursor->size]; newRoot->ptr[0] = cursor; newRoot->ptr[1] = newInternal; newRoot->IS_LEAF = false; newRoot->size = 1; root = newRoot; } else { insertInternal(cursor->key[cursor->size], findParent(root, cursor), newInternal); } } } // Find the parent Node *BPTree::findParent(Node *cursor, Node *child) { Node *parent; if (cursor->IS_LEAF || (cursor->ptr[0])->IS_LEAF) { return NULL; } for (int i = 0; i < cursor->size + 1; i++) { if (cursor->ptr[i] == child) { parent = cursor; return parent; } else { parent = findParent(cursor->ptr[i], child); if (parent != NULL) return parent; } } return parent; } // Print the tree void BPTree::display(Node *cursor) { if (cursor != NULL) { for (int i = 0; i < cursor->size; i++) { cout << cursor->key[i] << " "; } cout << "\n"; if (cursor->IS_LEAF != true) { for (int i = 0; i < cursor->size + 1; i++) { display(cursor->ptr[i]); } } } } // Get the root Node *BPTree::getRoot() { return root; } int main() { BPTree node; int num; std::cin>>num; // Measure the time it takes to insert 1<<num values auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { node.insert(rand()%2147483648); } auto end = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Insertion Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; //print the data structure //node.display(node.getRoot()); // Search for the number auto start2 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { node.search(rand()%2147483647); } auto end2 = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Finding Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count() << " ms" << std::endl; } ``` ------ ### Treap ```cpp= // C++ program to demonstrate search, insert and delete in Treap #include <bits/stdc++.h> #include <random> #include <chrono> using namespace std; // A Treap Node struct TreapNode { int key, priority; TreapNode *left, *right; }; /* T1, T2 and T3 are subtrees of the tree rooted with y (on left side) or x (on right side) y x / \ Right Rotation / \ x T3 – – – – – – – > T1 y / \ < - - - - - - - / \ T1 T2 Left Rotation T2 T3 */ // A utility function to right rotate subtree rooted with y // See the diagram given above. TreapNode *rightRotate(TreapNode *y) { TreapNode *x = y->left, *T2 = x->right; // Perform rotation x->right = y; y->left = T2; // Return new root return x; } // A utility function to left rotate subtree rooted with x // See the diagram given above. TreapNode *leftRotate(TreapNode *x) { TreapNode *y = x->right, *T2 = y->left; // Perform rotation y->left = x; x->right = T2; // Return new root return y; } /* Utility function to add a new key */ TreapNode* newNode(int key) { TreapNode* temp = new TreapNode; temp->key = key; temp->priority = rand()%100; temp->left = temp->right = NULL; return temp; } // C function to search a given key in a given BST TreapNode* search(TreapNode* root, int key) { // Base Cases: root is null or key is present at root if (root == NULL || root->key == key) return root; // Key is greater than root's key if (root->key < key) return search(root->right, key); // Key is smaller than root's key return search(root->left, key); } /* Recursive implementation of insertion in Treap */ TreapNode* insert(TreapNode* root, int key) { // If root is NULL, create a new node and return it if (!root) return newNode(key); // If key is smaller than root if (key <= root->key) { // Insert in left subtree root->left = insert(root->left, key); // Fix Heap property if it is violated if (root->left->priority > root->priority) root = rightRotate(root); } else // If key is greater { // Insert in right subtree root->right = insert(root->right, key); // Fix Heap property if it is violated if (root->right->priority > root->priority) root = leftRotate(root); } return root; } // A utility function to print tree void inorder(TreapNode* root) { if (root) { inorder(root->left); cout << "key: "<< root->key << " | priority: %d " << root->priority; if (root->left) cout << " | left child: " << root->left->key; if (root->right) cout << " | right child: " << root->right->key; cout << endl; inorder(root->right); } } // Driver Program to test above functions int main() { srand(time(NULL)); struct TreapNode *root = NULL; int num; std::cin>>num; // Measure the time it takes to insert 1<<num values auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { root = insert(root, rand()%2147483648 ); } auto end = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Insertion Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; //print the data structure //ds.print(); // Search for the number auto start2 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { TreapNode *res = search(root, rand()%2147483647) } auto end2 = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Finding Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count() << " ms" << std::endl; //Search the data and get the result //TreapNode *res = search(root, 50); //(res == NULL)? cout << "\n50 Not Found ": // cout << "\n50 found"; ``` ------ ### Skip List ```cpp= // C++ code for searching and deleting element in skip list #include <bits/stdc++.h> #include <random> #include <chrono> using namespace std; // Class to implement node class Node { public: int key; // Array to hold pointers to node of different level Node **forward; Node(int, int); }; Node::Node(int key, int level) { this->key = key; // Allocate memory to forward forward = new Node*[level+1]; // Fill forward array with 0(NULL) memset(forward, 0, sizeof(Node*)*(level+1)); }; // Class for Skip list class SkipList { // Maximum level for this skip list int MAXLVL; // P is the fraction of the nodes with level // i pointers also having level i+1 pointers float P; // current level of skip list int level; // pointer to header node Node *header; public: SkipList(int, float); int randomLevel(); Node* createNode(int, int); void insertElement(int); void deleteElement(int); void searchElement(int); void displayList(); }; SkipList::SkipList(int MAXLVL, float P) { this->MAXLVL = MAXLVL; this->P = P; level = 0; // create header node and initialize key to -1 header = new Node(-1, MAXLVL); }; // create random level for node int SkipList::randomLevel() { float r = (float)rand()/RAND_MAX; int lvl = 0; while(r < P && lvl < MAXLVL) { lvl++; r = (float)rand()/RAND_MAX; } return lvl; }; // create new node Node* SkipList::createNode(int key, int level) { Node *n = new Node(key, level); return n; }; // Insert given key in skip list void SkipList::insertElement(int key) { Node *current = header; // create update array and initialize it Node *update[MAXLVL+1]; memset(update, 0, sizeof(Node*)*(MAXLVL+1)); /* start from highest level of skip list move the current pointer forward while key is greater than key of node next to current Otherwise inserted current in update and move one level down and continue search */ for(int i = level; i >= 0; i--) { while(current->forward[i] != NULL && current->forward[i]->key < key) current = current->forward[i]; update[i] = current; } /* reached level 0 and forward pointer to right, which is desired position to insert key. */ current = current->forward[0]; /* if current is NULL that means we have reached to end of the level or current's key is not equal to key to insert that means we have to insert node between update[0] and current node */ if (current == NULL || current->key != key) { // Generate a random level for node int rlevel = randomLevel(); /* If random level is greater than list's current level (node with highest level inserted in list so far), initialize update value with pointer to header for further use */ if(rlevel > level) { for(int i=level+1;i<rlevel+1;i++) update[i] = header; // Update the list current level level = rlevel; } // create new node with random level generated Node* n = createNode(key, rlevel); // insert node by rearranging pointers for(int i=0;i<=rlevel;i++) { n->forward[i] = update[i]->forward[i]; update[i]->forward[i] = n; } cout<<"Successfully Inserted key "<<key<<"\n"; } }; // Delete element from skip list void SkipList::deleteElement(int key) { Node *current = header; // create update array and initialize it Node *update[MAXLVL+1]; memset(update, 0, sizeof(Node*)*(MAXLVL+1)); /* start from highest level of skip list move the current pointer forward while key is greater than key of node next to current Otherwise inserted current in update and move one level down and continue search */ for(int i = level; i >= 0; i--) { while(current->forward[i] != NULL && current->forward[i]->key < key) current = current->forward[i]; update[i] = current; } /* reached level 0 and forward pointer to right, which is possibly our desired node.*/ current = current->forward[0]; // If current node is target node if(current != NULL and current->key == key) { /* start from lowest level and rearrange pointers just like we do in singly linked list to remove target node */ for(int i=0;i<=level;i++) { /* If at level i, next node is not target node, break the loop, no need to move further level */ if(update[i]->forward[i] != current) break; update[i]->forward[i] = current->forward[i]; } // Remove levels having no elements while(level>0 && header->forward[level] == 0) level--; cout<<"Successfully deleted key "<<key<<"\n"; } }; // Search for element in skip list void SkipList::searchElement(int key) { Node *current = header; /* start from highest level of skip list move the current pointer forward while key is greater than key of node next to current Otherwise inserted current in update and move one level down and continue search */ for(int i = level; i >= 0; i--) { while(current->forward[i] && current->forward[i]->key < key) current = current->forward[i]; } /* reached level 0 and advance pointer to right, which is possibly our desired node*/ current = current->forward[0]; // If current node have key equal to // search key, we have found our target node if(current and current->key == key) cout<<"Found key: "<<key<<"\n"; }; // Display skip list level wise void SkipList::displayList() { cout<<"\n*****Skip List*****"<<"\n"; for(int i=0;i<=level;i++) { Node *node = header->forward[i]; cout<<"Level "<<i<<": "; while(node != NULL) { cout<<node->key<<" "; node = node->forward[i]; } cout<<"\n"; } }; // Driver to test above code int main() { // Seed random number generator srand((unsigned)time(0)); // create SkipList object with MAXLVL and P SkipList lst(3, 0.5); int num; std::cin>>num; // Measure the time it takes to insert 1<<num values auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { lst.insert(rand()%2147483648 ); } auto end = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Insertion Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; //print the data structure //ds.print(); // Search for the number auto start2 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { lst.searchElement(rand()%2147483647); } auto end2 = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Finding Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count() << " ms" << std::endl; //print skip list //lst.displayList(); //Search for node 19 //Delete node 19 //lst.deleteElement(19); //lst.displayList(); } ``` ------ ### Array of sorted rrays ```cpp= #include <vector> #include <iostream> #include <algorithm> #include <random> #include <chrono> using namespace std; class DS { private: std::vector<int> _arr; std::vector<std::vector<int>> _vec_vec; int _vec_num; public: void print(); std::pair<int, int> find(int); public: DS() { _vec_num = 0; } void insert(int input) { _arr.push_back(input); for (int i = 0; i < _vec_vec.size(); i++) { if (!_vec_vec[i].empty()) { vector<int> merged(_arr.size() + _vec_vec[i].size()); std:: merge(_arr.begin(), _arr.end(), _vec_vec[i].begin(), _vec_vec[i].end(), merged.begin()); _arr = merged; _vec_vec[i].clear(); } else if (!_arr.empty()) { // Assign _arr to _vec_vec[i] and clear _arr _vec_vec[i] = _arr; _arr.clear(); break; } } if (!_arr.empty()) { // Push _arr to the end of _vec_vec and increment vec_num _vec_vec.push_back(_arr); _vec_num++; _arr.clear(); } } }; void DS::print() { std:: cout << "arrayOfSortedArrays: " << endl; for (int i = 0; i < _vec_vec.size(); ++i) { std:: cout << i << ": "; for (int j = 0; j < _vec_vec[i].size(); ++j) { std:: cout << _vec_vec[i][j] << ' '; } std:: cout << endl; } std:: cout << "Print end\n"; return; } // Function to find a given number in the DS data structure // and return an std::pair of integers containing the vector index // and position of the number within the vector std::pair<int, int> DS:: find(int number) { // Loop through the vectors in _vec_of_vec for (int i = 0; i < _vec_vec.size(); i++) { // Perform binary search on the current vector int left = 0; int right = _vec_vec[i].size() - 1; while (left <= right) { int mid = left + (right - left) / 2; if (_vec_vec[i][mid] == number) { // Return a pair containing the vector index and position of the number return std::make_pair(i, mid); } else if (_vec_vec[i][mid] < number) { left = mid + 1; } else { right = mid - 1; } } } // Return a pair with -1 as both elements if the number is not found return std::make_pair(-1, -1); } int main() { DS ds; int num; std::cin>>num; // Measure the time it takes to insert 1<<num values auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { ds.insert(rand()%2147483648 ); } auto end = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Insertion Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; //print the data structure //ds.print(); // Search for the number auto start2 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { std::pair<int, int> result = ds.find(rand()%2147483647); } auto end2 = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Finding Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count() << " ms" << std::endl; // Search for the number 32765 //std::pair<int, int> result = ds.find(32765); //if (result.first != -1 && result.second != -1) { // std::cout << "Number found at vector index " << result.first << " and position " << result.second << std::endl; //} else { // std::cout << "Number not found" << std::endl; //} return 0; } ``` ------ ### Hash Table ```cpp= // C++ program to demonstrate search, insert and display in Hash Table #include <random> #include <chrono> #include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; #define CAPACITY 50000 // Size of the Hash Table unsigned long hash_function(char* str) { unsigned long i = 0; for (int j=0; str[j]; j++) i += str[j]; return i % CAPACITY; } typedef struct Ht_item Ht_item; // Define the Hash Table Item here struct Ht_item { char* key; char* value; }; typedef struct HashTable HashTable; // Define the Hash Table here struct HashTable { // Contains an array of pointers // to items Ht_item** items; int size; int count; }; Ht_item* create_item(char* key, char* value) { // Creates a pointer to a new hash table item Ht_item* item = (Ht_item*) malloc (sizeof(Ht_item)); item->key = (char*) malloc (strlen(key) + 1); item->value = (char*) malloc (strlen(value) + 1); strcpy(item->key, key); strcpy(item->value, value); return item; } HashTable* create_table(int size) { // Creates a new HashTable HashTable* table = (HashTable*) malloc (sizeof(HashTable)); table->size = size; table->count = 0; table->items = (Ht_item**) calloc (table->size, sizeof(Ht_item*)); for (int i=0; i<table->size; i++) table->items[i] = NULL; return table; } void free_item(Ht_item* item) { // Frees an item free(item->key); free(item->value); free(item); } void free_table(HashTable* table) { // Frees the table for (int i=0; i<table->size; i++) { Ht_item* item = table->items[i]; if (item != NULL) free_item(item); } free(table->items); free(table); } void handle_collision(HashTable* table, unsigned long index, Ht_item* item) { } void ht_insert(HashTable* table, char* key, char* value) { // Create the item Ht_item* item = create_item(key, value); // Compute the index unsigned long index = hash_function(key); Ht_item* current_item = table->items[index]; if (current_item == NULL) { // Key does not exist. if (table->count == table->size) { // Hash Table Full printf("Insert Error: Hash Table is full\n"); // Remove the create item free_item(item); return; } // Insert directly table->items[index] = item; table->count++; } else { // Scenario 1: We only need to update value if (strcmp(current_item->key, key) == 0) { strcpy(table->items[index]->value, value); return; } else { // Scenario 2: Collision // We will handle case this a bit later handle_collision(table, index, item); return; } } } char* ht_search(HashTable* table, char* key) { // Searches the key in the hashtable // and returns NULL if it doesn't exist int index = hash_function(key); Ht_item* item = table->items[index]; // Ensure that we move to a non NULL item if (item != NULL) { if (strcmp(item->key, key) == 0) return item->value; } return NULL; } void print_search(HashTable* table, char* key) { char* val; if ((val = ht_search(table, key)) == NULL) { printf("Key:%s does not exist\n", key); return; } else { printf("Key:%s, Value:%s\n", key, val); } } void print_table(HashTable* table) { printf("\nHash Table\n-------------------\n"); for (int i=0; i<table->size; i++) { if (table->items[i]) { printf("Index:%d, Key:%s, Value:%s\n", i, table->items[i]->key, table->items[i]->value); } } printf("-------------------\n\n"); } int main() { //create a hash table HashTable* ht = create_table(CAPACITY); //print_search(ht, "2"); int num; std::cin>>num; // Measure the time it takes to insert 1<<num values auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { ht_insert(ht, char(i), char(rand()%2147483647)); } auto end = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Insertion Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl; // Search for the number auto start2 = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num; ++i) { ht_search(ht, char(rand()%2147483647) } auto end2 = std::chrono::high_resolution_clock::now(); // Print the elapsed time in milliseconds std::cout << "Finding Elapsed time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2).count() << " ms" << std::endl; //display search and the table //print_search(ht, "3"); //print_table(ht); //free the hash table free_table(ht); return 0; } ```