---
# System prepended metadata

title: 'Different Data Structure Insertion and Search Time Test:'

---

# 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;
}

```