chore: import upstream snapshot with attribution
Awesome CI Workflow / Code Formatter (push) Has been cancelled
Awesome CI Workflow / Compile checks (macOS-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Has been cancelled
Awesome CI Workflow / Compile checks (windows-latest) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:37:28 +08:00
commit 29cfe479ab
432 changed files with 68491 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
# with full pathname. RELATIVE may makes it easier to extract an executable name
# automatically.
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
foreach( testsourcefile ${APP_SOURCES} )
# I used a simple string replace, to cut off .cpp.
string( REPLACE ".cpp" "" testname ${testsourcefile} )
add_executable( ${testname} ${testsourcefile} )
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
if(OpenMP_CXX_FOUND)
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
endif()
install(TARGETS ${testname} DESTINATION "bin/data_structures")
endforeach( testsourcefile ${APP_SOURCES} )
add_subdirectory(cll)
+198
View File
@@ -0,0 +1,198 @@
/**
* \file
* \brief A simple tree implementation using nodes
*
* \todo update code to use C++ STL library features and OO structure
* \warning This program is a poor implementation and does not utilize any of
* the C++ STL features.
*/
#include <algorithm> /// for std::max
#include <iostream> /// for std::cout
#include <queue> /// for std::queue
using node = struct node {
int data;
int height;
struct node *left;
struct node *right;
};
/**
* @brief creates and returns a new node
* @param[in] data value stored in the node
* @return newly created node
*/
node *createNode(int data) {
node *nn = new node();
nn->data = data;
nn->height = 0;
nn->left = nullptr;
nn->right = nullptr;
return nn;
}
/**
* @param[in] root the root of the tree
* @return height of tree
*/
int height(node *root) {
if (root == nullptr) {
return 0;
}
return 1 + std::max(height(root->left), height(root->right));
}
/**
* @param[in] root of the tree
* @return difference between height of left and right subtree
*/
int getBalance(node *root) { return height(root->left) - height(root->right); }
/**
* @param root of the tree to be rotated
* @return node after right rotation
*/
node *rightRotate(node *root) {
node *t = root->left;
node *u = t->right;
t->right = root;
root->left = u;
return t;
}
/**
* @param root of the tree to be rotated
* @return node after left rotation
*/
node *leftRotate(node *root) {
node *t = root->right;
node *u = t->left;
t->left = root;
root->right = u;
return t;
}
/**
* @param root of the tree
* @returns node with minimum value in the tree
*/
node *minValue(node *root) {
if (root->left == nullptr) {
return root;
}
return minValue(root->left);
}
/**
* @brief inserts a new element into AVL tree
* @param root of the tree
* @param[in] item the element to be insterted into the tree
* @return root of the updated tree
*/
node *insert(node *root, int item) {
if (root == nullptr) {
return createNode(item);
}
if (item < root->data) {
root->left = insert(root->left, item);
} else {
root->right = insert(root->right, item);
}
int b = getBalance(root);
if (b > 1) {
if (getBalance(root->left) < 0) {
root->left = leftRotate(root->left); // Left-Right Case
}
return rightRotate(root); // Left-Left Case
} else if (b < -1) {
if (getBalance(root->right) > 0) {
root->right = rightRotate(root->right); // Right-Left Case
}
return leftRotate(root); // Right-Right Case
}
return root;
}
/**
* @brief removes a given element from AVL tree
* @param root of the tree
* @param[in] element the element to be deleted from the tree
* @return root of the updated tree
*/
node *deleteNode(node *root, int element) {
if (root == nullptr) {
return root;
}
if (element < root->data) {
root->left = deleteNode(root->left, element);
} else if (element > root->data) {
root->right = deleteNode(root->right, element);
} else {
// Node to be deleted is leaf node or have only one Child
if (!root->right || !root->left) {
node *temp = !root->right ? root->left : root->right;
delete root;
return temp;
}
// Node to be deleted have both left and right subtrees
node *temp = minValue(root->right);
root->data = temp->data;
root->right = deleteNode(root->right, temp->data);
}
// Balancing Tree after deletion
return root;
}
/**
* @brief calls delete on every node
* @param root of the tree
*/
void deleteAllNodes(const node *const root) {
if (root) {
deleteAllNodes(root->left);
deleteAllNodes(root->right);
delete root;
}
}
/**
* @brief prints given tree in the LevelOrder
* @param[in] root of the tree
*/
void levelOrder(node *root) {
std::queue<node *> q;
q.push(root);
while (!q.empty()) {
root = q.front();
std::cout << root->data << " ";
q.pop();
if (root->left) {
q.push(root->left);
}
if (root->right) {
q.push(root->right);
}
}
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
// Testing AVL Tree
node *root = nullptr;
int i = 0;
for (i = 1; i <= 7; i++) root = insert(root, i);
std::cout << "LevelOrder: ";
levelOrder(root);
root = deleteNode(root, 1); // Deleting key with value 1
std::cout << "\nLevelOrder: ";
levelOrder(root);
root = deleteNode(root, 4); // Deletin key with value 4
std::cout << "\nLevelOrder: ";
levelOrder(root);
deleteAllNodes(root);
return 0;
}
+174
View File
@@ -0,0 +1,174 @@
/**
* \file
* \brief A simple tree implementation using structured nodes
*
* \todo update code to use C++ STL library features and OO structure
* \warning This program is a poor implementation - C style - and does not
* utilize any of the C++ STL features.
*/
#include <iostream>
struct node {
int val;
node *left;
node *right;
};
struct Queue {
node *t[100];
int front;
int rear;
};
Queue queue;
void enqueue(node *n) { queue.t[queue.rear++] = n; }
node *dequeue() { return (queue.t[queue.front++]); }
void Insert(node *n, int x) {
if (x < n->val) {
if (n->left == NULL) {
node *temp = new node;
temp->val = x;
temp->left = NULL;
temp->right = NULL;
n->left = temp;
} else {
Insert(n->left, x);
}
} else {
if (n->right == NULL) {
node *temp = new node;
temp->val = x;
temp->left = NULL;
temp->right = NULL;
n->right = temp;
} else {
Insert(n->right, x);
}
}
}
int findMaxInLeftST(node *n) {
while (n->right != NULL) {
n = n->right;
}
return n->val;
}
void Remove(node *p, node *n, int x) {
if (n->val == x) {
if (n->right == NULL && n->left == NULL) {
if (x < p->val) {
p->right = NULL;
} else {
p->left = NULL;
}
} else if (n->right == NULL) {
if (x < p->val) {
p->right = n->left;
} else {
p->left = n->left;
}
} else if (n->left == NULL) {
if (x < p->val) {
p->right = n->right;
} else {
p->left = n->right;
}
} else {
int y = findMaxInLeftST(n->left);
n->val = y;
Remove(n, n->right, y);
}
} else if (x < n->val) {
Remove(n, n->left, x);
} else {
Remove(n, n->right, x);
}
}
void BFT(node *n) {
if (n != NULL) {
std::cout << n->val << " ";
enqueue(n->left);
enqueue(n->right);
BFT(dequeue());
}
}
void Pre(node *n) {
if (n != NULL) {
std::cout << n->val << " ";
Pre(n->left);
Pre(n->right);
}
}
void In(node *n) {
if (n != NULL) {
In(n->left);
std::cout << n->val << " ";
In(n->right);
}
}
void Post(node *n) {
if (n != NULL) {
Post(n->left);
Post(n->right);
std::cout << n->val << " ";
}
}
int main() {
queue.front = 0;
queue.rear = 0;
int value;
int ch;
node *root = new node;
std::cout << "\nEnter the value of root node :";
std::cin >> value;
root->val = value;
root->left = NULL;
root->right = NULL;
do {
std::cout << "\n1. Insert"
<< "\n2. Delete"
<< "\n3. Breadth First"
<< "\n4. Preorder Depth First"
<< "\n5. Inorder Depth First"
<< "\n6. Postorder Depth First";
std::cout << "\nEnter Your Choice : ";
std::cin >> ch;
int x;
switch (ch) {
case 1:
std::cout << "\nEnter the value to be Inserted : ";
std::cin >> x;
Insert(root, x);
break;
case 2:
std::cout << "\nEnter the value to be Deleted : ";
std::cin >> x;
Remove(root, root, x);
break;
case 3:
BFT(root);
break;
case 4:
Pre(root);
break;
case 5:
In(root);
break;
case 6:
Post(root);
break;
}
} while (ch != 0);
return 0;
}
+565
View File
@@ -0,0 +1,565 @@
/**
* @file
* @brief A generic [binary search tree](https://en.wikipedia.org/wiki/Binary_search_tree) implementation.
* Here you can find more information about the algorithm: [Scaler - Binary Search tree](https://www.scaler.com/topics/data-structures/binary-search-tree/).
* @see binary_search_tree.cpp
*/
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <vector>
/**
* @brief The Binary Search Tree class.
*
* @tparam T The type of the binary search tree key.
*/
template <class T>
class binary_search_tree {
private:
/**
* @brief A struct to represent a node in the Binary Search Tree.
*/
struct bst_node {
T value; /**< The value/key of the node. */
std::unique_ptr<bst_node> left; /**< Pointer to left subtree. */
std::unique_ptr<bst_node> right; /**< Pointer to right subtree. */
/**
* Constructor for bst_node, used to simplify node construction and
* smart pointer construction.
* @param _value The value of the constructed node.
*/
explicit bst_node(T _value) {
value = _value;
left = nullptr;
right = nullptr;
}
};
std::unique_ptr<bst_node> root_; /**< Pointer to the root of the BST. */
std::size_t size_ = 0; /**< Number of elements/nodes in the BST. */
/**
* @brief Recursive function to find the maximum value in the BST.
*
* @param node The node to search from.
* @param ret_value Variable to hold the maximum value.
* @return true If the maximum value was successfully found.
* @return false Otherwise.
*/
bool find_max(std::unique_ptr<bst_node>& node, T& ret_value) {
if (!node) {
return false;
} else if (!node->right) {
ret_value = node->value;
return true;
}
return find_max(node->right, ret_value);
}
/**
* @brief Recursive function to find the minimum value in the BST.
*
* @param node The node to search from.
* @param ret_value Variable to hold the minimum value.
* @return true If the minimum value was successfully found.
* @return false Otherwise.
*/
bool find_min(std::unique_ptr<bst_node>& node, T& ret_value) {
if (!node) {
return false;
} else if (!node->left) {
ret_value = node->value;
return true;
}
return find_min(node->left, ret_value);
}
/**
* @brief Recursive function to insert a value into the BST.
*
* @param node The node to search from.
* @param new_value The value to insert.
* @return true If the insert operation was successful.
* @return false Otherwise.
*/
bool insert(std::unique_ptr<bst_node>& node, T new_value) {
if (root_ == node && !root_) {
root_ = std::unique_ptr<bst_node>(new bst_node(new_value));
return true;
}
if (new_value < node->value) {
if (!node->left) {
node->left = std::unique_ptr<bst_node>(new bst_node(new_value));
return true;
} else {
return insert(node->left, new_value);
}
} else if (new_value > node->value) {
if (!node->right) {
node->right =
std::unique_ptr<bst_node>(new bst_node(new_value));
return true;
} else {
return insert(node->right, new_value);
}
} else {
return false;
}
}
/**
* @brief Recursive function to remove a value from the BST.
*
* @param parent The parent node of node.
* @param node The node to search from.
* @param rm_value The value to remove.
* @return true If the removal operation was successful.
* @return false Otherwise.
*/
bool remove(std::unique_ptr<bst_node>& parent,
std::unique_ptr<bst_node>& node, T rm_value) {
if (!node) {
return false;
}
if (node->value == rm_value) {
if (node->left && node->right) {
T successor_node_value{};
find_max(node->left, successor_node_value);
remove(root_, root_, successor_node_value);
node->value = successor_node_value;
return true;
} else if (node->left || node->right) {
std::unique_ptr<bst_node>& non_null =
(node->left ? node->left : node->right);
if (node == root_) {
root_ = std::move(non_null);
} else if (rm_value < parent->value) {
parent->left = std::move(non_null);
} else {
parent->right = std::move(non_null);
}
return true;
} else {
if (node == root_) {
root_.reset(nullptr);
} else if (rm_value < parent->value) {
parent->left.reset(nullptr);
} else {
parent->right.reset(nullptr);
}
return true;
}
} else if (rm_value < node->value) {
return remove(node, node->left, rm_value);
} else {
return remove(node, node->right, rm_value);
}
}
/**
* @brief Recursive function to check if a value is in the BST.
*
* @param node The node to search from.
* @param value The value to find.
* @return true If the value was found in the BST.
* @return false Otherwise.
*/
bool contains(std::unique_ptr<bst_node>& node, T value) {
if (!node) {
return false;
}
if (value < node->value) {
return contains(node->left, value);
} else if (value > node->value) {
return contains(node->right, value);
} else {
return true;
}
}
/**
* @brief Recursive function to traverse the tree in in-order order.
*
* @param callback Function that is called when a value needs to processed.
* @param node The node to traverse from.
*/
void traverse_inorder(std::function<void(T)> callback,
std::unique_ptr<bst_node>& node) {
if (!node) {
return;
}
traverse_inorder(callback, node->left);
callback(node->value);
traverse_inorder(callback, node->right);
}
/**
* @brief Recursive function to traverse the tree in pre-order order.
*
* @param callback Function that is called when a value needs to processed.
* @param node The node to traverse from.
*/
void traverse_preorder(std::function<void(T)> callback,
std::unique_ptr<bst_node>& node) {
if (!node) {
return;
}
callback(node->value);
traverse_preorder(callback, node->left);
traverse_preorder(callback, node->right);
}
/**
* @brief Recursive function to traverse the tree in post-order order.
*
* @param callback Function that is called when a value needs to processed.
* @param node The node to traverse from.
*/
void traverse_postorder(std::function<void(T)> callback,
std::unique_ptr<bst_node>& node) {
if (!node) {
return;
}
traverse_postorder(callback, node->left);
traverse_postorder(callback, node->right);
callback(node->value);
}
public:
/**
* @brief Construct a new Binary Search Tree object.
*
*/
binary_search_tree() {
root_ = nullptr;
size_ = 0;
}
/**
* @brief Insert a new value into the BST.
*
* @param new_value The value to insert into the BST.
* @return true If the insertion was successful.
* @return false Otherwise.
*/
bool insert(T new_value) {
bool result = insert(root_, new_value);
if (result) {
size_++;
}
return result;
}
/**
* @brief Remove a specified value from the BST.
*
* @param rm_value The value to remove.
* @return true If the removal was successful.
* @return false Otherwise.
*/
bool remove(T rm_value) {
bool result = remove(root_, root_, rm_value);
if (result) {
size_--;
}
return result;
}
/**
* @brief Check if a value is in the BST.
*
* @param value The value to find.
* @return true If value is in the BST.
* @return false Otherwise.
*/
bool contains(T value) { return contains(root_, value); }
/**
* @brief Find the smallest value in the BST.
*
* @param ret_value Variable to hold the minimum value.
* @return true If minimum value was successfully found.
* @return false Otherwise.
*/
bool find_min(T& ret_value) { return find_min(root_, ret_value); }
/**
* @brief Find the largest value in the BST.
*
* @param ret_value Variable to hold the maximum value.
* @return true If maximum value was successfully found.
* @return false Otherwise.
*/
bool find_max(T& ret_value) { return find_max(root_, ret_value); }
/**
* @brief Get the number of values in the BST.
*
* @return std::size_t Number of values in the BST.
*/
std::size_t size() { return size_; }
/**
* @brief Get all values of the BST in in-order order.
*
* @return std::vector<T> List of values, sorted in in-order order.
*/
std::vector<T> get_elements_inorder() {
std::vector<T> result;
traverse_inorder([&](T node_value) { result.push_back(node_value); },
root_);
return result;
}
/**
* @brief Get all values of the BST in pre-order order.
*
* @return std::vector<T> List of values, sorted in pre-order order.
*/
std::vector<T> get_elements_preorder() {
std::vector<T> result;
traverse_preorder([&](T node_value) { result.push_back(node_value); },
root_);
return result;
}
/**
* @brief Get all values of the BST in post-order order.
*
* @return std::vector<T> List of values, sorted in post-order order.
*/
std::vector<T> get_elements_postorder() {
std::vector<T> result;
traverse_postorder([&](T node_value) { result.push_back(node_value); },
root_);
return result;
}
};
/**
* @brief Function for testing insert().
*
* @returns `void`
*/
static void test_insert() {
std::cout << "Testing BST insert...";
binary_search_tree<int> tree;
bool res = tree.insert(5);
int min = -1, max = -1;
assert(res);
assert(tree.find_max(max));
assert(tree.find_min(min));
assert(max == 5);
assert(min == 5);
assert(tree.size() == 1);
tree.insert(4);
tree.insert(3);
tree.insert(6);
assert(tree.find_max(max));
assert(tree.find_min(min));
assert(max == 6);
assert(min == 3);
assert(tree.size() == 4);
bool fail_res = tree.insert(4);
assert(!fail_res);
assert(tree.size() == 4);
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing remove().
*
* @returns `void`
*/
static void test_remove() {
std::cout << "Testing BST remove...";
binary_search_tree<int> tree;
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
bool res = tree.remove(5);
int min = -1, max = -1;
assert(res);
assert(tree.find_max(max));
assert(tree.find_min(min));
assert(max == 6);
assert(min == 3);
assert(tree.size() == 3);
assert(tree.contains(5) == false);
tree.remove(4);
tree.remove(3);
tree.remove(6);
assert(tree.size() == 0);
assert(tree.contains(6) == false);
bool fail_res = tree.remove(5);
assert(!fail_res);
assert(tree.size() == 0);
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing contains().
*
* @returns `void`
*/
static void test_contains() {
std::cout << "Testing BST contains...";
binary_search_tree<int> tree;
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
assert(tree.contains(5));
assert(tree.contains(4));
assert(tree.contains(3));
assert(tree.contains(6));
assert(!tree.contains(999));
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing find_min().
*
* @returns `void`
*/
static void test_find_min() {
std::cout << "Testing BST find_min...";
int min = 0;
binary_search_tree<int> tree;
assert(!tree.find_min(min));
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
assert(tree.find_min(min));
assert(min == 3);
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing find_max().
*
* @returns `void`
*/
static void test_find_max() {
std::cout << "Testing BST find_max...";
int max = 0;
binary_search_tree<int> tree;
assert(!tree.find_max(max));
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
assert(tree.find_max(max));
assert(max == 6);
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing get_elements_inorder().
*
* @returns `void`
*/
static void test_get_elements_inorder() {
std::cout << "Testing BST get_elements_inorder...";
binary_search_tree<int> tree;
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
std::vector<int> expected = {3, 4, 5, 6};
std::vector<int> actual = tree.get_elements_inorder();
assert(actual == expected);
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing get_elements_preorder().
*
* @returns `void`
*/
static void test_get_elements_preorder() {
std::cout << "Testing BST get_elements_preorder...";
binary_search_tree<int> tree;
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
std::vector<int> expected = {5, 4, 3, 6};
std::vector<int> actual = tree.get_elements_preorder();
assert(actual == expected);
std::cout << "ok" << std::endl;
}
/**
* @brief Function for testing get_elements_postorder().
*
* @returns `void`
*/
static void test_get_elements_postorder() {
std::cout << "Testing BST get_elements_postorder...";
binary_search_tree<int> tree;
tree.insert(5);
tree.insert(4);
tree.insert(3);
tree.insert(6);
std::vector<int> expected = {3, 4, 6, 5};
std::vector<int> actual = tree.get_elements_postorder();
assert(actual == expected);
std::cout << "ok" << std::endl;
}
int main() {
test_insert();
test_remove();
test_contains();
test_find_max();
test_find_min();
test_get_elements_inorder();
test_get_elements_preorder();
test_get_elements_postorder();
}
+142
View File
@@ -0,0 +1,142 @@
/**
* \file
* \brief A C++ program to demonstrate common Binary Heap Operations
*/
#include <climits>
#include <iostream>
#include <utility>
/** A class for Min Heap */
class MinHeap {
int *harr; ///< pointer to array of elements in heap
int capacity; ///< maximum possible size of min heap
int heap_size; ///< Current number of elements in min heap
public:
/** Constructor: Builds a heap from a given array a[] of given size
* \param[in] capacity initial heap capacity
*/
explicit MinHeap(int cap) {
heap_size = 0;
capacity = cap;
harr = new int[cap];
}
/** to heapify a subtree with the root at given index */
void MinHeapify(int);
int parent(int i) { return (i - 1) / 2; }
/** to get index of left child of node at index i */
int left(int i) { return (2 * i + 1); }
/** to get index of right child of node at index i */
int right(int i) { return (2 * i + 2); }
/** to extract the root which is the minimum element */
int extractMin();
/** Decreases key value of key at index i to new_val */
void decreaseKey(int i, int new_val);
/** Returns the minimum key (key at root) from min heap */
int getMin() { return harr[0]; }
/** Deletes a key stored at index i */
void deleteKey(int i);
/** Inserts a new key 'k' */
void insertKey(int k);
~MinHeap() { delete[] harr; }
};
// Inserts a new key 'k'
void MinHeap::insertKey(int k) {
if (heap_size == capacity) {
std::cout << "\nOverflow: Could not insertKey\n";
return;
}
// First insert the new key at the end
heap_size++;
int i = heap_size - 1;
harr[i] = k;
// Fix the min heap property if it is violated
while (i != 0 && harr[parent(i)] > harr[i]) {
std::swap(harr[i], harr[parent(i)]);
i = parent(i);
}
}
/** Decreases value of key at index 'i' to new_val. It is assumed that new_val
* is smaller than harr[i].
*/
void MinHeap::decreaseKey(int i, int new_val) {
harr[i] = new_val;
while (i != 0 && harr[parent(i)] > harr[i]) {
std::swap(harr[i], harr[parent(i)]);
i = parent(i);
}
}
// Method to remove minimum element (or root) from min heap
int MinHeap::extractMin() {
if (heap_size <= 0)
return INT_MAX;
if (heap_size == 1) {
heap_size--;
return harr[0];
}
// Store the minimum value, and remove it from heap
int root = harr[0];
harr[0] = harr[heap_size - 1];
heap_size--;
MinHeapify(0);
return root;
}
/** This function deletes key at index i. It first reduced value to minus
* infinite, then calls extractMin()
*/
void MinHeap::deleteKey(int i) {
decreaseKey(i, INT_MIN);
extractMin();
}
/** A recursive method to heapify a subtree with the root at given index
* This method assumes that the subtrees are already heapified
*/
void MinHeap::MinHeapify(int i) {
int l = left(i);
int r = right(i);
int smallest = i;
if (l < heap_size && harr[l] < harr[i])
smallest = l;
if (r < heap_size && harr[r] < harr[smallest])
smallest = r;
if (smallest != i) {
std::swap(harr[i], harr[smallest]);
MinHeapify(smallest);
}
}
// Driver program to test above functions
int main() {
MinHeap h(11);
h.insertKey(3);
h.insertKey(2);
h.deleteKey(1);
h.insertKey(15);
h.insertKey(5);
h.insertKey(4);
h.insertKey(45);
std::cout << h.extractMin() << " ";
std::cout << h.getMin() << " ";
h.decreaseKey(2, 1);
std::cout << h.getMin();
return 0;
}
+291
View File
@@ -0,0 +1,291 @@
/**
* @file
* @brief [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter)
* generic implementation in C++
* @details A Bloom filter is a space-efficient probabilistic data structure,
* a query returns either "possibly in set" or "definitely not in set".
*
* More generally, fewer than 10 bits per element are required for a 1% false
* positive probability, independent of the size or number of elements in the
* set.
*
* It helps us to not make an "expensive operations", like disk IO - we can
* use bloom filter to check incoming request, and with a good probability
* get an answer of bloom filter, that we don't need to make our "expensive
* operation"
*
*
* [Very good use case example](https://stackoverflow.com/a/30247022)
*
* Basic bloom filter doesn't support deleting of elements, so
* we don't need to implement deletion in bloom filter and bitset in our case.
* @author [DanArmor](https://github.com/DanArmor)
*/
#include <cassert> /// for assert
#include <functional> /// for list of hash functions for bloom filter constructor
#include <initializer_list> /// for initializer_list for bloom filter constructor
#include <string> /// for testing on strings
#include <vector> /// for std::vector
#include <iostream> /// for IO operations
/**
* @namespace data_structures
* @brief Data Structures algorithms
*/
namespace data_structures {
/**
* @brief Simple bitset implementation for bloom filter
*/
class Bitset {
private:
std::vector<std::size_t> data; ///< short info of this variable
static const std::size_t blockSize =
sizeof(std::size_t); ///< size of integer type, that we are using in
///< our bitset
public:
explicit Bitset(std::size_t);
std::size_t size();
void add(std::size_t);
bool contains(std::size_t);
};
/**
* @brief Utility function to return the size of the inner array
* @returns the size of inner array
*/
std::size_t Bitset::size() { return data.size(); }
/**
* @brief BitSet class constructor
* @param initSize amount of blocks, each contain sizeof(std::size_t) bits
*/
Bitset::Bitset(std::size_t initSize) : data(initSize) {}
/**
* @brief Turn bit on position x to 1s
*
* @param x position to turn bit on
* @returns void
*/
void Bitset::add(std::size_t x) {
std::size_t blockIndex = x / blockSize;
if (blockIndex >= data.size()) {
data.resize(blockIndex + 1);
}
data[blockIndex] |= 1 << (x % blockSize);
}
/**
* @brief Doest bitset contains element x
*
* @param x position in bitset to check
* @returns true if bit position x is 1
* @returns false if bit position x is 0
*/
bool Bitset::contains(std::size_t x) {
std::size_t blockIndex = x / blockSize;
if (blockIndex >= data.size()) {
return false;
}
return data[blockIndex] & (1 << (x % blockSize));
}
/**
* @brief Bloom filter template class
* @tparam T type of elements that we need to filter
*/
template <typename T>
class BloomFilter {
private:
Bitset set; ///< inner bitset for elements
std::vector<std::function<std::size_t(T)>>
hashFunks; ///< hash functions for T type
public:
BloomFilter(std::size_t,
std::initializer_list<std::function<std::size_t(T)>>);
void add(T);
bool contains(T);
};
/**
* @brief Constructor for Bloom filter
*
* @tparam T type of elements that we need to filter
* @param size initial size of Bloom filter
* @param funks hash functions for T type
* @returns none
*/
template <typename T>
BloomFilter<T>::BloomFilter(
std::size_t size,
std::initializer_list<std::function<std::size_t(T)>> funks)
: set(size), hashFunks(funks) {}
/**
* @brief Add function for Bloom filter
*
* @tparam T type of elements that we need to filter
* @param x element to add to filter
* @returns void
*/
template <typename T>
void BloomFilter<T>::add(T x) {
for (std::size_t i = 0; i < hashFunks.size(); i++) {
set.add(hashFunks[i](x) % (sizeof(std::size_t) * set.size()));
}
}
/**
* @brief Check element function for Bloom filter
*
* @tparam T type of elements that we need to filter
* @param x element to check in filter
* @return true if the element probably appears in the filter
* @return false if the element certainly does not appear in the filter
*/
template <typename T>
bool BloomFilter<T>::contains(T x) {
for (std::size_t i = 0; i < hashFunks.size(); i++) {
if (set.contains(hashFunks[i](x) %
(sizeof(std::size_t) * set.size())) == false) {
return false;
}
}
return true;
}
/**
* @brief [Function djb2](http://www.cse.yorku.ca/~oz/hash.html)
* to get hash for the given string.
*
* @param s string to get hash from
* @returns hash for a string
*/
static std::size_t hashDJB2(std::string const& s) {
std::size_t hash = 5381;
for (char c : s) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}
/**
* @brief [Hash
* function](https://stackoverflow.com/questions/8317508/hash-function-for-a-string),
* to get hash for the given string.
*
* @param s string to get hash from
* @returns hash for the given string
*/
static std::size_t hashStr(std::string const& s) {
std::size_t hash = 37;
std::size_t primeNum1 = 54059;
std::size_t primeNum2 = 76963;
for (char c : s) {
hash = (hash * primeNum1) ^ (c * primeNum2);
}
return hash;
}
/**
* @brief [Hash function for
* test](https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key)
*
* @param x to get hash from
* @returns hash for the `x` parameter
*/
std::size_t hashInt_1(int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
/**
* @brief [Hash function for
* test](https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key)
*
* @param x to get hash from
* @returns hash for the `x` parameter
*/
std::size_t hashInt_2(int x) {
auto y = static_cast<std::size_t>(x);
y = (y ^ (y >> 30)) * static_cast<std::size_t>(0xbf58476d1ce4e5b9);
y = (y ^ (y >> 27)) * static_cast<std::size_t>(0x94d049bb133111eb);
y = y ^ (y >> 31);
return y;
}
} // namespace data_structures
/**
* @brief Test for bloom filter with string as generic type
* @returns void
*/
static void test_bloom_filter_string() {
data_structures::BloomFilter<std::string> filter(
10, {data_structures::hashDJB2, data_structures::hashStr});
std::vector<std::string> toCheck{"hello", "world", "!"};
std::vector<std::string> toFalse{"false", "world2", "!!!"};
for (const auto& x : toCheck) {
filter.add(x);
}
for (const auto& x : toFalse) {
assert(filter.contains(x) == false);
}
for (const auto& x : toCheck) {
assert(filter.contains(x));
}
}
/**
* @brief Test for bloom filter with int as generic type
* @returns void
*/
static void test_bloom_filter_int() {
data_structures::BloomFilter<int> filter(
20, {data_structures::hashInt_1, data_structures::hashInt_2});
std::vector<int> toCheck{100, 200, 300, 50};
std::vector<int> toFalse{1, 2, 3, 4, 5, 6, 7, 8};
for (int x : toCheck) {
filter.add(x);
}
for (int x : toFalse) {
assert(filter.contains(x) == false);
}
for (int x : toCheck) {
assert(filter.contains(x));
}
}
/**
* @brief Test for bitset
*
* @returns void
*/
static void test_bitset() {
data_structures::Bitset set(2);
std::vector<std::size_t> toCheck{0, 1, 5, 8, 63, 64, 67, 127};
for (auto x : toCheck) {
set.add(x);
assert(set.contains(x));
}
assert(set.contains(128) == false);
assert(set.contains(256) == false);
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
// run self-test implementations
test_bitset(); // run test for bitset, because bloom filter is depending on it
test_bloom_filter_string();
test_bloom_filter_int();
std::cout << "All tests have successfully passed!\n";
return 0;
}
@@ -0,0 +1,82 @@
#include <iostream>
struct node {
int data;
struct node* next;
};
class Queue {
node* front = nullptr;
node* rear = nullptr;
Queue(const Queue&) = delete;
Queue& operator=(const Queue&) = delete;
public:
Queue() = default;
~Queue() {
while (front) {
dequeue();
}
}
private:
void createNode(int val) {
auto* nn = new node;
nn->data = val;
nn->next = nullptr;
front = nn;
rear = nn;
}
public:
void enqueue(int val) {
if (front == nullptr || rear == nullptr) {
createNode(val);
} else {
node* nn = new node;
nn->data = val;
rear->next = nn;
nn->next = front;
rear = nn;
}
}
void dequeue() {
if (front == nullptr) {
return;
}
const node* const n = front;
if (front == rear) {
front = nullptr;
rear = nullptr;
} else {
front = front->next;
rear->next = front;
}
delete n;
}
void traverse() {
if (front == nullptr) {
return;
}
const node* ptr = front;
do {
std::cout << ptr->data << ' ';
ptr = ptr->next;
} while (ptr != front);
std::cout << '\n';
}
};
int main(void) {
Queue q;
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
q.enqueue(40);
q.enqueue(50);
q.enqueue(60);
q.enqueue(70);
q.traverse();
q.dequeue();
q.traverse();
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
add_executable( cll
cll.cpp
main_cll.cpp
)
install(TARGETS cll DESTINATION "bin/data_structures")
+110
View File
@@ -0,0 +1,110 @@
/*
A simple class for Cicular Linear Linked List
*/
#include "cll.h"
using namespace std;
/* Constructor */
cll::cll() {
head = NULL;
total = 0;
}
cll::~cll() { /* Desstructure, no need to fill */
}
/* Display a list. and total element */
void cll::display() {
if (head == NULL)
cout << "List is empty !" << endl;
else {
cout << "CLL list: ";
node *current = head;
for (int i = 0; i < total; i++) {
cout << current->data << " -> ";
current = current->next;
}
cout << head->data << endl;
cout << "Total element: " << total << endl;
}
}
/* List insert a new value at head in list */
void cll::insert_front(int new_data) {
node *newNode;
newNode = new node;
newNode->data = new_data;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
head->next = head;
} else {
node *current = head;
while (current->next != head) {
current = current->next;
}
newNode->next = head;
current->next = newNode;
head = newNode;
}
total++;
}
/* List insert a new value at head in list */
void cll::insert_tail(int new_data) {
node *newNode;
newNode = new node;
newNode->data = new_data;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
head->next = head;
} else {
node *current = head;
while (current->next != head) {
current = current->next;
}
current->next = newNode;
newNode->next = head;
}
total++;
}
/* Get total element in list */
int cll::get_size() { return total; }
/* Return true if the requested item (sent in as an argument)
is in the list, otherwise return false */
bool cll::find_item(int item_to_find) {
if (head == NULL) {
cout << "List is empty !" << endl;
return false;
} else {
node *current = head;
while (current->next != head) {
if (current->data == item_to_find)
return true;
current = current->next;
}
return false;
}
}
/* Overloading method*/
int cll::operator*() { return head->data; }
/* Overload the pre-increment operator.
The iterator is advanced to the next node. */
void cll::operator++() {
if (head == NULL) {
cout << "List is empty !" << endl;
} else {
node *current = head;
while (current->next != head) {
current = current->next;
}
current->next = head->next;
head = head->next;
}
total--;
}
+43
View File
@@ -0,0 +1,43 @@
/*
* Simple data structure CLL (Circular Linear Linked List)
* */
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#ifndef CLL_H
#define CLL_H
/*The data structure is a linear linked list of integers */
struct node {
int data;
node* next;
};
class cll {
public:
cll(); /* Construct without parameter */
~cll();
void display(); /* Show the list */
/******************************************************
* Useful method for list
*******************************************************/
void insert_front(int new_data); /* Insert a new value at head */
void insert_tail(int new_data); /* Insert a new value at tail */
int get_size(); /* Get total element in list */
bool find_item(int item_to_find); /* Find an item in list */
/******************************************************
* Overloading method for list
*******************************************************/
int operator*(); /* Returns the info contained in head */
/* Overload the pre-increment operator.
The iterator is advanced to the next node. */
void operator++();
protected:
node* head;
int total; /* Total element in a list */
};
#endif
+43
View File
@@ -0,0 +1,43 @@
#include "cll.h"
using namespace std;
int main() {
/* Test CLL */
cout << "----------- Test construct -----------" << endl;
cll list1;
list1.display();
cout << "----------- Test insert front -----------" << endl;
list1.insert_front(5);
cout << "After insert 5 at front: " << endl;
list1.display();
cout << "After insert 10 3 7 at front: " << endl;
list1.insert_front(10);
list1.insert_front(3);
list1.insert_front(7);
list1.display();
cout << "----------- Test insert tail -----------" << endl;
cout << "After insert 18 19 20 at tail: " << endl;
list1.insert_tail(18);
list1.insert_tail(19);
list1.insert_tail(20);
list1.display();
cout << "----------- Test find item -----------" << endl;
if (list1.find_item(10))
cout << "PASS" << endl;
else
cout << "FAIL" << endl;
if (!list1.find_item(30))
cout << "PASS" << endl;
else
cout << "FAIL" << endl;
cout << "----------- Test * operator -----------" << endl;
int value = *list1;
cout << "Value at *list1: " << value << endl;
cout << "----------- Test ++ operator -----------" << endl;
list1.display();
++list1;
cout << "After ++list1: " << endl;
list1.display();
return 0;
}
+114
View File
@@ -0,0 +1,114 @@
/**
*
* \file
* \brief [Disjoint Sets Data Structure
* (Disjoint Sets)](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
*
* \author [leoyang429](https://github.com/leoyang429)
*
* \details
* A disjoint set data structure (also called union find or merge find set)
* is a data structure that tracks a set of elements partitioned into a number
* of disjoint (non-overlapping) subsets.
* Some situations where disjoint sets can be used are-
* to find connected components of a graph, kruskal's algorithm for finding
* Minimum Spanning Tree etc.
* There are two operation which we perform on disjoint sets -
* 1) Union
* 2) Find
*
*/
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
vector<int> root, rank;
/**
*
* Function to create a set
* @param n number of element
*
*/
void CreateSet(int n) {
root = vector<int>(n + 1);
rank = vector<int>(n + 1, 1);
for (int i = 1; i <= n; ++i) {
root[i] = i;
}
}
/**
*
* Find operation takes a number x and returns the set to which this number
* belongs to.
* @param x element of some set
* @return set to which x belongs to
*
*/
int Find(int x) {
if (root[x] == x) {
return x;
}
return root[x] = Find(root[x]);
}
/**
*
* A utility function to check if x and y are from same set or not
* @param x element of some set
* @param y element of some set
*
*/
bool InSameUnion(int x, int y) { return Find(x) == Find(y); }
/**
*
* Union operation combines two disjoint sets to make a single set
* in this union function we pass two elements and check if they are
* from different sets then combine those sets
* @param x element of some set
* @param y element of some set
*
*/
void Union(int x, int y) {
int a = Find(x), b = Find(y);
if (a != b) {
if (rank[a] < rank[b]) {
root[a] = b;
} else if (rank[a] > rank[b]) {
root[b] = a;
} else {
root[a] = b;
++rank[b];
}
}
}
/** Main function */
int main() {
// tests CreateSet & Find
int n = 100;
CreateSet(n);
for (int i = 1; i <= 100; ++i) {
if (root[i] != i) {
cout << "Fail" << endl;
break;
}
}
// tests InSameUnion & Union
cout << "1 and 2 are initially not in the same subset" << endl;
if (InSameUnion(1, 2)) {
cout << "Fail" << endl;
}
Union(1, 2);
cout << "1 and 2 are now in the same subset" << endl;
if (!InSameUnion(1, 2)) {
cout << "Fail" << endl;
}
return 0;
}
+136
View File
@@ -0,0 +1,136 @@
#include <cstdio>
#include <cstdlib>
#include <iostream>
struct node {
int val;
node *prev;
node *next;
} * start;
class double_linked_list {
public:
double_linked_list() { start = NULL; }
void insert(int x);
void remove(int x);
void search(int x);
void show();
void reverseShow();
};
void double_linked_list::insert(int x) {
node *t = start;
if (start != NULL) {
while (t->next != NULL) {
t = t->next;
}
node *n = new node;
t->next = n;
n->prev = t;
n->val = x;
n->next = NULL;
} else {
node *n = new node;
n->val = x;
n->prev = NULL;
n->next = NULL;
start = n;
}
}
void double_linked_list::remove(int x) {
node *t = start;
while (t != NULL && t->val != x) {
t = t->next;
}
if (t == NULL) {
return;
}
if (t->prev == NULL) {
if (t->next == NULL) {
start = NULL;
} else {
start = t->next;
start->prev = NULL;
}
} else if (t->next == NULL) {
t->prev->next = NULL;
} else {
t->prev->next = t->next;
t->next->prev = t->prev;
}
delete t;
}
void double_linked_list::search(int x) {
node *t = start;
int found = 0;
while (t != NULL) {
if (t->val == x) {
std::cout << "\nFound";
found = 1;
break;
}
t = t->next;
}
if (found == 0) {
std::cout << "\nNot Found";
}
}
void double_linked_list::show() {
node *t = start;
while (t != NULL) {
std::cout << t->val << "\t";
t = t->next;
}
}
void double_linked_list::reverseShow() {
node *t = start;
while (t != NULL && t->next != NULL) {
t = t->next;
}
while (t != NULL) {
std::cout << t->val << "\t";
t = t->prev;
}
}
int main() {
int choice, x;
double_linked_list ob;
do {
std::cout << "\n1. Insert";
std::cout << "\n2. Delete";
std::cout << "\n3. Search";
std::cout << "\n4. Forward print";
std::cout << "\n5. Reverse print";
std::cout << "\n\nEnter you choice : ";
std::cin >> choice;
switch (choice) {
case 1:
std::cout << "\nEnter the element to be inserted : ";
std::cin >> x;
ob.insert(x);
break;
case 2:
std::cout << "\nEnter the element to be removed : ";
std::cin >> x;
ob.remove(x);
break;
case 3:
std::cout << "\nEnter the element to be searched : ";
std::cin >> x;
ob.search(x);
break;
case 4:
ob.show();
break;
case 5:
ob.reverseShow();
break;
}
} while (choice != 0);
return 0;
}
+214
View File
@@ -0,0 +1,214 @@
/**
* @file
* @brief [DSU (Disjoint
* sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure)
* @details
* It is a very powerful data structure that keeps track of different
* clusters(sets) of elements, these sets are disjoint(doesnot have a common
* element). Disjoint sets uses cases : for finding connected components in a
* graph, used in Kruskal's algorithm for finding Minimum Spanning tree.
* Operations that can be performed:
* 1) UnionSet(i,j): add(element i and j to the set)
* 2) findSet(i): returns the representative of the set to which i belogngs to.
* 3) get_max(i),get_min(i) : returns the maximum and minimum
* Below is the class-based approach which uses the heuristic of path
* compression. Using path compression in findSet(i),we are able to get to the
* representative of i in O(1) time.
* @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT)
* @see dsu_union_rank.cpp
*/
#include <cassert> /// for assert
#include <cstdint>
#include <iostream> /// for IO operations
#include <vector> /// for std::vector
using std::cout;
using std::endl;
using std::vector;
/**
* @brief Disjoint sets union data structure, class based representation.
* @param n number of elements
*/
class dsu {
private:
vector<uint64_t> p; ///< keeps track of the parent of ith element
vector<uint64_t> depth; ///< tracks the depth(rank) of i in the tree
vector<uint64_t> setSize; ///< size of each chunk(set)
vector<uint64_t> maxElement; ///< maximum of each set to which i belongs to
vector<uint64_t> minElement; ///< minimum of each set to which i belongs to
public:
/**
* @brief contructor for initialising all data members.
* @param n number of elements
*/
explicit dsu(uint64_t n) {
p.assign(n, 0);
/// initially, all of them are their own parents
for (uint64_t i = 0; i < n; i++) {
p[i] = i;
}
/// initially all have depth are equals to zero
depth.assign(n, 0);
maxElement.assign(n, 0);
minElement.assign(n, 0);
for (uint64_t i = 0; i < n; i++) {
depth[i] = 0;
maxElement[i] = i;
minElement[i] = i;
}
setSize.assign(n, 0);
/// initially set size will be equals to one
for (uint64_t i = 0; i < n; i++) {
setSize[i] = 1;
}
}
/**
* @brief Method to find the representative of the set to which i belongs
* to, T(n) = O(1)
* @param i element of some set
* @returns representative of the set to which i belongs to.
*/
uint64_t findSet(uint64_t i) {
/// using path compression
if (p[i] == i) {
return i;
}
return (p[i] = findSet(p[i]));
}
/**
* @brief Method that combines two disjoint sets to which i and j belongs to
* and make a single set having a common representative.
* @param i element of some set
* @param j element of some set
* @returns void
*/
void UnionSet(uint64_t i, uint64_t j) {
/// check if both belongs to the same set or not
if (isSame(i, j)) {
return;
}
// we find the representative of the i and j
uint64_t x = findSet(i);
uint64_t y = findSet(j);
/// always keeping the min as x
/// shallow tree
if (depth[x] > depth[y]) {
std::swap(x, y);
}
/// making the shallower root's parent the deeper root
p[x] = y;
/// if same depth, then increase one's depth
if (depth[x] == depth[y]) {
depth[y]++;
}
/// total size of the resultant set
setSize[y] += setSize[x];
/// changing the maximum elements
maxElement[y] = std::max(maxElement[x], maxElement[y]);
minElement[y] = std::min(minElement[x], minElement[y]);
}
/**
* @brief A utility function which check whether i and j belongs to
* same set or not
* @param i element of some set
* @param j element of some set
* @returns `true` if element `i` and `j` ARE in the same set
* @returns `false` if element `i` and `j` are NOT in same set
*/
bool isSame(uint64_t i, uint64_t j) {
if (findSet(i) == findSet(j)) {
return true;
}
return false;
}
/**
* @brief prints the minimum, maximum and size of the set to which i belongs
* to
* @param i element of some set
* @returns void
*/
vector<uint64_t> get(uint64_t i) {
vector<uint64_t> ans;
ans.push_back(get_min(i));
ans.push_back(get_max(i));
ans.push_back(size(i));
return ans;
}
/**
* @brief A utility function that returns the size of the set to which i
* belongs to
* @param i element of some set
* @returns size of the set to which i belongs to
*/
uint64_t size(uint64_t i) { return setSize[findSet(i)]; }
/**
* @brief A utility function that returns the max element of the set to
* which i belongs to
* @param i element of some set
* @returns maximum of the set to which i belongs to
*/
uint64_t get_max(uint64_t i) { return maxElement[findSet(i)]; }
/**
* @brief A utility function that returns the min element of the set to
* which i belongs to
* @param i element of some set
* @returns minimum of the set to which i belongs to
*/
uint64_t get_min(uint64_t i) { return minElement[findSet(i)]; }
};
/**
* @brief Self-test implementations, 1st test
* @returns void
*/
static void test1() {
// the minimum, maximum, and size of the set
uint64_t n = 10; ///< number of items
dsu d(n + 1); ///< object of class disjoint sets
// set 1
d.UnionSet(1, 2); // performs union operation on 1 and 2
d.UnionSet(1, 4); // performs union operation on 1 and 4
vector<uint64_t> ans = {1, 4, 3};
for (uint64_t i = 0; i < ans.size(); i++) {
assert(d.get(4).at(i) == ans[i]); // makes sure algorithm works fine
}
cout << "1st test passed!" << endl;
}
/**
* @brief Self-implementations, 2nd test
* @returns void
*/
static void test2() {
// the minimum, maximum, and size of the set
uint64_t n = 10; ///< number of items
dsu d(n + 1); ///< object of class disjoint sets
// set 1
d.UnionSet(3, 5);
d.UnionSet(5, 6);
d.UnionSet(5, 7);
vector<uint64_t> ans = {3, 7, 4};
for (uint64_t i = 0; i < ans.size(); i++) {
assert(d.get(3).at(i) == ans[i]); // makes sure algorithm works fine
}
cout << "2nd test passed!" << endl;
}
/**
* @brief Main function
* @returns 0 on exit
* */
int main() {
uint64_t n = 10; ///< number of items
dsu d(n + 1); ///< object of class disjoint sets
test1(); // run 1st test case
test2(); // run 2nd test case
return 0;
}
+188
View File
@@ -0,0 +1,188 @@
/**
* @file
* @brief [DSU (Disjoint
* sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure)
* @details
* dsu : It is a very powerful data structure which keeps track of different
* clusters(sets) of elements, these sets are disjoint(doesnot have a common
* element). Disjoint sets uses cases : for finding connected components in a
* graph, used in Kruskal's algorithm for finding Minimum Spanning tree.
* Operations that can be performed:
* 1) UnionSet(i,j): add(element i and j to the set)
* 2) findSet(i): returns the representative of the set to which i belogngs to.
* 3) getParents(i): prints the parent of i and so on and so forth.
* Below is the class-based approach which uses the heuristic of union-ranks.
* Using union-rank in findSet(i),we are able to get to the representative of i
* in slightly delayed O(logN) time but it allows us to keep tracks of the
* parent of i.
* @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT)
* @see dsu_path_compression.cpp
*/
#include <cassert> /// for assert
#include <cstdint>
#include <iostream> /// for IO operations
#include <vector> /// for std::vector
using std::cout;
using std::endl;
using std::vector;
/**
* @brief Disjoint sets union data structure, class based representation.
* @param n number of elements
*/
class dsu {
private:
vector<uint64_t> p; ///< keeps track of the parent of ith element
vector<uint64_t> depth; ///< tracks the depth(rank) of i in the tree
vector<uint64_t> setSize; ///< size of each chunk(set)
public:
/**
* @brief constructor for initialising all data members
* @param n number of elements
*/
explicit dsu(uint64_t n) {
p.assign(n, 0);
/// initially all of them are their own parents
depth.assign(n, 0);
setSize.assign(n, 0);
for (uint64_t i = 0; i < n; i++) {
p[i] = i;
depth[i] = 0;
setSize[i] = 1;
}
}
/**
* @brief Method to find the representative of the set to which i belongs
* to, T(n) = O(logN)
* @param i element of some set
* @returns representative of the set to which i belongs to
*/
uint64_t findSet(uint64_t i) {
/// using union-rank
while (i != p[i]) {
i = p[i];
}
return i;
}
/**
* @brief Method that combines two disjoint sets to which i and j belongs to
* and make a single set having a common representative.
* @param i element of some set
* @param j element of some set
* @returns void
*/
void unionSet(uint64_t i, uint64_t j) {
/// checks if both belongs to same set or not
if (isSame(i, j)) {
return;
}
/// we find representative of the i and j
uint64_t x = findSet(i);
uint64_t y = findSet(j);
/// always keeping the min as x
/// in order to create a shallow tree
if (depth[x] > depth[y]) {
std::swap(x, y);
}
/// making the shallower tree, root parent of the deeper root
p[x] = y;
/// if same depth, then increase one's depth
if (depth[x] == depth[y]) {
depth[y]++;
}
/// total size of the resultant set
setSize[y] += setSize[x];
}
/**
* @brief A utility function which check whether i and j belongs to same set
* or not
* @param i element of some set
* @param j element of some set
* @returns `true` if element i and j are in same set
* @returns `false` if element i and j are not in same set
*/
bool isSame(uint64_t i, uint64_t j) {
if (findSet(i) == findSet(j)) {
return true;
}
return false;
}
/**
* @brief Method to print all the parents of i, or the path from i to
* representative.
* @param i element of some set
* @returns void
*/
vector<uint64_t> getParents(uint64_t i) {
vector<uint64_t> ans;
while (p[i] != i) {
ans.push_back(i);
i = p[i];
}
ans.push_back(i);
return ans;
}
};
/**
* @brief Self-implementations, 1st test
* @returns void
*/
static void test1() {
/* checks the parents in the resultant structures */
uint64_t n = 10; ///< number of elements
dsu d(n + 1); ///< object of class disjoint sets
d.unionSet(2, 1); ///< performs union operation on 1 and 2
d.unionSet(1, 4);
d.unionSet(8, 1);
d.unionSet(3, 5);
d.unionSet(5, 6);
d.unionSet(5, 7);
d.unionSet(9, 10);
d.unionSet(2, 10);
// keeping track of the changes using parent pointers
vector<uint64_t> ans = {7, 5};
for (uint64_t i = 0; i < ans.size(); i++) {
assert(d.getParents(7).at(i) ==
ans[i]); // makes sure algorithm works fine
}
cout << "1st test passed!" << endl;
}
/**
* @brief Self-implementations, 2nd test
* @returns void
*/
static void test2() {
// checks the parents in the resultant structures
uint64_t n = 10; ///< number of elements
dsu d(n + 1); ///< object of class disjoint sets
d.unionSet(2, 1); /// performs union operation on 1 and 2
d.unionSet(1, 4);
d.unionSet(8, 1);
d.unionSet(3, 5);
d.unionSet(5, 6);
d.unionSet(5, 7);
d.unionSet(9, 10);
d.unionSet(2, 10);
/// keeping track of the changes using parent pointers
vector<uint64_t> ans = {2, 1, 10};
for (uint64_t i = 0; i < ans.size(); i++) {
assert(d.getParents(2).at(i) ==
ans[i]); /// makes sure algorithm works fine
}
cout << "2nd test passed!" << endl;
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test1(); // run 1st test case
test2(); // run 2nd test case
return 0;
}
+281
View File
@@ -0,0 +1,281 @@
/**
* @file
* @brief Implementation of singly linked list algorithm.
* @details
* The linked list is a data structure used for holding a sequence of
* values, which can be added, removed and displayed.
* ### Algorithm
* Values can be added by iterating to the end of a list(by following
* the pointers) starting from the first link. Whichever link points to null
* is considered the last link and is pointed to the new value.
*
* Values can be removed by also iterating through the list. When the node
* containing the value is found, the node pointing to the current node is made
* to point to the node that the current node is pointing to, and then returning
* the current node to heap store.
*/
#include <iostream>
#include <memory>
#include <string>
/**
* @namespace data_structures
* @brief Data Structures algorithms
*/
namespace data_structures {
/**
* @namespace linked_list
* @brief Functions for singly linked list algorithm
*/
namespace linked_list {
/**
* This function checks if the string passed consists
* of only digits.
* @param s To be checked if s contains only integers
* @returns true if there are only digits present in the string
* @returns false if any other character is found
*/
bool isDigit(const std::string& s) {
// function statements here
for (char i : s) {
if (!isdigit(i)) {
return false;
}
}
return true;
}
/**
* A link class containing a value and pointer to another link
*/
class link {
private:
int pvalue; ///< value of the current link
std::shared_ptr<link> psucc; ///< pointer to the next value on the list
public:
/**
* function returns the integer value stored in the link.
* @returns the integer value stored in the link.
*/
int val() { return pvalue; }
/**
* function returns the pointer to next link
* @returns the pointer to the next link
* */
std::shared_ptr<link>& succ() { return psucc; }
/**
* Creates link with provided value and pointer to next link
* @param value is the integer stored in the link
*/
explicit link(int value = 0) : pvalue(value), psucc(nullptr) {}
};
/**
* A list class containing a sequence of links
*/
class list {
private:
std::shared_ptr<link> first; ///< link before the actual first element
std::shared_ptr<link> last; ///< last link on the list
public:
/**
* List constructor. Initializes the first and last link.
*/
list() {
// Initialize the first link
first = std::make_shared<link>();
// Initialize the last link with the first link
last = nullptr;
}
bool isEmpty();
void push_back(int new_elem);
void push_front(int new_elem);
void erase(int old_elem);
void display();
std::shared_ptr<link> search(int find_elem);
void reverse();
};
/**
* function checks if list is empty
* @returns true if list is empty
* @returns false if list is not empty
*/
bool list::isEmpty() {
if (last == nullptr) {
return true;
} else {
return false;
}
}
/**
* function adds new element to the end of the list
* @param new_elem to be added to the end of the list
*/
void list::push_back(int new_elem) {
if (isEmpty()) {
first->succ() = std::make_shared<link>(new_elem);
last = first->succ();
} else {
last->succ() = std::make_shared<link>(new_elem);
last = last->succ();
}
}
/**
* function adds new element to the beginning of the list
* @param new_elem to be added to front of the list
*/
void list::push_front(int new_elem) {
if (isEmpty()) {
first->succ() = std::make_shared<link>(new_elem);
last = first->succ();
} else {
std::shared_ptr<link> t = std::make_shared<link>(new_elem);
t->succ() = first->succ();
first->succ() = t;
}
}
/**
* function erases old element from the list
* @param old_elem to be erased from the list
*/
void list::erase(int old_elem) {
if (isEmpty()) {
std::cout << "List is Empty!";
return;
}
std::shared_ptr<link> t = first;
std::shared_ptr<link> to_be_removed = nullptr;
while (t != last && t->succ()->val() != old_elem) {
t = t->succ();
}
if (t == last) {
std::cout << "Element not found\n";
return;
}
to_be_removed = t->succ();
t->succ() = t->succ()->succ();
to_be_removed.reset();
if (t->succ() == nullptr) {
last = t;
}
if (first == last){
last = nullptr;
}
}
/**
* function displays all the elements in the list
* @returns 'void'
*/
void list::display() {
if (isEmpty()) {
std::cout << "List is Empty!";
return;
}
std::shared_ptr<link> t = first;
while (t->succ() != nullptr) {
std::cout << t->succ()->val() << "\t";
t = t->succ();
}
}
/**
* function searchs for @param find_elem in the list
* @param find_elem to be searched for in the list
*/
std::shared_ptr<link> list::search(int find_elem) {
if (isEmpty()) {
std::cout << "List is Empty!";
return nullptr;
}
std::shared_ptr<link> t = first;
while (t != last && t->succ()->val() != find_elem) {
t = t->succ();
}
if (t == last) {
std::cout << "Element not found\n";
return nullptr;
}
std::cout << "Element was found\n";
return t->succ();
}
} // namespace linked_list
} // namespace data_structures
/**
* Main function:
* Allows the user add and delete values from the list.
* Also allows user to search for and display values in the list.
* @returns 0 on exit
*/
int main() {
data_structures::linked_list::list l;
int choice = 0;
int x = 0;
std::string s;
do {
std::cout << "\n1. Insert";
std::cout << "\n2. Delete";
std::cout << "\n3. Search";
std::cout << "\n4. Print";
std::cout << "\n0. Exit";
std::cout << "\n\nEnter you choice : ";
std::cin >> choice;
switch (choice) {
case 0:
std::cout << "\nQuitting the program...\n";
break;
case 1:
std::cout << "\nEnter the element to be inserted : ";
std::cin >> s;
if (data_structures::linked_list::isDigit(s)) {
x = std::stoi(s);
l.push_back(x);
} else {
std::cout << "Wrong Input!\n";
}
break;
case 2:
std::cout << "\nEnter the element to be removed : ";
std::cin >> s;
if (data_structures::linked_list::isDigit(s)) {
x = std::stoi(s);
l.erase(x);
} else {
std::cout << "Wrong Input!\n";
}
break;
case 3:
std::cout << "\nEnter the element to be searched : ";
std::cin >> s;
if (data_structures::linked_list::isDigit(s)) {
x = std::stoi(s);
std::shared_ptr<data_structures::linked_list::link> found =
l.search(x);
} else {
std::cout << "Wrong Input!\n";
}
break;
case 4:
l.display();
std::cout << "\n";
break;
default:
std::cout << "Invalid Input\n" << std::endl;
break;
}
} while (choice != 0);
return 0;
}
@@ -0,0 +1,114 @@
/**
* \file
* \brief Linked list implementation using Arrays
*
* The difference between the pointer implementation of linked list and array
* implementation of linked list:
* 1. The NULL is represented by -1;
* 2. Limited size. (in the following case it is 100 nodes at max). But we can
* reuse the nodes that are to be deleted by again linking it bacj to the list.
*/
#include <iostream>
struct Node {
int data;
int next;
};
Node AvailArray[100]; ///< array that will act as nodes of a linked list.
int head = -1;
int avail = 0;
void initialise_list() {
for (int i = 0; i <= 98; i++) {
AvailArray[i].next = i + 1;
}
AvailArray[99].next = -1; // indicating the end of the linked list.
}
/** This will return the index of the first free node present in the avail list
*/
int getnode() {
int NodeIndexToBeReturned = avail;
avail = AvailArray[avail].next;
return NodeIndexToBeReturned;
}
/** This function when called will delete the node with
* the index presented as an argument, and will put
* back that node into the array.
*/
void freeNode(int nodeToBeDeleted) {
AvailArray[nodeToBeDeleted].next = avail;
avail = nodeToBeDeleted;
}
/** The function will insert the given data
* into the front of the linked list.
*/
void insertAtTheBeginning(int data) {
int newNode = getnode();
AvailArray[newNode].data = data;
AvailArray[newNode].next = head;
head = newNode;
}
void insertAtTheEnd(int data) {
int newNode = getnode();
int temp = head;
while (AvailArray[temp].next != -1) {
temp = AvailArray[temp].next;
}
// temp is now pointing to the end node.
AvailArray[newNode].data = data;
AvailArray[newNode].next = -1;
AvailArray[temp].next = newNode;
}
void display() {
int temp = head;
while (temp != -1) {
std::cout << AvailArray[temp].data << "->";
temp = AvailArray[temp].next;
}
std::cout << "-1" << std::endl;
}
/** Main function */
int main() {
initialise_list();
int x, y, z;
for (;;) {
std::cout << "1. Insert At The Beginning" << std::endl;
std::cout << "2. Insert At The End" << std::endl;
std::cout << "3. Display" << std::endl;
std::cout << "4.Exit" << std::endl;
std::cout << "Enter Your choice" << std::endl;
std::cin >> z;
switch (z) {
case 1:
std::cout << "Enter the number you want to enter" << std::endl;
std::cin >> x;
insertAtTheBeginning(x);
break;
case 2:
std::cout << "Enter the number you want to enter" << std::endl;
std::cin >> y;
insertAtTheEnd(y);
break;
case 3:
std::cout
<< "The linked list contains the following element in order"
<< std::endl;
display();
break;
case 4:
return 0;
default:
std::cout << "The entered choice is not correct" << std::endl;
}
}
return 0;
}
+263
View File
@@ -0,0 +1,263 @@
/**
* @file
* @brief [Dynamic Array](https://en.wikipedia.org/wiki/Dynamic_array)
*
* @details
* The list_array is the implementation of list represented using array.
* We can perform basic CRUD operations as well as other operations like sorting
* etc.
*
* ### Algorithm
* It implements various method like insert, sort, search etc. efficiently.
* You can select the operation and methods will do the rest work for you.
* You can insert element, sort them in order, search efficiently, delete values
* and print the list.
*/
#include <array> /// for std::array
#include <cassert> /// for assert
#include <cstdint>
#include <iostream> /// for io operations
/**
* @namespace data_structures
* @brief Algorithms with data structures
*/
namespace data_structures {
/**
* @namespace list_array
* @brief Functions for [Dynamic
* Array](https://en.wikipedia.org/wiki/Dynamic_array) algorithm
*/
namespace list_array {
/**
* @brief Structure of List with supporting methods.
*/
template <uint64_t N>
struct list {
std::array<uint64_t, N> data{}; // Array that implement list
uint64_t top = 0; // Pointer to the last element
bool isSorted = false; // indicator whether list is sorted or not
/**
* @brief Search an element in the list using binarySearch.
* @param dataArr list
* @param first pointer to the first element in the remaining list
* @param last pointer to the last element in the remaining list
* @param val element that will be searched
* @return index of element in the list if present else -1
*/
uint64_t BinarySearch(const std::array<uint64_t, N> &dataArr,
const uint64_t &first, const uint64_t &last,
const uint64_t &val) {
// If both pointer cross each other means no element present in the list
// which is equal to the val
if (last < first) {
return -1;
}
uint64_t mid = (first + last) / 2;
// check whether current mid pointer value is equal to element or not
if (dataArr[mid] == val)
return mid;
// if current mid value is greater than element we have to search in
// first half
else if (val < dataArr[mid])
return (BinarySearch(dataArr, first, mid - 1, val));
// if current mid value is greater than element we have to search in
// second half
else if (val > dataArr[mid])
return (BinarySearch(dataArr, mid + 1, last, val));
std::cerr << __func__ << ":" << __LINE__ << ": Undefined condition\n";
return -1;
}
/**
* @brief Search an element using linear search
* @param dataArr list
* @param val element that will be searched
* @return index of element in the list if present else -1
*/
uint64_t LinearSearch(const std::array<uint64_t, N> &dataArr,
const uint64_t &val) const {
// Going through each element in the list
for (uint64_t i = 0; i < top; i++) {
if (dataArr[i] == val) {
return i; // element found at ith index
}
}
// element is not present in the list
return -1;
}
/*
* @brief Parent function of binarySearch and linearSearch methods
* @param val element that will be searched
* @return index of element in the list if present else -1
*/
uint64_t search(const uint64_t &val) {
uint64_t pos; // pos variable to store index value of element.
// if list is sorted, binary search works efficiently else linear search
// is the only option
if (isSorted) {
pos = BinarySearch(data, 0, top - 1, val);
} else {
pos = LinearSearch(data, val);
}
// if index is equal to -1 means element does not present
// else print the index of that element
if (pos != -1) {
std::cout << "\nElement found at position : " << pos;
} else {
std::cout << "\nElement not found";
}
// return the index of element or -1.
return pos;
}
/**
* @brief Sort the list
* @returns void
*/
void sort() {
// Going through each element in the list
for (uint64_t i = 0; i < top; i++) {
uint64_t min_idx = i; // Initialize the min variable
for (uint64_t j = i + 1; j < top; j++) {
// check whether any element less than current min value
if (data[j] < data[min_idx]) {
min_idx = j; // update index accordingly
}
}
// swap min value and element at the ith index
std::swap(data[min_idx], data[i]);
}
// mark isSorted variable as true
isSorted = true;
}
/**
* @brief Insert the new element in the list
* @param val element that will be inserted
* @returns void
*/
void insert(const uint64_t &val) {
// overflow check
if (top == N) {
std::cout << "\nOverflow";
return;
}
// if list is not sorted, insert at the last
// otherwise place it to correct position
if (!isSorted) {
data[top] = val;
top++;
} else {
uint64_t pos = 0; // Initialize the index variable
// Going through each element and find correct position for element
for (uint64_t i = 0; i < top - 1; i++) {
// check for the correct position
if (data[i] <= val && val <= data[i + 1]) {
pos = i + 1; // assign correct pos to the index var
break; // to get out from the loop
}
}
// if all elements are smaller than the element
if (pos == 0) {
pos = top - 1;
}
// shift all element to make a room for new element
for (uint64_t i = top; i > pos; i--) {
data[i] = data[i - 1];
}
top++; // Increment the value of top.
data[pos] =
val; // Assign the value to the correct index in the array
}
}
/**
* @brief To remove the element from the list
* @param val element that will be removed
* @returns void
*/
void remove(const uint64_t &val) {
uint64_t pos = search(val); // search the index of the value
// if search returns -1, element does not present in the list
if (pos == -1) {
std::cout << "\n Element does not present in the list ";
return;
}
std::cout << "\n"
<< data[pos] << " deleted"; // print the appropriate message
// shift all the element 1 left to fill vacant space
for (uint64_t i = pos; i < top; i++) {
data[i] = data[i + 1];
}
top--; // decrement the top variable to maintain last index
}
/**
* @brief Utility function to print array
* @returns void
*/
void show() {
// Going through each element in the list
std::cout << '\n';
for (uint64_t i = 0; i < top; i++) {
std::cout << data[i] << " "; // print the element
}
}
}; // structure list
} // namespace list_array
} // namespace data_structures
/**
* @brief Test implementations
* @returns void
*/
static void test() {
data_structures::list_array::list<50> L;
// Insert testing
L.insert(11);
L.insert(12);
assert(L.top == 2);
L.insert(15);
L.insert(10);
L.insert(12);
L.insert(20);
L.insert(18);
assert(L.top == 7);
L.show(); // To print the array
// Remove testing
L.remove(12); // Remove Duplicate value in the list
L.remove(15); // Remove the existing value in the list
assert(L.top == 5);
L.remove(50); // Try to remove the non-existing value in the list
assert(L.top == 5);
// LinearSearch testing
assert(L.search(11) == 0); // search for the existing element
assert(L.search(12) == 2);
assert(L.search(50) == -1); // search for the non-existing element
// Sort testing
L.sort();
assert(L.isSorted == true);
L.show();
// BinarySearch testing
assert(L.search(11) == 1); // search for the existing element
assert(L.search(12) == 2);
assert(L.search(50) == -1); // search for the non-existing element
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // Execute the tests
return 0;
}
+101
View File
@@ -0,0 +1,101 @@
#include <iostream>
#include <queue>
/**************************
@author shrutisheoran
**************************/
using namespace std;
struct Btree {
int data;
struct Btree *left; // Pointer to left subtree
struct Btree *right; // Pointer to right subtree
};
void insert(Btree **root, int d) {
Btree *nn = new Btree(); // Creating new node
nn->data = d;
nn->left = NULL;
nn->right = NULL;
if (*root == NULL) {
*root = nn;
return;
} else {
queue<Btree *> q;
// Adding root node to queue
q.push(*root);
while (!q.empty()) {
Btree *node = q.front();
// Removing parent node from queue
q.pop();
if (node->left)
// Adding left child of removed node to queue
q.push(node->left);
else {
// Adding new node if no left child is present
node->left = nn;
return;
}
if (node->right)
// Adding right child of removed node to queue
q.push(node->right);
else {
// Adding new node if no right child is present
node->right = nn;
return;
}
}
}
}
void morrisInorder(Btree *root) {
Btree *curr = root;
Btree *temp;
while (curr) {
if (curr->left == NULL) {
cout << curr->data << " ";
// If left of current node is NULL then curr is shifted to right
curr = curr->right;
} else {
// Left of current node is stored in temp
temp = curr->left;
// Moving to extreme right of temp
while (temp->right && temp->right != curr) temp = temp->right;
// If extreme right is null it is made to point to currrent node
// (will be used for backtracking)
if (temp->right == NULL) {
temp->right = curr;
// current node is made to point its left subtree
curr = curr->left;
}
// If extreme right already points to currrent node it it set to
// null
else if (temp->right == curr) {
cout << curr->data << " ";
temp->right = NULL;
// current node is made to point its right subtree
curr = curr->right;
}
}
}
}
void deleteAll(const Btree *const root) {
if (root) {
deleteAll(root->left);
deleteAll(root->right);
delete root;
}
}
int main() {
// Testing morrisInorder funtion
Btree *root = NULL;
int i;
for (i = 1; i <= 7; i++) insert(&root, i);
cout << "Morris Inorder: ";
morrisInorder(root);
deleteAll(root);
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
/**
* @file
* @brief Provides Node class and related utilities
**/
#ifndef DATA_STRUCTURES_NODE_HPP_
#define DATA_STRUCTURES_NODE_HPP_
#include <iostream> /// for std::cout
#include <memory> /// for std::shared_ptr
#include <vector> /// for std::vector
/** Definition of the node as a linked-list
* \tparam ValueType type of data nodes of the linked list should contain
*/
template <class ValueType>
struct Node {
using value_type = ValueType;
ValueType data = {};
std::shared_ptr<Node<ValueType>> next = {};
};
template <typename Node, typename Action>
void traverse(const Node* const inNode, const Action& action) {
if (inNode) {
action(*inNode);
traverse(inNode->next.get(), action);
}
}
template <typename Node>
void display_all(const Node* const inNode) {
traverse(inNode,
[](const Node& curNode) { std::cout << curNode.data << " "; });
}
template <typename Node>
std::vector<typename Node::value_type> push_all_to_vector(
const Node* const inNode, const std::size_t expected_size = 0) {
std::vector<typename Node::value_type> res;
res.reserve(expected_size);
traverse(inNode,
[&res](const Node& curNode) { res.push_back(curNode.data); });
return res;
}
#endif // DATA_STRUCTURES_NODE_HPP_
+104
View File
@@ -0,0 +1,104 @@
/* This class specifies the basic operation on a queue as a linked list */
#ifndef DATA_STRUCTURES_QUEUE_HPP_
#define DATA_STRUCTURES_QUEUE_HPP_
#include "node.hpp"
/** Definition of the queue class */
template <class ValueType>
class queue {
using node_type = Node<ValueType>;
public:
using value_type = ValueType;
/**
* @brief prints the queue into the std::cout
*/
void display() const {
std::cout << "Front --> ";
display_all(this->queueFront.get());
std::cout << '\n';
std::cout << "Size of queue: " << size << '\n';
}
/**
* @brief converts the queue into the std::vector
* @return std::vector containning all of the elements of the queue in the
* same order
*/
std::vector<value_type> toVector() const {
return push_all_to_vector(this->queueFront.get(), this->size);
}
private:
/**
* @brief throws an exception if queue is empty
* @exception std::invalid_argument if queue is empty
*/
void ensureNotEmpty() const {
if (isEmptyQueue()) {
throw std::invalid_argument("Queue is empty.");
}
}
public:
/**
* @brief checks if the queue has no elements
* @return true if the queue is empty, false otherwise
*/
bool isEmptyQueue() const { return (queueFront == nullptr); }
/**
* @brief inserts a new item into the queue
*/
void enQueue(const value_type& item) {
auto newNode = std::make_shared<node_type>();
newNode->data = item;
newNode->next = nullptr;
if (isEmptyQueue()) {
queueFront = newNode;
queueRear = newNode;
} else {
queueRear->next = newNode;
queueRear = queueRear->next;
}
++size;
}
/**
* @return the first element of the queue
* @exception std::invalid_argument if queue is empty
*/
value_type front() const {
ensureNotEmpty();
return queueFront->data;
}
/**
* @brief removes the first element from the queue
* @exception std::invalid_argument if queue is empty
*/
void deQueue() {
ensureNotEmpty();
queueFront = queueFront->next;
--size;
}
/**
* @brief removes all elements from the queue
*/
void clear() {
queueFront = nullptr;
queueRear = nullptr;
size = 0;
}
private:
std::shared_ptr<node_type> queueFront =
{}; /**< Pointer to the front of the queue */
std::shared_ptr<node_type> queueRear =
{}; /**< Pointer to the rear of the queue */
std::size_t size = 0;
};
#endif // DATA_STRUCTURES_QUEUE_HPP_
+140
View File
@@ -0,0 +1,140 @@
/**
* @file
* @brief Implementation of Linear [Queue using array]
* (https://www.geeksforgeeks.org/array-implementation-of-queue-simple/).
* @details
* The Linear Queue is a data structure used for holding a sequence of
* values, which can be added to the end line (enqueue), removed from
* head of line (dequeue) and displayed.
* ### Algorithm
* Values can be added by increasing the `rear` variable by 1 (which points to
* the end of the array), then assigning new value to `rear`'s element of the
* array.
*
* Values can be removed by increasing the `front` variable by 1 (which points
* to the first of the array), so it cannot reached any more.
*
* @author [Pooja](https://github.com/pooja-git11)
* @author [Farbod Ahmadian](https://github.com/farbodahm)
*/
#include <array> /// for std::array
#include <cstdint>
#include <iostream> /// for io operations
constexpr uint16_t max_size{10}; ///< Maximum size of the queue
/**
* @namespace data_structures
* @brief Algorithms with data structures
*/
namespace data_structures {
/**
* @namespace queue_using_array
* @brief Functions for [Queue using Array]
* (https://www.geeksforgeeks.org/array-implementation-of-queue-simple/)
* implementation.
*/
namespace queue_using_array {
/**
* @brief Queue_Array class containing the main data and also index of head and
* tail of the array.
*/
class Queue_Array {
public:
void enqueue(const int16_t&); ///< Add element to the first of the queue
int dequeue(); ///< Delete element from back of the queue
void display() const; ///< Show all saved data
private:
int8_t front{-1}; ///< Index of head of the array
int8_t rear{-1}; ///< Index of tail of the array
std::array<int16_t, max_size> arr{}; ///< All stored data
};
/**
* @brief Adds new element to the end of the queue
* @param ele to be added to the end of the queue
*/
void Queue_Array::enqueue(const int16_t& ele) {
if (rear == arr.size() - 1) {
std::cout << "\nStack is full";
} else if (front == -1 && rear == -1) {
front = 0;
rear = 0;
arr[rear] = ele;
} else if (rear < arr.size()) {
++rear;
arr[rear] = ele;
}
}
/**
* @brief Remove element that is located at the first of the queue
* @returns data that is deleted if queue is not empty
*/
int Queue_Array::dequeue() {
int8_t d{0};
if (front == -1) {
std::cout << "\nstack is empty ";
return 0;
} else if (front == rear) {
d = arr.at(front);
front = rear = -1;
} else {
d = arr.at(front++);
}
return d;
}
/**
* @brief Utility function to show all elements in the queue
*/
void Queue_Array::display() const {
if (front == -1) {
std::cout << "\nStack is empty";
} else {
for (int16_t i{front}; i <= rear; ++i) std::cout << arr.at(i) << " ";
}
}
} // namespace queue_using_array
} // namespace data_structures
/**
* @brief Main function
* @details
* Allows the user to add and delete values from the queue.
* Also allows user to display values in the queue.
* @returns 0 on exit
*/
int main() {
int op{0}, data{0};
data_structures::queue_using_array::Queue_Array ob;
std::cout << "\n1. enqueue(Insertion) ";
std::cout << "\n2. dequeue(Deletion)";
std::cout << "\n3. Display";
std::cout << "\n4. Exit";
while (true) {
std::cout << "\nEnter your choice ";
std::cin >> op;
if (op == 1) {
std::cout << "Enter data ";
std::cin >> data;
ob.enqueue(data);
} else if (op == 2) {
data = ob.dequeue();
std::cout << "\ndequeue element is:\t" << data;
} else if (op == 3) {
ob.display();
} else if (op == 4) {
exit(0);
} else {
std::cout << "\nWrong choice ";
}
}
return 0;
}
+56
View File
@@ -0,0 +1,56 @@
#include <iostream>
int queue[10];
int front = 0;
int rear = 0;
void Enque(int x) {
if (rear == 10) {
std::cout << "\nOverflow";
} else {
queue[rear++] = x;
}
}
void Deque() {
if (front == rear) {
std::cout << "\nUnderflow";
}
else {
std::cout << "\n" << queue[front++] << " deleted";
for (int i = front; i < rear; i++) {
queue[i - front] = queue[i];
}
rear = rear - front;
front = 0;
}
}
void show() {
for (int i = front; i < rear; i++) {
std::cout << queue[i] << "\t";
}
}
int main() {
int ch, x;
do {
std::cout << "\n1. Enque";
std::cout << "\n2. Deque";
std::cout << "\n3. Print";
std::cout << "\nEnter Your Choice : ";
std::cin >> ch;
if (ch == 1) {
std::cout << "\nInsert : ";
std::cin >> x;
Enque(x);
} else if (ch == 2) {
Deque();
} else if (ch == 3) {
show();
}
} while (ch != 0);
return 0;
}
@@ -0,0 +1,70 @@
#include <iostream>
using namespace std;
struct node {
int val;
node *next;
};
node *front, *rear;
void Enque(int x) {
if (rear == NULL) {
node *n = new node;
n->val = x;
n->next = NULL;
rear = n;
front = n;
}
else {
node *n = new node;
n->val = x;
n->next = NULL;
rear->next = n;
rear = n;
}
}
void Deque() {
if (rear == NULL && front == NULL) {
cout << "\nUnderflow";
} else {
node *t = front;
cout << "\n" << t->val << " deleted";
front = front->next;
delete t;
if (front == NULL)
rear = NULL;
}
}
void show() {
node *t = front;
while (t != NULL) {
cout << t->val << "\t";
t = t->next;
}
}
int main() {
int ch, x;
do {
cout << "\n1. Enque";
cout << "\n2. Deque";
cout << "\n3. Print";
cout << "\nEnter Your Choice : ";
cin >> ch;
if (ch == 1) {
cout << "\nInsert : ";
cin >> x;
Enque(x);
} else if (ch == 2) {
Deque();
} else if (ch == 3) {
show();
}
} while (ch != 0);
return 0;
}
@@ -0,0 +1,86 @@
/*
Write a program to implement Queue using linkedlist.
*/
#include <iostream>
struct linkedlist {
int data;
linkedlist *next;
};
class stack_linkedList {
public:
linkedlist *front;
linkedlist *rear;
stack_linkedList() { front = rear = NULL; }
void enqueue(int);
int dequeue();
void display();
};
void stack_linkedList::enqueue(int ele) {
linkedlist *temp = new linkedlist();
temp->data = ele;
temp->next = NULL;
if (front == NULL)
front = rear = temp;
else {
rear->next = temp;
rear = temp;
}
}
int stack_linkedList::dequeue() {
linkedlist *temp;
int ele;
if (front == NULL)
std::cout << "\nStack is empty";
else {
temp = front;
ele = temp->data;
if (front == rear) // if length of queue is 1;
rear = rear->next;
front = front->next;
delete (temp);
}
return ele;
}
void stack_linkedList::display() {
if (front == NULL)
std::cout << "\nStack is empty";
else {
linkedlist *temp;
temp = front;
while (temp != NULL) {
std::cout << temp->data << " ";
temp = temp->next;
}
}
}
int main() {
int op, data;
stack_linkedList ob;
std::cout << "\n1. enqueue(Insertion) ";
std::cout << "\n2. dequeue(Deletion)";
std::cout << "\n3. Display";
std::cout << "\n4. Exit";
while (1) {
std::cout << "\nEnter your choice ";
std::cin >> op;
if (op == 1) {
std::cout << "Enter data ";
std::cin >> data;
ob.enqueue(data);
} else if (op == 2)
data = ob.dequeue();
else if (op == 3)
ob.display();
else if (op == 4)
exit(0);
else
std::cout << "\nWrong choice ";
}
return 0;
}
+144
View File
@@ -0,0 +1,144 @@
/**
* @author [shoniavika](https://github.com/shoniavika)
* @file
*
* Implementation of a Queue using two Stacks.
*/
#include <cassert>
#include <iostream>
#include <stack>
namespace {
/**
* @brief Queue data structure. Stores elements in FIFO
* (first-in-first-out) manner.
* @tparam T datatype to store in the queue
*/
template <typename T>
class MyQueue {
private:
std::stack<T> s1, s2;
public:
/**
* Constructor for queue.
*/
MyQueue() = default;
/**
* Pushes x to the back of queue.
*/
void push(T x);
/**
* Removes an element from the front of the queue.
*/
const T& pop();
/**
* Returns first element, without removing it.
*/
const T& peek() const;
/**
* Returns whether the queue is empty.
*/
bool empty() const;
};
/**
* Appends element to the end of the queue
*/
template <typename T>
void MyQueue<T>::push(T x) {
while (!s2.empty()) {
s1.push(s2.top());
s2.pop();
}
s2.push(x);
while (!s1.empty()) {
s2.push(s1.top());
s1.pop();
}
}
/**
* Removes element from the front of the queue
*/
template <typename T>
const T& MyQueue<T>::pop() {
const T& temp = MyQueue::peek();
s2.pop();
return temp;
}
/**
* Returns element in the front.
* Does not remove it.
*/
template <typename T>
const T& MyQueue<T>::peek() const {
if (!empty()) {
return s2.top();
}
std::cerr << "Queue is empty" << std::endl;
exit(0);
}
/**
* Checks whether a queue is empty
*/
template <typename T>
bool MyQueue<T>::empty() const {
return s2.empty() && s1.empty();
}
} // namespace
/**
* Testing function
*/
void queue_test() {
MyQueue<int> que;
std::cout << "Test #1\n";
que.push(2);
que.push(5);
que.push(0);
assert(que.peek() == 2);
assert(que.pop() == 2);
assert(que.peek() == 5);
assert(que.pop() == 5);
assert(que.peek() == 0);
assert(que.pop() == 0);
assert(que.empty() == true);
std::cout << "PASSED\n";
std::cout << "Test #2\n";
que.push(-1);
assert(que.empty() == false);
assert(que.peek() == -1);
assert(que.pop() == -1);
std::cout << "PASSED\n";
MyQueue<double> que2;
std::cout << "Test #3\n";
que2.push(2.31223);
que2.push(3.1415926);
que2.push(2.92);
assert(que2.peek() == 2.31223);
assert(que2.pop() == 2.31223);
assert(que2.peek() == 3.1415926);
assert(que2.pop() == 3.1415926);
assert(que2.peek() == 2.92);
assert(que2.pop() == 2.92);
std::cout << "PASSED\n";
}
/**
* Main function, calls testing function
*/
int main() {
queue_test();
return 0;
}
+505
View File
@@ -0,0 +1,505 @@
#include<iostream>
using namespace std;
struct node
{
int key;
node *parent;
char color;
node *left;
node *right;
};
class RBtree
{
node *root;
node *q;
public:
RBtree()
{
q = NULL;
root = NULL;
}
void insert();
void insertfix(node *);
void leftrotate(node *);
void rightrotate(node *);
void del();
node* successor(node *);
void delfix(node *);
void disp();
void display(node *);
void search();
};
void RBtree::insert()
{
int z;
cout << "\nEnter key of the node to be inserted: ";
cin >> z;
node *p, *q;
node *t = new node;
t->key = z;
t->left = NULL;
t->right = NULL;
t->color = 'r';
p = root;
q = NULL;
if (root == NULL)
{
root = t;
t->parent = NULL;
}
else
{
while (p != NULL)
{
q = p;
if (p->key < t->key)
p = p->right;
else
p = p->left;
}
t->parent = q;
if (q->key < t->key)
q->right = t;
else
q->left = t;
}
insertfix(t);
}
void RBtree::insertfix(node *t)
{
node *u;
if (root == t)
{
t->color = 'b';
return;
}
while (t->parent != NULL && t->parent->color == 'r')
{
node *g = t->parent->parent;
if (g->left == t->parent)
{
if (g->right != NULL)
{
u = g->right;
if (u->color == 'r')
{
t->parent->color = 'b';
u->color = 'b';
g->color = 'r';
t = g;
}
}
else
{
if (t->parent->right == t)
{
t = t->parent;
leftrotate(t);
}
t->parent->color = 'b';
g->color = 'r';
rightrotate(g);
}
}
else
{
if (g->left != NULL)
{
u = g->left;
if (u->color == 'r')
{
t->parent->color = 'b';
u->color = 'b';
g->color = 'r';
t = g;
}
}
else
{
if (t->parent->left == t)
{
t = t->parent;
rightrotate(t);
}
t->parent->color = 'b';
g->color = 'r';
leftrotate(g);
}
}
root->color = 'b';
}
}
void RBtree::del()
{
if (root == NULL)
{
cout << "\nEmpty Tree.";
return;
}
int x;
cout << "\nEnter the key of the node to be deleted: ";
cin >> x;
node *p;
p = root;
node *y = NULL;
node *q = NULL;
int found = 0;
while (p != NULL && found == 0)
{
if (p->key == x)
found = 1;
if (found == 0)
{
if (p->key < x)
p = p->right;
else
p = p->left;
}
}
if (found == 0)
{
cout << "\nElement Not Found.";
return;
}
else
{
cout << "\nDeleted Element: " << p->key;
cout << "\nColour: ";
if (p->color == 'b')
cout << "Black\n";
else
cout << "Red\n";
if (p->parent != NULL)
cout << "\nParent: " << p->parent->key;
else
cout << "\nThere is no parent of the node. ";
if (p->right != NULL)
cout << "\nRight Child: " << p->right->key;
else
cout << "\nThere is no right child of the node. ";
if (p->left != NULL)
cout << "\nLeft Child: " << p->left->key;
else
cout << "\nThere is no left child of the node. ";
cout << "\nNode Deleted.";
if (p->left == NULL || p->right == NULL)
y = p;
else
y = successor(p);
if (y->left != NULL)
q = y->left;
else
{
if (y->right != NULL)
q = y->right;
else
q = NULL;
}
if (q != NULL)
q->parent = y->parent;
if (y->parent == NULL)
root = q;
else
{
if (y == y->parent->left)
y->parent->left = q;
else
y->parent->right = q;
}
if (y != p)
{
p->color = y->color;
p->key = y->key;
}
if (y->color == 'b')
delfix(q);
}
}
void RBtree::delfix(node *p)
{
node *s;
while (p != root && p->color == 'b')
{
if (p->parent->left == p)
{
s = p->parent->right;
if (s->color == 'r')
{
s->color = 'b';
p->parent->color = 'r';
leftrotate(p->parent);
s = p->parent->right;
}
if (s->right->color == 'b'&&s->left->color == 'b')
{
s->color = 'r';
p = p->parent;
}
else
{
if (s->right->color == 'b')
{
s->left->color = 'b';
s->color = 'r';
rightrotate(s);
s = p->parent->right;
}
s->color = p->parent->color;
p->parent->color = 'b';
s->right->color = 'b';
leftrotate(p->parent);
p = root;
}
}
else
{
s = p->parent->left;
if (s->color == 'r')
{
s->color = 'b';
p->parent->color = 'r';
rightrotate(p->parent);
s = p->parent->left;
}
if (s->left->color == 'b'&&s->right->color == 'b')
{
s->color = 'r';
p = p->parent;
}
else
{
if (s->left->color == 'b')
{
s->right->color = 'b';
s->color = 'r';
leftrotate(s);
s = p->parent->left;
}
s->color = p->parent->color;
p->parent->color = 'b';
s->left->color = 'b';
rightrotate(p->parent);
p = root;
}
}
p->color = 'b';
root->color = 'b';
}
}
void RBtree::leftrotate(node *p)
{
if (p->right == NULL)
return;
else
{
node *y = p->right;
if (y->left != NULL)
{
p->right = y->left;
y->left->parent = p;
}
else
p->right = NULL;
if (p->parent != NULL)
y->parent = p->parent;
if (p->parent == NULL)
root = y;
else
{
if (p == p->parent->left)
p->parent->left = y;
else
p->parent->right = y;
}
y->left = p;
p->parent = y;
}
}
void RBtree::rightrotate(node *p)
{
if (p->left == NULL)
return;
else
{
node *y = p->left;
if (y->right != NULL)
{
p->left = y->right;
y->right->parent = p;
}
else
p->left = NULL;
if (p->parent != NULL)
y->parent = p->parent;
if (p->parent == NULL)
root = y;
else
{
if (p == p->parent->left)
p->parent->left = y;
else
p->parent->right = y;
}
y->right = p;
p->parent = y;
}
}
node* RBtree::successor(node *p)
{
node *y = NULL;
if (p->left != NULL)
{
y = p->left;
while (y->right != NULL)
y = y->right;
}
else
{
y = p->right;
while (y->left != NULL)
y = y->left;
}
return y;
}
void RBtree::disp()
{
display(root);
}
void RBtree::display(node *p)
{
if (root == NULL)
{
cout << "\nEmpty Tree.";
return;
}
if (p != NULL)
{
cout << "\n\t NODE: ";
cout << "\n Key: " << p->key;
cout << "\n Colour: ";
if (p->color == 'b')
cout << "Black";
else
cout << "Red";
if (p->parent != NULL)
cout << "\n Parent: " << p->parent->key;
else
cout << "\n There is no parent of the node. ";
if (p->right != NULL)
cout << "\n Right Child: " << p->right->key;
else
cout << "\n There is no right child of the node. ";
if (p->left != NULL)
cout << "\n Left Child: " << p->left->key;
else
cout << "\n There is no left child of the node. ";
cout << endl;
if (p->left)
{
cout << "\n\nLeft:\n";
display(p->left);
}
/*else
cout<<"\nNo Left Child.\n";*/
if (p->right)
{
cout << "\n\nRight:\n";
display(p->right);
}
/*else
cout<<"\nNo Right Child.\n"*/
}
}
void RBtree::search()
{
if (root == NULL)
{
cout << "\nEmpty Tree\n";
return;
}
int x;
cout << "\n Enter key of the node to be searched: ";
cin >> x;
node *p = root;
int found = 0;
while (p != NULL && found == 0)
{
if (p->key == x)
found = 1;
if (found == 0)
{
if (p->key < x)
p = p->right;
else
p = p->left;
}
}
if (found == 0)
cout << "\nElement Not Found.";
else
{
cout << "\n\t FOUND NODE: ";
cout << "\n Key: " << p->key;
cout << "\n Colour: ";
if (p->color == 'b')
cout << "Black";
else
cout << "Red";
if (p->parent != NULL)
cout << "\n Parent: " << p->parent->key;
else
cout << "\n There is no parent of the node. ";
if (p->right != NULL)
cout << "\n Right Child: " << p->right->key;
else
cout << "\n There is no right child of the node. ";
if (p->left != NULL)
cout << "\n Left Child: " << p->left->key;
else
cout << "\n There is no left child of the node. ";
cout << endl;
}
}
int main()
{
int ch, y = 0;
RBtree obj;
do
{
cout << "\n\t RED BLACK TREE ";
cout << "\n 1. Insert in the tree ";
cout << "\n 2. Delete a node from the tree";
cout << "\n 3. Search for an element in the tree";
cout << "\n 4. Display the tree ";
cout << "\n 5. Exit ";
cout << "\nEnter Your Choice: ";
cin >> ch;
switch (ch)
{
case 1: obj.insert();
cout << "\nNode Inserted.\n";
break;
case 2: obj.del();
break;
case 3: obj.search();
break;
case 4: obj.disp();
break;
case 5: y = 1;
break;
default: cout << "\nEnter a Valid Choice.";
}
cout << endl;
} while (y != 1);
return 1;
}
+306
View File
@@ -0,0 +1,306 @@
/**
* @file
* @brief Implementation of [Reversing
* a single linked list](https://simple.wikipedia.org/wiki/Linked_list)
* @details
* The linked list is a data structure used for holding a sequence of
* values, which can be added, displayed, reversed, or removed.
* ### Algorithm
* Values can be added by iterating to the end of a list (by following
* the pointers) starting from the first link. Whichever link points to null
* is considered the last link and is pointed to the new value.
*
* Linked List can be reversed by using 3 pointers: current, previous, and
* next_node; we keep iterating until the last node. Meanwhile, before changing
* to the next of current, we store it in the next_node pointer, now we store
* the prev pointer in the current of next, this is where the actual reversal
* happens. And then we move the prev and current pointers one step forward.
* Then the head node is made to point to the last node (prev pointer) after
* completion of an iteration.
* [A graphic explanation and view of what's happening behind the
*scenes](https://drive.google.com/file/d/1pM5COF0wx-wermnNy_svtyZquaCUP2xS/view?usp=sharing)
*/
#include <cassert> /// for assert
#include <iostream> /// for I/O operations
#include <new> /// for managing dynamic storage
/**
* @namespace data_structures
* @brief Data Structures algorithms
*/
namespace data_structures {
/**
* @namespace linked_list
* @brief Functions for singly linked list algorithm
*/
namespace linked_list {
/**
* A Node class containing a value and pointer to another link
*/
class Node {
public:
int32_t val; /// value of the current link
Node* next; /// pointer to the next value on the list
};
/**
* @brief creates a deep copy of a list starting at the input node
* @param[in] node pointer to the first node/head of the list to be copied
* @return pointer to the first node/head of the copied list or nullptr
*/
Node* copy_all_nodes(const Node* const node) {
if (node) {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
Node* res = new Node();
res->val = node->val;
res->next = copy_all_nodes(node->next);
return res;
}
return nullptr;
}
/**
* A list class containing a sequence of links
*/
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
class list {
private:
Node* head = nullptr; // link before the actual first element
void delete_all_nodes();
void copy_all_nodes_from_list(const list& other);
public:
bool isEmpty() const;
void insert(int32_t new_elem);
void reverseList();
void display() const;
int32_t top() const;
int32_t last() const;
int32_t traverse(int32_t index) const;
~list();
list() = default;
list(const list& other);
list& operator=(const list& other);
};
/**
* @brief Utility function that checks if the list is empty
* @returns true if the list is empty
* @returns false if the list is not empty
*/
bool list::isEmpty() const { return head == nullptr; }
/**
* @brief Utility function that adds a new element at the end of the list
* @param new_elem element be added at the end of the list
*/
void list::insert(int32_t n) {
try {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
Node* new_node = new Node();
Node* temp = nullptr;
new_node->val = n;
new_node->next = nullptr;
if (isEmpty()) {
head = new_node;
} else {
temp = head;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = new_node;
}
} catch (std::bad_alloc& exception) {
std::cerr << "bad_alloc detected: " << exception.what() << "\n";
}
}
/**
* @brief Utility function for reversing a list
* @brief Using the current, previous, and next pointer.
* @returns void
*/
void list::reverseList() {
Node* curr = head;
Node* prev = nullptr;
Node* next_node = nullptr;
while (curr != nullptr) {
next_node = curr->next;
curr->next = prev;
prev = curr;
curr = next_node;
}
head = prev;
}
/**
* @brief Utility function to find the top element of the list
* @returns the top element of the list
*/
int32_t list::top() const {
if (!isEmpty()) {
return head->val;
} else {
throw std::logic_error("List is empty");
}
}
/**
* @brief Utility function to find the last element of the list
* @returns the last element of the list
*/
int32_t list::last() const {
if (!isEmpty()) {
Node* t = head;
while (t->next != nullptr) {
t = t->next;
}
return t->val;
} else {
throw std::logic_error("List is empty");
}
}
/**
* @brief Utility function to find the i th element of the list
* @returns the i th element of the list
*/
int32_t list::traverse(int32_t index) const {
Node* current = head;
int count = 0;
while (current != nullptr) {
if (count == index) {
return (current->val);
}
count++;
current = current->next;
}
/* if we get to this line,the caller was asking for a non-existent element
so we assert fail */
exit(1);
}
/**
* @brief calls delete operator on every node in the represented list
*/
void list::delete_all_nodes() {
while (head != nullptr) {
const auto tmp_node = head->next;
delete head;
head = tmp_node;
}
}
list::~list() { delete_all_nodes(); }
void list::copy_all_nodes_from_list(const list& other) {
assert(isEmpty());
head = copy_all_nodes(other.head);
}
/**
* @brief copy constructor creating a deep copy of every node of the input
*/
list::list(const list& other) { copy_all_nodes_from_list(other); }
/**
* @brief assignment operator creating a deep copy of every node of the input
*/
list& list::operator=(const list& other) {
if (this == &other) {
return *this;
}
delete_all_nodes();
copy_all_nodes_from_list(other);
return *this;
}
} // namespace linked_list
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
data_structures::linked_list::list L;
// 1st test
L.insert(11);
L.insert(12);
L.insert(15);
L.insert(10);
L.insert(-12);
L.insert(-20);
L.insert(18);
assert(L.top() == 11);
assert(L.last() == 18);
L.reverseList();
// Reversal Testing
assert(L.top() == 18);
assert(L.traverse(1) == -20);
assert(L.traverse(2) == -12);
assert(L.traverse(3) == 10);
assert(L.traverse(4) == 15);
assert(L.traverse(5) == 12);
assert(L.last() == 11);
std::cout << "All tests have successfully passed!" << std::endl;
}
void test_copy_constructor() {
data_structures::linked_list::list L;
L.insert(10);
L.insert(20);
L.insert(30);
data_structures::linked_list::list otherList(L);
otherList.insert(40);
L.insert(400);
assert(L.top() == 10);
assert(otherList.top() == 10);
assert(L.traverse(1) == 20);
assert(otherList.traverse(1) == 20);
assert(L.traverse(2) == 30);
assert(otherList.traverse(2) == 30);
assert(L.last() == 400);
assert(otherList.last() == 40);
}
void test_assignment_operator() {
data_structures::linked_list::list L;
data_structures::linked_list::list otherList;
L.insert(10);
L.insert(20);
L.insert(30);
otherList = L;
otherList.insert(40);
L.insert(400);
assert(L.top() == 10);
assert(otherList.top() == 10);
assert(L.traverse(1) == 20);
assert(otherList.traverse(1) == 20);
assert(L.traverse(2) == 30);
assert(otherList.traverse(2) == 30);
assert(L.last() == 400);
assert(otherList.last() == 40);
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
test_copy_constructor();
test_assignment_operator();
return 0;
}
+133
View File
@@ -0,0 +1,133 @@
/**
* @file
* @brief A data structure to quickly do operations on ranges: the [Segment Tree](https://en.wikipedia.org/wiki/Segment_tree) algorithm implementation
* @details
* Implementation of the segment tree data structre
*
* Can do point updates (updates the value of some position)
* and range queries, where it gives the value of some associative
* opperation done on a range
*
* Both of these operations take O(log N) time
* @author [Nishant Chatterjee](https://github.com/nishantc1527)
*/
#include <iostream> /// For IO operations
#include <vector> /// For std::vector
#include <algorithm> /// For std::min and std::max
#include <cassert> /// For assert
/*
* @namespace
* @brief Data structures
*/
namespace data_structures {
/**
* @brief class representation of the segment tree
* @tparam T The type of the class that goes in the datastructure
*/
template <class T>
class SegmentTree {
private:
const T ID = 0; ///< Comb(ID, x) = x
std::vector<T> t; ///< Vector to represent the tree
int size = 0; ///< Number of elements available for querying in the tree
private:
/**
* @brief Any associative function that combines x and y
* @param x The first operand
* @param y The second operand
* @return Some associative operation applied to these two values. In this case, I used addition
*/
T comb(T x, T y) {
return x + y;
}
/**
* @brief Gives the midpoint between two integers
* @param l The left endpoint
* @param r The right endpoint
* @return the middle point between them
*/
int mid(int l, int r) {
return l + (r - l) / 2;
}
/**
* @brief Helper method for update method below
* @param i The index of the current node
* @param l The leftmost node of the current node
* @param r The rightmost node of the current node
* @param pos The position to update
* @param val The value to update it to
*/
void update(int i, int l, int r, int pos, T val) {
if(l == r) t[i] = val;
else {
int m = mid(l, r);
if(pos <= m) update(i * 2, l, m, pos, val);
else update(i * 2 + 1, m + 1, r, pos, val);
t[i] = comb(t[i * 2], t[i * 2 + 1]);
}
}
/**
* @brief Helper method for range_comb method below
* @param i The current node
* @param l The leftmost node of the current node
* @param r The rightmost node of the current node
* @param tl The left endpoint of the range
* @param tr The right endpoint of the range
* @return The comb operation applied to all values between tl and tr
*/
T range_comb(int i, int l, int r, int tl, int tr) {
if(l == tl && r == tr) return t[i];
if(tl > tr) return 0;
int m = mid(l, r);
return comb(range_comb(i * 2, l, m, tl, std::min(tr, m)), range_comb(i * 2 + 1, m + 1, r, std::max(tl, m + 1), tr));
}
public:
SegmentTree(int n) : t(n * 4, ID), size(n) {}
/**
* @brief Updates a value at a certain position
* @param pos The position to update
* @param val The value to update it to
*/
void update(int pos, T val) {
update(1, 1, size, pos, val);
}
/**
* @brief Returns comb across all values between l and r
* @param l The left endpoint of the range
* @param r The right endpoint of the range
* @return The value of the comb operations
*/
T range_comb(int l, int r) {
return range_comb(1, 1, size, l, r);
}
};
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
data_structures::SegmentTree<int> t(5);
t.update(1, 1);
t.update(2, 2);
t.update(3, 3);
t.update(4, 4);
t.update(5, 5);
assert(t.range_comb(1, 3) == 6); // 1 + 2 + 3 = 6
t.update(1, 3);
assert(t.range_comb(1, 3) == 8); // 3 + 2 + 3 = 8
std::cout << "All tests have successfully passed!\n";
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
return 0;
}
+225
View File
@@ -0,0 +1,225 @@
/**
* @file skip_list.cpp
* @brief Data structure for fast searching and insertion in \f$O(\log n)\f$
* time
* @details
* A skip list is a data structure that is used for storing a sorted list of
* items with a help of hierarchy of linked lists that connect increasingly
* sparse subsequences of the items
*
* References used: [GeeksForGeek](https://www.geeksforgeeks.org/skip-list/),
* [OpenGenus](https://iq.opengenus.org/skip-list) for PseudoCode and Code
* @author [enqidu](https://github.com/enqidu)
* @author [Krishna Vedala](https://github.com/kvedala)
*/
#include <array>
#include <cstring>
#include <ctime>
#include <iostream>
#include <memory>
#include <vector>
/** \namespace data_structures
* \brief Data-structure algorithms
*/
namespace data_structures {
constexpr int MAX_LEVEL = 2; ///< Maximum level of skip list
constexpr float PROBABILITY = 0.5; ///< Current probability for "coin toss"
/**
* Node structure [Key][Node*, Node*...]
*/
struct Node {
int key; ///< key integer
void* value; ///< pointer of value
std::vector<std::shared_ptr<Node>>
forward; ///< nodes of the given one in all levels
/**
* Creates node with provided key, level and value
* @param key is number that is used for comparision
* @param level is the maximum level node's going to added
*/
Node(int key, int level, void* value = nullptr) : key(key), value(value) {
// Initialization of forward vector
for (int i = 0; i < (level + 1); i++) {
forward.push_back(nullptr);
}
}
};
/**
* SkipList class implementation with basic methods
*/
class SkipList {
int level; ///< Maximum level of the skiplist
std::shared_ptr<Node> header; ///< Pointer to the header node
public:
/**
* Skip List constructor. Initializes header, start
* Node for searching in the list
*/
SkipList() {
level = 0;
// Header initialization
header = std::make_shared<Node>(-1, MAX_LEVEL);
}
/**
* Returns random level of the skip list.
* Every higher level is 2 times less likely.
* @return random level for skip list
*/
int randomLevel() {
int lvl = 0;
while (static_cast<float>(std::rand()) / RAND_MAX < PROBABILITY &&
lvl < MAX_LEVEL) {
lvl++;
}
return lvl;
}
/**
* Inserts elements with given key and value;
* It's level is computed by randomLevel() function.
* @param key is number that is used for comparision
* @param value pointer to a value, that can be any type
*/
void insertElement(int key, void* value) {
std::cout << "Inserting" << key << "...";
std::shared_ptr<Node> x = header;
std::array<std::shared_ptr<Node>, MAX_LEVEL + 1> update;
update.fill(nullptr);
for (int i = level; i >= 0; i--) {
while (x->forward[i] != nullptr && x->forward[i]->key < key) {
x = x->forward[i];
}
update[i] = x;
}
x = x->forward[0];
bool doesnt_exist = (x == nullptr || x->key != key);
if (doesnt_exist) {
int rlevel = randomLevel();
if (rlevel > level) {
for (int i = level + 1; i < rlevel + 1; i++) update[i] = header;
// Update current level
level = rlevel;
}
std::shared_ptr<Node> n =
std::make_shared<Node>(key, rlevel, value);
for (int i = 0; i <= rlevel; i++) {
n->forward[i] = update[i]->forward[i];
update[i]->forward[i] = n;
}
std::cout << "Inserted" << std::endl;
} else {
std::cout << "Exists" << std::endl;
}
}
/**
* Deletes an element by key and prints if has been removed successfully
* @param key is number that is used for comparision.
*/
void deleteElement(int key) {
std::shared_ptr<Node> x = header;
std::array<std::shared_ptr<Node>, MAX_LEVEL + 1> update;
update.fill(nullptr);
for (int i = level; i >= 0; i--) {
while (x->forward[i] != nullptr && x->forward[i]->key < key) {
x = x->forward[i];
}
update[i] = x;
}
x = x->forward[0];
bool doesnt_exist = (x == nullptr || x->key != key);
if (!doesnt_exist) {
for (int i = 0; i <= level; i++) {
if (update[i]->forward[i] != x) {
break;
}
update[i]->forward[i] = x->forward[i];
}
/* Remove empty levels*/
while (level > 0 && header->forward[level] == nullptr) level--;
std::cout << "Deleted" << std::endl;
} else {
std::cout << "Doesn't exist" << std::endl;
}
}
/**
* Searching element in skip list structure
* @param key is number that is used for comparision
* @return pointer to the value of the node
*/
void* searchElement(int key) {
std::shared_ptr<Node> x = header;
std::cout << "Searching for " << key << std::endl;
for (int i = level; i >= 0; i--) {
while (x->forward[i] && x->forward[i]->key < key) x = x->forward[i];
}
x = x->forward[0];
if (x && x->key == key) {
std::cout << "Found" << std::endl;
return x->value;
} else {
std::cout << "Not Found" << std::endl;
return nullptr;
}
}
/**
* Display skip list level
*/
void displayList() {
std::cout << "Displaying list:\n";
for (int i = 0; i <= level; i++) {
std::shared_ptr<Node> node = header->forward[i];
std::cout << "Level " << (i) << ": ";
while (node != nullptr) {
std::cout << node->key << " ";
node = node->forward[i];
}
std::cout << std::endl;
}
}
};
} // namespace data_structures
/**
* Main function:
* Creates and inserts random 2^[number of levels]
* elements into the skip lists and than displays it
*/
int main() {
std::srand(std::time(nullptr));
data_structures::SkipList lst;
for (int j = 0; j < (1 << (data_structures::MAX_LEVEL + 1)); j++) {
int k = (std::rand() % (1 << (data_structures::MAX_LEVEL + 2)) + 1);
lst.insertElement(k, &j);
}
lst.displayList();
return 0;
}
+163
View File
@@ -0,0 +1,163 @@
/**
* @file
* @brief Implementation of [Sparse
* Table](https://brilliant.org/wiki/sparse-table/) for `min()` function.
* @author [Mann Patel](https://github.com/manncodes)
* @details
* Sparse Table is a data structure, that allows answering range queries.
* It can answer most range queries in O(logn), but its true power is answering
* range minimum queries (or equivalent range maximum queries). For those
* queries it can compute the answer in O(1) time. The only drawback of this
* data structure is, that it can only be used on immutable arrays. This means,
* that the array cannot be changed between two queries.
*
* If any element in the array changes, the complete data structure has to be
* recomputed.
*
* @todo make stress tests.
*
* @warning
* This sparse table is made for `min(a1,a2,...an)` duplicate invariant
* function. This implementation can be changed to other functions like
* `gcd()`, `lcm()`, and `max()` by changing a few lines of code.
*/
#include <array> /// for std::array
#include <cassert> /// for assert
#include <cstdint>
#include <iostream> /// for IO operations
/**
* @namespace data_structures
* @brief Data Structures algorithms
*/
namespace data_structures {
/**
* @namespace sparse_table
* @brief Functions for Implementation of [Sparse
* Table](https://brilliant.org/wiki/sparse-table/)
*/
namespace sparse_table {
/**
* @brief A struct to represent sparse table for `min()` as their invariant
* function, for the given array `A`. The answer to queries are stored in the
* array ST.
*/
constexpr uint32_t N = 12345; ///< the maximum size of the array.
constexpr uint8_t M = 14; ///< ceil(log2(N)).
struct Sparse_table {
size_t n = 0; ///< size of input array.
/** @warning check if `N` is not less than `n`. if so, manually increase the
* value of N */
std::array<int64_t, N> A = {}; ///< input array to perform RMQ.
std::array<std::array<int64_t, N>, M>
ST{}; ///< the sparse table storing `min()` values for given interval.
std::array<int64_t, N> LOG = {}; ///< where floor(log2(i)) are precomputed.
/**
* @brief Builds the sparse table for computing min/max/gcd/lcm/...etc
* for any contiguous sub-segment of the array.This is an example of
* computing the index of the minimum value.
* @return void
* @complexity: O(n.log(n))
*/
void buildST() {
LOG[0] = -1;
for (size_t i = 0; i < n; ++i) {
ST[0][i] = static_cast<int64_t>(i);
LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)`
}
for (size_t j = 1; static_cast<size_t>(1 << j) <= n; ++j) {
for (size_t i = 0; static_cast<size_t>(i + (1 << j)) <= n; ++i) {
/**
* @note notice how we deal with the range of length `pow(2,i)`,
* and we can reuse the computation that we did for the range of
* length `pow(2,i-1)`.
*
* So, ST[j][i] = min( ST[j-1][i], ST[j-1][i + pow(2,j-1)]).
* @example ST[2][3] = min(ST[1][3], ST[1][5])
*/
int64_t x = ST[j - 1][i]; ///< represents minimum value over
///< the range [j,i]
int64_t y =
ST[j - 1]
[i + (1 << (j - 1))]; ///< represents minimum value over
///< the range [j,i + pow(2,j-1)]
ST[j][i] =
(A[x] <= A[y] ? x : y); ///< represents minimum value over
///< the range [j,i]
}
}
}
/**
* @brief Queries the sparse table for the value of the interval [l, r]
* (i.e. from l to r inclusive).
* @param l the left index of the range (inclusive).
* @param r the right index of the range (inclusive).
* @return the computed value of the given interval.
* @complexity: O(1)
*/
int64_t query(int64_t l, int64_t r) {
int64_t g = LOG[r - l + 1]; ///< smallest power of 2 covering [l,r]
int64_t x = ST[g][l]; ///< represents minimum value over the range
///< [g,l]
int64_t y =
ST[g][r - (1 << g) + 1]; ///< represents minimum value over the
///< range [g, r - pow(2,g) + 1]
return (A[x] <= A[y] ? x : y); ///< represents minimum value over
///< the whole range [l,r]
}
};
} // namespace sparse_table
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
/* We take an array as an input on which we need to perform the ranged
* minimum queries[RMQ](https://en.wikipedia.org/wiki/Range_minimum_query).
*/
std::array<int64_t, 10> testcase = {
1, 2, 3, 4, 5,
6, 7, 8, 9, 10}; ///< array on which RMQ will be performed.
size_t testcase_size =
sizeof(testcase) / sizeof(testcase[0]); ///< size of self test's array
data_structures::sparse_table::Sparse_table
st{}; ///< declaring sparse tree
std::copy(std::begin(testcase), std::end(testcase),
std::begin(st.A)); ///< copying array to the struct
st.n = testcase_size; ///< passing the array's size to the struct
st.buildST(); ///< precomputing sparse tree
// pass queries of the form: [l,r]
assert(st.query(1, 9) == 1); ///< as 1 is smallest from 1..9
assert(st.query(2, 6) == 2); ///< as 2 is smallest from 2..6
assert(st.query(3, 8) == 3); ///< as 3 is smallest from 3..8
std::cout << "Self-test implementations passed!" << std::endl;
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
return 0;
}
+80
View File
@@ -0,0 +1,80 @@
/**
* @file
* @author danghai
* @author [Piotr Idzik](https://github.com/vil02)
* @brief This class specifies the basic operation on a stack as a linked list
**/
#ifndef DATA_STRUCTURES_STACK_HPP_
#define DATA_STRUCTURES_STACK_HPP_
#include <stdexcept> /// for std::invalid_argument
#include "node.hpp" /// for Node
/** Definition of the stack class
* \tparam value_type type of data nodes of the linked list in the stack should
* contain
*/
template <class ValueType>
class stack {
public:
using value_type = ValueType;
/** Show stack */
void display() const {
std::cout << "Top --> ";
display_all(this->stackTop.get());
std::cout << '\n';
std::cout << "Size of stack: " << size << std::endl;
}
std::vector<value_type> toVector() const {
return push_all_to_vector(this->stackTop.get(), this->size);
}
private:
void ensureNotEmpty() const {
if (isEmptyStack()) {
throw std::invalid_argument("Stack is empty.");
}
}
public:
/** Determine whether the stack is empty */
bool isEmptyStack() const { return (stackTop == nullptr); }
/** Add new item to the stack */
void push(const value_type& item) {
auto newNode = std::make_shared<Node<value_type>>();
newNode->data = item;
newNode->next = stackTop;
stackTop = newNode;
size++;
}
/** Return the top element of the stack */
value_type top() const {
ensureNotEmpty();
return stackTop->data;
}
/** Remove the top element of the stack */
void pop() {
ensureNotEmpty();
stackTop = stackTop->next;
size--;
}
/** Clear stack */
void clear() {
stackTop = nullptr;
size = 0;
}
private:
std::shared_ptr<Node<value_type>> stackTop =
{}; /**< Pointer to the stack */
std::size_t size = 0; ///< size of stack
};
#endif // DATA_STRUCTURES_STACK_HPP_
+179
View File
@@ -0,0 +1,179 @@
#include <cassert> /// For std::assert
#include <iostream> /// For std::cout
#include <memory> /// For std::unique_ptr
#include <stdexcept> /// For std::out_of_range
/**
* @namespace
* @brief data_structures
*/
namespace data_structures {
/**
* @brief Class representation of a stack
* @tparam T The type of the elements in the stack
*/
template <typename T>
class Stack {
private:
std::unique_ptr<T[]> stack; ///< Smart pointer to the stack array
int stackSize; ///< Maximum size of the stack
int stackIndex; ///< Index pointing to the top element of the stack
public:
/**
* @brief Constructs a new Stack object
*
* @param size Maximum size of the stack
*/
Stack(int size) : stack(new T[size]), stackSize(size), stackIndex(-1) {}
/**
* @brief Checks if the stack is full
*
* @return true if the stack is full, false otherwise
*/
bool full() const { return stackIndex == stackSize - 1; }
/**
* @brief Checks if the stack is empty
* @return true if the stack is empty, false otherwise
*/
bool empty() const { return stackIndex == -1; }
/**
* @brief Pushes an element onto the stack
*
* @param element Element to push onto the stack
*/
void push(T element) {
if (full()) {
throw std::out_of_range("Stack overflow");
} else {
stack[++stackIndex] = element;
}
}
/**
* @brief Pops an element from the stack
*
* @return The popped element
* @throws std::out_of_range if the stack is empty
*/
T pop() {
if (empty()) {
throw std::out_of_range("Stack underflow");
}
return stack[stackIndex--];
}
/**
* @brief Displays all elements in the stack
*/
void show() const {
for (int i = 0; i <= stackIndex; i++) {
std::cout << stack[i] << "\n";
}
}
/**
* @brief Displays the topmost element of the stack
*
* @return The topmost element of the stack
* @throws std::out_of_range if the stack is empty
*/
T topmost() const {
if (empty()) {
throw std::out_of_range("Stack underflow");
}
return stack[stackIndex];
}
/**
* @brief Displays the bottom element of the stack
*
* @return The bottom element of the stack
* @throws std::out_of_range if the stack is empty
*/
T bottom() const {
if (empty()) {
throw std::out_of_range("Stack underflow");
}
return stack[0];
}
};
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
data_structures::Stack<int> stack(5);
// Test empty and full operations
assert(stack.empty());
assert(!stack.full());
// Test pushing elements and checking topmost
stack.push(10);
assert(stack.topmost() == 10);
stack.push(20);
assert(stack.topmost() == 20);
stack.push(30);
stack.push(40);
stack.push(50);
assert(stack.full());
// Test stack overflow
try {
stack.push(60);
} catch (const std::out_of_range& e) {
assert(std::string(e.what()) == "Stack overflow");
}
// Test popping elements
assert(stack.pop() == 50);
assert(stack.pop() == 40);
assert(stack.pop() == 30);
// Check topmost and bottom elements
assert(stack.topmost() == 20);
assert(stack.bottom() == 10);
assert(stack.pop() == 20);
assert(stack.pop() == 10);
assert(stack.empty());
assert(!stack.full());
// Test stack underflow
try {
stack.pop();
} catch (const std::out_of_range& e) {
assert(std::string(e.what()) == "Stack underflow");
}
try {
stack.topmost();
} catch (const std::out_of_range& e) {
assert(std::string(e.what()) == "Stack underflow");
}
try {
stack.bottom();
} catch (const std::out_of_range& e) {
assert(std::string(e.what()) == "Stack underflow");
}
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
std::cout << "All tests passed!" << std::endl;
return 0;
}
@@ -0,0 +1,66 @@
#include <iostream>
struct node {
int val;
node *next;
};
node *top_var;
void push(int x) {
node *n = new node;
n->val = x;
n->next = top_var;
top_var = n;
}
void pop() {
if (top_var == nullptr) {
std::cout << "\nUnderflow";
} else {
node *t = top_var;
std::cout << "\n" << t->val << " deleted";
top_var = top_var->next;
delete t;
}
}
void show() {
node *t = top_var;
while (t != nullptr) {
std::cout << t->val << "\n";
t = t->next;
}
}
int main() {
int ch = 0, x = 0;
do {
std::cout << "\n0. Exit or Ctrl+C";
std::cout << "\n1. Push";
std::cout << "\n2. Pop";
std::cout << "\n3. Print";
std::cout << "\nEnter Your Choice: ";
std::cin >> ch;
switch (ch) {
case 0:
break;
case 1:
std::cout << "\nInsert : ";
std::cin >> x;
push(x);
break;
case 2:
pop();
break;
case 3:
show();
break;
default:
std::cout << "Invalid option!\n";
break;
}
} while (ch != 0);
return 0;
}
+119
View File
@@ -0,0 +1,119 @@
/**
* @brief Stack Data Structure Using the Queue Data Structure
* @details
* Using 2 Queues inside the Stack class, we can easily implement Stack
* data structure with heavy computation in push function.
*
* References used:
* [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue)
* @author [tushar2407](https://github.com/tushar2407)
*/
#include <cassert> /// for assert
#include <cstdint>
#include <iostream> /// for IO operations
#include <queue> /// for queue data structure
/**
* @namespace data_structures
* @brief Data structures algorithms
*/
namespace data_structures {
/**
* @namespace stack_using_queue
* @brief Functions for the [Stack Using
* Queue](https://www.studytonight.com/data-structures/stack-using-queue)
* implementation
*/
namespace stack_using_queue {
/**
* @brief Stack Class implementation for basic methods of Stack Data Structure.
*/
struct Stack {
std::queue<int64_t> main_q; ///< stores the current state of the stack
std::queue<int64_t> auxiliary_q; ///< used to carry out intermediate
///< operations to implement stack
uint32_t current_size = 0; ///< stores the current size of the stack
/**
* Returns the top most element of the stack
* @returns top element of the queue
*/
int top() { return main_q.front(); }
/**
* @brief Inserts an element to the top of the stack.
* @param val the element that will be inserted into the stack
* @returns void
*/
void push(int val) {
auxiliary_q.push(val);
while (!main_q.empty()) {
auxiliary_q.push(main_q.front());
main_q.pop();
}
swap(main_q, auxiliary_q);
current_size++;
}
/**
* @brief Removes the topmost element from the stack
* @returns void
*/
void pop() {
if (main_q.empty()) {
return;
}
main_q.pop();
current_size--;
}
/**
* @brief Utility function to return the current size of the stack
* @returns current size of stack
*/
int size() { return current_size; }
};
} // namespace stack_using_queue
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
data_structures::stack_using_queue::Stack s;
s.push(1); /// insert an element into the stack
s.push(2); /// insert an element into the stack
s.push(3); /// insert an element into the stack
assert(s.size() == 3); /// size should be 3
assert(s.top() == 3); /// topmost element in the stack should be 3
s.pop(); /// remove the topmost element from the stack
assert(s.top() == 2); /// topmost element in the stack should now be 2
s.pop(); /// remove the topmost element from the stack
assert(s.top() == 1);
s.push(5); /// insert an element into the stack
assert(s.top() == 5); /// topmost element in the stack should now be 5
s.pop(); /// remove the topmost element from the stack
assert(s.top() == 1); /// topmost element in the stack should now be 1
assert(s.size() == 1); /// size should be 1
}
/**
* @brief Main function
* Creates a stack and pushed some value into it.
* Through a series of push and pop functions on stack,
* it demostrates the functionality of the custom stack
* declared above.
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
return 0;
}
+17
View File
@@ -0,0 +1,17 @@
3.4 Tom
3.2 Kathy
2.5 Hoang
3.4 Tom
3.8 Randy
3.9 Kingston
3.8 Mickey
3.6 Peter
3.5 Donald
3.8 Cindy
3.7 Dome
3.9 Andy
3.8 Hai
3.9 Minnie
2.7 Gilda
3.9 Vinay
3.4 Hiral
+93
View File
@@ -0,0 +1,93 @@
#include <cassert> /// for assert
#include <iostream> /// for std::cout
#include "./queue.hpp"
template <typename T>
void testConstructedQueueIsEmpty() {
const queue<T> curQueue;
assert(curQueue.isEmptyQueue());
}
void testEnQueue() {
queue<int> curQueue;
curQueue.enQueue(10);
assert(curQueue.toVector() == std::vector<int>({10}));
curQueue.enQueue(20);
assert(curQueue.toVector() == std::vector<int>({10, 20}));
curQueue.enQueue(30);
curQueue.enQueue(40);
assert(curQueue.toVector() == std::vector<int>({10, 20, 30, 40}));
}
void testDeQueue() {
queue<int> curQueue;
curQueue.enQueue(10);
curQueue.enQueue(20);
curQueue.enQueue(30);
curQueue.deQueue();
assert(curQueue.toVector() == std::vector<int>({20, 30}));
curQueue.deQueue();
assert(curQueue.toVector() == std::vector<int>({30}));
curQueue.deQueue();
assert(curQueue.isEmptyQueue());
}
void testFront() {
queue<int> curQueue;
curQueue.enQueue(10);
assert(curQueue.front() == 10);
curQueue.enQueue(20);
assert(curQueue.front() == 10);
}
void testQueueAfterClearIsEmpty() {
queue<int> curQueue;
curQueue.enQueue(10);
curQueue.enQueue(20);
curQueue.enQueue(30);
curQueue.clear();
assert(curQueue.isEmptyQueue());
}
void testFrontThrowsAnInvalidArgumentWhenQueueEmpty() {
const queue<int> curQueue;
bool wasException = false;
try {
curQueue.front();
} catch (const std::invalid_argument&) {
wasException = true;
}
assert(wasException);
}
void testDeQueueThrowsAnInvalidArgumentWhenQueueEmpty() {
queue<int> curQueue;
bool wasException = false;
try {
curQueue.deQueue();
} catch (const std::invalid_argument&) {
wasException = true;
}
assert(wasException);
}
int main() {
testConstructedQueueIsEmpty<int>();
testConstructedQueueIsEmpty<double>();
testConstructedQueueIsEmpty<std::vector<long double>>();
testEnQueue();
testDeQueue();
testQueueAfterClearIsEmpty();
testFrontThrowsAnInvalidArgumentWhenQueueEmpty();
testDeQueueThrowsAnInvalidArgumentWhenQueueEmpty();
std::cout << "All tests pass!\n";
return 0;
}
+203
View File
@@ -0,0 +1,203 @@
#include <cassert> /// for assert
#include <iostream> /// for std::cout
#include <stdexcept> /// std::invalid_argument
#include <vector> /// for std::vector
#include "./stack.hpp"
template <typename T>
void testConstructedStackIsEmpty() {
const stack<T> curStack;
assert(curStack.isEmptyStack());
}
void testPush() {
using valueType = int;
stack<valueType> curStack;
curStack.push(10);
curStack.push(20);
curStack.push(30);
curStack.push(40);
const auto expectedData = std::vector<valueType>({40, 30, 20, 10});
assert(curStack.toVector() == expectedData);
}
void testTop() {
using valueType = unsigned;
stack<valueType> curStack;
curStack.push(1);
curStack.push(2);
curStack.push(3);
curStack.push(4);
assert(curStack.top() == static_cast<valueType>(4));
}
void testPop() {
using valueType = int;
stack<valueType> curStack;
curStack.push(100);
curStack.push(200);
curStack.push(300);
assert(curStack.top() == static_cast<valueType>(300));
curStack.pop();
assert(curStack.top() == static_cast<valueType>(200));
curStack.pop();
assert(curStack.top() == static_cast<valueType>(100));
curStack.pop();
assert(curStack.isEmptyStack());
}
void testClear() {
stack<int> curStack;
curStack.push(1000);
curStack.push(2000);
curStack.clear();
assert(curStack.isEmptyStack());
}
void testCopyOfStackHasSameData() {
stack<int> stackA;
stackA.push(10);
stackA.push(200);
stackA.push(3000);
const auto stackB(stackA);
assert(stackA.toVector() == stackB.toVector());
}
void testPushingToCopyDoesNotChangeOriginal() {
using valueType = int;
stack<valueType> stackA;
stackA.push(10);
stackA.push(20);
stackA.push(30);
auto stackB(stackA);
stackB.push(40);
const auto expectedDataA = std::vector<valueType>({30, 20, 10});
const auto expectedDataB = std::vector<valueType>({40, 30, 20, 10});
assert(stackA.toVector() == expectedDataA);
assert(stackB.toVector() == expectedDataB);
}
void testPoppingFromCopyDoesNotChangeOriginal() {
using valueType = int;
stack<valueType> stackA;
stackA.push(10);
stackA.push(20);
stackA.push(30);
auto stackB(stackA);
stackB.pop();
const auto expectedDataA = std::vector<valueType>({30, 20, 10});
const auto expectedDataB = std::vector<valueType>({20, 10});
assert(stackA.toVector() == expectedDataA);
assert(stackB.toVector() == expectedDataB);
}
void testPushingToOrginalDoesNotChangeCopy() {
using valueType = int;
stack<valueType> stackA;
stackA.push(10);
stackA.push(20);
stackA.push(30);
const auto stackB(stackA);
stackA.push(40);
const auto expectedDataA = std::vector<valueType>({40, 30, 20, 10});
const auto expectedDataB = std::vector<valueType>({30, 20, 10});
assert(stackA.toVector() == expectedDataA);
assert(stackB.toVector() == expectedDataB);
}
void testPoppingFromOrginalDoesNotChangeCopy() {
using valueType = int;
stack<valueType> stackA;
stackA.push(10);
stackA.push(20);
stackA.push(30);
const auto stackB(stackA);
stackA.pop();
const auto expectedDataA = std::vector<valueType>({20, 10});
const auto expectedDataB = std::vector<valueType>({30, 20, 10});
assert(stackA.toVector() == expectedDataA);
assert(stackB.toVector() == expectedDataB);
}
void testAssign() {
using valueType = int;
stack<valueType> stackA;
stackA.push(10);
stackA.push(20);
stackA.push(30);
stack<valueType> stackB = stackA;
stackA.pop();
stackB.push(40);
const auto expectedDataA = std::vector<valueType>({20, 10});
const auto expectedDataB = std::vector<valueType>({40, 30, 20, 10});
assert(stackA.toVector() == expectedDataA);
assert(stackB.toVector() == expectedDataB);
stackB = stackA;
stackA.pop();
stackB.push(5);
stackB.push(6);
const auto otherExpectedDataA = std::vector<valueType>({10});
const auto otherExpectedDataB = std::vector<valueType>({6, 5, 20, 10});
assert(stackA.toVector() == otherExpectedDataA);
assert(stackB.toVector() == otherExpectedDataB);
}
void testTopThrowsAnInvalidArgumentWhenStackEmpty() {
const stack<long double> curStack;
bool wasException = false;
try {
curStack.top();
} catch (const std::invalid_argument&) {
wasException = true;
}
assert(wasException);
}
void testPopThrowsAnInvalidArgumentWhenStackEmpty() {
stack<bool> curStack;
bool wasException = false;
try {
curStack.pop();
} catch (const std::invalid_argument&) {
wasException = true;
}
assert(wasException);
}
int main() {
testConstructedStackIsEmpty<int>();
testConstructedStackIsEmpty<char>();
testPush();
testPop();
testClear();
testCopyOfStackHasSameData();
testPushingToCopyDoesNotChangeOriginal();
testPoppingFromCopyDoesNotChangeOriginal();
testPushingToOrginalDoesNotChangeCopy();
testPoppingFromOrginalDoesNotChangeCopy();
testAssign();
testTopThrowsAnInvalidArgumentWhenStackEmpty();
testPopThrowsAnInvalidArgumentWhenStackEmpty();
std::cout << "All tests pass!\n";
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* This program reads a data file consisting of students' GPAs
* followed by their names. The program then prints the highest
* GPA and the names of the students with the highest GPA.
* It uses stack to store the names of the students
* Run:
* make all
* ./main student.txt
************************************************************
* */
#include <cassert>
#include <cmath>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include "./stack.hpp"
int main(int argc, char* argv[]) {
double GPA = NAN;
double highestGPA = NAN;
std::string name;
assert(argc == 2);
std::ifstream infile;
stack<std::string> stk;
infile.open(argv[1]);
std::cout << std::fixed << std::showpoint;
std::cout << std::setprecision(2);
infile >> GPA >> name;
highestGPA = GPA;
while (infile) {
if (GPA > highestGPA) {
stk.clear();
stk.push(name);
highestGPA = GPA;
} else if (GPA == highestGPA) {
stk.push(name);
}
infile >> GPA >> name;
}
std::cout << "Highest GPA: " << highestGPA << std::endl;
std::cout << "Students the highest GPA are: " << std::endl;
while (!stk.isEmptyStack()) {
std::cout << stk.top() << std::endl;
stk.pop();
}
std::cout << std::endl;
return 0;
}
+258
View File
@@ -0,0 +1,258 @@
/**
* @file
* @brief A balanced binary search tree (BST) on the basis of binary search tree
* and heap: the [Treap](https://en.wikipedia.org/wiki/Treap) algorithm
* implementation
*
* @details
* Implementation of the treap data structre
*
* Support operations including insert, erase, and query (the rank of specified
* element or the element ranked x) as the same as BST
*
* But these operations take O(log N) time, since treap keeps property of heap
* using rotate operation, and the desired depth of the tree is O(log N).
* There's very little chance that it will degenerate into a chain like BST
*
* @author [Kairao ZHENG](https://github.com/fgmn)
*/
#include <array> /// For array
#include <cassert> /// For assert
#include <cstdint>
#include <iostream> /// For IO operations
/**
* @namespace
* @brief Data Structures
*/
namespace data_structures {
/**
* @namespace
* @brief Functions for the [Treap](https://en.wikipedia.org/wiki/Treap)
* algorithm implementation
*/
namespace treap {
const int maxNode = 1e5 + 5; ///< maximum number of nodes
/**
* @brief Struct representation of the treap
*/
struct Treap {
int root = 0; ///< root of the treap
int treapCnt = 0; ///< Total number of current nodes in the treap
std::array<int, maxNode> key = {}; ///< Node identifier
std::array<int, maxNode> priority = {}; ///< Random priority
std::array<std::array<int, 2>, maxNode> childs = {
{}}; ///< [i][0] represents the
///< left child of node i, and
///[i][1] represents the right
std::array<int, maxNode> cnt =
{}; ///< Maintains the subtree size for ranking query
std::array<int, maxNode> size = {}; ///< The number of copies per node
/**
* @brief Initialization
*/
Treap() : treapCnt(1) {
priority[0] = INT32_MAX;
size[0] = 0;
}
/**
* @brief Update the subtree size of the node
* @param x The node to update
*/
void update(int x) {
size[x] = size[childs[x][0]] + cnt[x] + size[childs[x][1]];
}
/**
* @brief Rotate without breaking the property of BST
* @param x The node to rotate
* @param t 0 represent left hand, while 1 right hand
*/
void rotate(int &x, int t) {
int y = childs[x][t];
childs[x][t] = childs[y][1 - t];
childs[y][1 - t] = x;
// The rotation will only change itself and its son nodes
update(x);
update(y);
x = y;
}
/**
* @brief Insert a value into the specified subtree (internal method)
* @param x Insert into the subtree of node x (Usually x=root)
* @param k Key to insert
*/
void _insert(int &x, int k) {
if (x) {
if (key[x] == k) {
cnt[x]++;
} // If the node already exists, the number of copies is ++
else {
int t = (key[x] < k); // Insert according to BST properties
_insert(childs[x][t], k);
// After insertion, the heap properties are retained by rotation
if (priority[childs[x][t]] < priority[x]) {
rotate(x, t);
}
}
} else { // Create a new node
x = treapCnt++;
key[x] = k;
cnt[x] = 1;
priority[x] = rand(); // Random priority
childs[x][0] = childs[x][1] = 0;
}
update(x);
}
/**
* @brief Erase a value from the specified subtree (internal method)
* @param x Erase from the subtree of node x (Usually x=root)
* @param k Key to erase
*/
void _erase(int &x, int k) {
if (key[x] == k) {
if (cnt[x] > 1) {
cnt[x]--;
} // If the node has more than one copy, the number of copies --
else {
if (childs[x][0] == 0 && childs[x][1] == 0) {
x = 0;
return;
} // If there are no children, delete and return
// Otherwise, we need to rotate the sons and delete them
// recursively
int t = (priority[childs[x][0]] > priority[childs[x][1]]);
rotate(x, t);
_erase(x, k);
}
} else { // Find the target value based on BST properties
_erase(childs[x][key[x] < k], k);
}
update(x);
}
/**
* @brief Find the KTH largest value (internal method)
* @param x Query the subtree of node x (Usually x=root)
* @param k The queried rank
* @return The element ranked number k
*/
int _get_k_th(int &x, int k) {
if (k <= size[childs[x][0]]) {
return _get_k_th(childs[x][0], k);
}
k -= size[childs[x][0]] + cnt[x];
if (k <= 0) {
return key[x];
}
return _get_k_th(childs[x][1], k);
}
/**
* @brief Query the rank of specified element (internal method)
* @param x Query the subtree of node x (Usually x=root)
* @param k The queried element
* @return The rank of element k
*/
int _get_rank(int x, int k) {
if (!x) {
return 0;
}
if (k == key[x]) {
return size[childs[x][0]] + 1;
} else if (k < key[x]) {
return _get_rank(childs[x][0], k);
} else {
return size[childs[x][0]] + cnt[x] + _get_rank(childs[x][1], k);
}
}
/**
* @brief Get the predecessor node of element k
* @param k The queried element
* @return The predecessor
*/
int get_predecessor(int k) {
int x = root, pre = -1;
while (x) {
if (key[x] < k) {
pre = key[x], x = childs[x][1];
} else {
x = childs[x][0];
}
}
return pre;
}
/**
* @brief Get the successor node of element k
* @param k The queried element
* @return The successor
*/
int get_next(int k) {
int x = root, next = -1;
while (x) {
if (key[x] > k) {
next = key[x], x = childs[x][0];
} else {
x = childs[x][1];
}
}
return next;
}
/**
* @brief Insert element (External method)
* @param k Key to insert
*/
void insert(int k) { _insert(root, k); }
/**
* @brief Erase element (External method)
* @param k Key to erase
*/
void erase(int k) { _erase(root, k); }
/**
* @brief Get the KTH largest value (External method)
* @param k The queried rank
* @return The element ranked number x
*/
int get_k_th(int k) { return _get_k_th(root, k); }
/**
* @brief Get the rank of specified element (External method)
* @param k The queried element
* @return The rank of element k
*/
int get_rank(int k) { return _get_rank(root, k); }
};
} // namespace treap
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
data_structures::treap::Treap mTreap; ///< Treap object instance
mTreap.insert(1);
mTreap.insert(2);
mTreap.insert(3);
assert(mTreap.get_k_th(2) == 2);
mTreap.insert(4);
mTreap.insert(5);
mTreap.insert(6);
assert(mTreap.get_next(4) == 5);
mTreap.insert(7);
assert(mTreap.get_predecessor(7) == 6);
mTreap.erase(4);
assert(mTreap.get_k_th(4) == 5);
assert(mTreap.get_rank(5) == 4);
mTreap.insert(10);
assert(mTreap.get_rank(10) == 7);
assert(mTreap.get_predecessor(10) == 7);
std::cout << "All tests have successfully passed!\n";
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
return 0;
}
+119
View File
@@ -0,0 +1,119 @@
#include <iostream>
#include <list>
using namespace std;
struct node {
int val;
node *left;
node *right;
};
void CreateTree(node *curr, node *n, int x, char pos) {
if (n != NULL) {
char ch;
cout << "\nLeft or Right of " << n->val << " : ";
cin >> ch;
if (ch == 'l')
CreateTree(n, n->left, x, ch);
else if (ch == 'r')
CreateTree(n, n->right, x, ch);
} else {
node *t = new node;
t->val = x;
t->left = NULL;
t->right = NULL;
if (pos == 'l') {
curr->left = t;
} else if (pos == 'r') {
curr->right = t;
}
}
}
void BFT(node *n) {
list<node *> queue;
queue.push_back(n);
while (!queue.empty()) {
n = queue.front();
cout << n->val << " ";
queue.pop_front();
if (n->left != NULL)
queue.push_back(n->left);
if (n->right != NULL)
queue.push_back(n->right);
}
}
void Pre(node *n) {
if (n != NULL) {
cout << n->val << " ";
Pre(n->left);
Pre(n->right);
}
}
void In(node *n) {
if (n != NULL) {
In(n->left);
cout << n->val << " ";
In(n->right);
}
}
void Post(node *n) {
if (n != NULL) {
Post(n->left);
Post(n->right);
cout << n->val << " ";
}
}
int main() {
int value;
int ch;
node *root = new node;
cout << "\nEnter the value of root node :";
cin >> value;
root->val = value;
root->left = NULL;
root->right = NULL;
do {
cout << "\n1. Insert";
cout << "\n2. Breadth First";
cout << "\n3. Preorder Depth First";
cout << "\n4. Inorder Depth First";
cout << "\n5. Postorder Depth First";
cout << "\nEnter Your Choice : ";
cin >> ch;
switch (ch) {
case 1:
int x;
char pos;
cout << "\nEnter the value to be Inserted : ";
cin >> x;
cout << "\nLeft or Right of Root : ";
cin >> pos;
if (pos == 'l')
CreateTree(root, root->left, x, pos);
else if (pos == 'r')
CreateTree(root, root->right, x, pos);
break;
case 2:
BFT(root);
break;
case 3:
Pre(root);
break;
case 4:
In(root);
break;
case 5:
Post(root);
break;
}
} while (ch != 0);
}
File diff suppressed because it is too large Load Diff
+168
View File
@@ -0,0 +1,168 @@
/**
* @file
*
* @author Anmol3299
* \brief A basic implementation of trie class to store only lower-case strings.
*/
#include <iostream> // for io operations
#include <memory> // for std::shared_ptr<>
#include <string> // for std::string class
/**
* A basic implementation of trie class to store only lower-case strings.
* You can extend the implementation to all the ASCII characters by changing the
* value of @ ALPHABETS to 128.
*/
class Trie {
private:
static constexpr size_t ALPHABETS = 26;
/**
* Structure of trie node.
* This struct doesn't need a constructor as we are initializing using
* intializer list which is more efficient than if we had done so with
* constructor.
*/
struct TrieNode {
// An array of pointers of size 26 which tells if a character of word is
// present or not.
std::shared_ptr<TrieNode> character[ALPHABETS]{nullptr};
bool isEndOfWord{false};
};
/**
* Function to check if a node has some children which can form words.
* @param node whose character array of pointers need to be checked for
* children.
* @return `true` if a child is found
* @return `false` if a child is not found
*/
inline static bool hasChildren(std::shared_ptr<TrieNode> node) {
for (size_t i = 0; i < ALPHABETS; i++) {
if (node->character[i]) {
return true;
}
}
return false;
}
/**
* A recursive helper function to remove a word from the trie. First, it
* recursively traverses to the location of last character of word in the
* trie. However, if the word is not found, the function returns a runtime
* error. Upon successfully reaching the last character of word in trie, if
* sets the isEndOfWord to false and deletes the node if and only if it has
* no children, else it returns the current node.
* @param word is the string which needs to be removed from trie.
* @param curr is the current node we are at.
* @param index is the index of the @word we are at.
* @return if current node has childern, it returns @ curr, else it returns
* nullptr.
* @throw a runtime error in case @ word is not found in the trie.
*/
std::shared_ptr<TrieNode> removeWordHelper(const std::string& word,
std::shared_ptr<TrieNode> curr,
size_t index) {
if (word.size() == index) {
if (curr->isEndOfWord) {
curr->isEndOfWord = false;
}
if (hasChildren(curr)) {
return curr;
}
return nullptr;
}
size_t idx = word[index] - 'a';
// Throw a runtime error in case the user enters a word which is not
// present in the trie.
if (!curr->character[idx]) {
throw std::runtime_error(std::move(std::string("Word not found.")));
}
curr->character[idx] =
removeWordHelper(word, curr->character[idx], index + 1);
// This if condition checks if the node has some childern.
// The 1st if check, i.e. (curr->character[idx]) is checked specifically
// because if the older string is a prefix of some other string, then,
// there would be no need to check all 26 characters. Example- str1 =
// abbey, str2 = abbex and we want to delete string "abbey", then in
// this case, there would be no need to check all characters for the
// chars a,b,b.
if (curr->character[idx] || hasChildren(curr)) {
return curr;
}
return nullptr;
}
public:
/// constructor to initialise the root of the trie.
Trie() : m_root(std::make_shared<TrieNode>()) {}
/**
* Insert a word into the trie.
* @param word which needs to be inserted into the string.
*/
void insert(const std::string& word) {
auto curr = m_root;
for (char ch : word) {
size_t index = ch - 'a';
// if a node for current word is not already present in trie, create
// a new node for it.
if (!curr->character[index]) {
curr->character[index] = std::make_shared<TrieNode>();
}
curr = curr->character[index];
}
curr->isEndOfWord = true;
}
/**
* Search if a word is present in trie or not.
* @param word which is needed to be searched in the trie.
* @return True if the word is found in trie and isEndOfWord is set to true.
* @return False if word is not found in trie or isEndOfWord is set to
* false.
*/
bool search(const std::string& word) {
auto curr = m_root;
for (char ch : word) {
size_t index = ch - 'a';
// if any node for a character is not found, then return that the
// word cannot be formed.
if (!curr->character[index]) {
return false;
}
curr = curr->character[index];
}
return curr->isEndOfWord;
}
// Function to remove the word which calls the helper function.
void removeWord(const std::string& word) {
m_root = removeWordHelper(word, m_root, 0);
}
private:
// data member to store the root of the trie.
std::shared_ptr<TrieNode> m_root;
};
/**
* Main function
*/
int main() {
Trie trie;
trie.insert("hel");
trie.insert("hello");
trie.removeWord("hel");
std::cout << trie.search("hello") << '\n';
return 0;
}
+209
View File
@@ -0,0 +1,209 @@
/**
* @file
* @author [@Arctic2333](https://github.com/Arctic2333)
* @author [Krishna Vedala](https://github.com/kvedala)
* @brief Implementation of [Trie](https://en.wikipedia.org/wiki/Trie) data
* structure for English alphabets in small characters.
* @note the function ::data_structure::trie::deleteString might be erroneous
* @see trie_modern.cpp
*/
#include <array>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <memory>
#include <string>
/** \namespace data_structures
* \brief Data-structure algorithms
*/
namespace data_structures {
/**
* @brief [Trie](https://en.wikipedia.org/wiki/Trie) implementation for
* small-case English alphabets `a-z`
*/
class trie {
private:
static constexpr uint8_t NUM_CHARS = 26; ///< Number of alphabets
/** @brief Recursive tree nodes as an array of shared-pointers */
std::array<std::shared_ptr<trie>, NUM_CHARS << 1> arr;
bool isEndofWord = false; ///< identifier if a node is terminal node
/**
* @brief Convert a character to integer for indexing
*
* @param ch character to index
* @return unsigned integer index
*/
uint8_t char_to_int(const char& ch) const {
if (ch >= 'A' && ch <= 'Z') {
return ch - 'A';
} else if (ch >= 'a' && ch <= 'z') {
return ch - 'a' + NUM_CHARS;
}
std::cerr << "Invalid character present. Exiting...";
std::exit(EXIT_FAILURE);
return 0;
}
/** search a string exists inside a given root trie
* @param str string to search for
* @param index start index to search from
* @returns `true` if found
* @returns `false` if not found
*/
bool search(const std::shared_ptr<trie>& root, const std::string& str,
int index) {
if (index == str.length()) {
if (!root->isEndofWord) {
return false;
}
return true;
}
int j = char_to_int(str[index]);
if (!root->arr[j]) {
return false;
}
return search(root->arr[j], str, index + 1);
}
public:
trie() = default; ///< Class default constructor
/** insert string into the trie
* @param str String to insert in the tree
*/
void insert(const std::string& str) {
std::shared_ptr<trie> root(nullptr);
for (const char& ch : str) {
int j = char_to_int(ch);
if (root) {
if (root->arr[j]) {
root = root->arr[j];
} else {
std::shared_ptr<trie> temp(new trie());
root->arr[j] = temp;
root = temp;
}
} else if (arr[j]) {
root = arr[j];
} else {
std::shared_ptr<trie> temp(new trie());
arr[j] = temp;
root = temp;
}
}
root->isEndofWord = true;
}
/** search a string exists inside the trie
* @param str string to search for
* @param index start index to search from
* @returns `true` if found
* @returns `false` if not found
*/
bool search(const std::string& str, int index) {
if (index == str.length()) {
if (!isEndofWord) {
return false;
}
return true;
}
int j = char_to_int(str[index]);
if (!arr[j]) {
return false;
}
return search(arr[j], str, index + 1);
}
/**
* removes the string if it is not a prefix of any other
* string, if it is then just sets the ::data_structure::trie::isEndofWord
* to false, else removes the given string
* @note the function ::data_structure::trie::deleteString might be
* erroneous
* @todo review the function ::data_structure::trie::deleteString and the
* commented lines
* @param str string to remove
* @param index index to remove from
* @returns `true` if successful
* @returns `false` if unsuccessful
*/
bool deleteString(const std::string& str, int index) {
if (index == str.length()) {
if (!isEndofWord) {
return false;
}
isEndofWord = false;
// following lines - possible source of error?
// for (int i = 0; i < NUM_CHARS; i++)
// if (!arr[i])
// return false;
return true;
}
int j = char_to_int(str[index]);
if (!arr[j]) {
return false;
}
bool var = deleteString(str, index + 1);
if (var) {
arr[j].reset();
if (isEndofWord) {
return false;
} else {
int i = 0;
for (i = 0; i < NUM_CHARS; i++) {
if (arr[i]) {
return false;
}
}
return true;
}
}
/* should not return here */
std::cout << __func__ << ":" << __LINE__
<< "Should not reach this line\n";
return false;
}
};
} // namespace data_structures
/**
* @brief Testing function
* @returns void
*/
static void test() {
data_structures::trie root;
root.insert("Hello");
root.insert("World");
assert(!root.search("hello", 0));
std::cout << "hello - " << root.search("hello", 0) << "\n";
assert(root.search("Hello", 0));
std::cout << "Hello - " << root.search("Hello", 0) << "\n";
assert(!root.search("Word", 0));
std::cout << "Word - " << root.search("Word", 0) << "\n";
assert(root.search("World", 0));
std::cout << "World - " << root.search("World", 0) << "\n";
// Following lines of code give erroneous output
// root.deleteString("hello", 0);
// assert(!root.search("hello", 0));
// std::cout << "hello - " << root.search("world", 0) << "\n";
}
/**
* @brief Main function
* @return 0 on exit
*/
int main() {
test();
return 0;
}
+345
View File
@@ -0,0 +1,345 @@
/**
* @file
* @author [Venkata Bharath](https://github.com/bharath000)
* @brief Implementation of [Trie](https://en.wikipedia.org/wiki/Trie) data
* structure using HashMap for different characters and method for predicting
* words based on prefix.
* @details The Trie data structure is implemented using unordered map to use
* memory optimally, predict_words method is developed to recommend words based
* on a given prefix along with other methods insert, delete, search, startwith
* in trie.
* @see trie_modern.cpp for difference
*/
#include <cassert> /// for assert
#include <iostream> /// for IO operations
#include <memory> /// for std::shared_ptr
#include <stack> /// for std::stack
#include <unordered_map> /// for std::unordered_map
#include <vector> /// for std::vector
/**
* @namespace data_structures
* @brief Data structures algorithms
*/
namespace data_structures {
/**
* @namespace trie_using_hashmap
* @brief Functions for [Trie](https://en.wikipedia.org/wiki/Trie) data
* structure using hashmap implementation
*/
namespace trie_using_hashmap {
/**
* @brief Trie class, implementation of trie using hashmap in each trie node
* for all the characters of char16_t(UTF-16)type with methods to insert,
* delete, search, start with and to recommend words based on a given
* prefix.
*/
class Trie {
private:
/**
* @brief struct representing a trie node.
*/
struct Node {
std::unordered_map<char16_t, std::shared_ptr<Node>>
children; ///< unordered map with key type char16_t and value is a
///< shared pointer type of Node
bool word_end = false; ///< boolean variable to represent the node end
};
std::shared_ptr<Node> root_node =
std::make_shared<Node>(); ///< declaring root node of trie
public:
///< Constructor
Trie() = default;
/**
* @brief insert the string into the trie
* @param word string to insert in the trie
*/
void insert(const std::string& word) {
std::shared_ptr<Node> curr = root_node;
for (char ch : word) {
if (curr->children.find(ch) == curr->children.end()) {
curr->children[ch] = std::make_shared<Node>();
}
curr = curr->children[ch];
}
if (!curr->word_end && curr != root_node) {
curr->word_end = true;
}
}
/**
* @brief search a word/string inside the trie
* @param word string to search for
* @returns `true` if found
* @returns `false` if not found
*/
bool search(const std::string& word) {
std::shared_ptr<Node> curr = root_node;
for (char ch : word) {
if (curr->children.find(ch) == curr->children.end()) {
return false;
}
curr = curr->children[ch];
if (!curr) {
return false;
}
}
if (curr->word_end) {
return true;
} else {
return false;
}
}
/**
* @brief search a word/string that starts with a given prefix
* @param prefix string to search for
* @returns `true` if found
* @returns `false` if not found
*/
bool startwith(const std::string& prefix) {
std::shared_ptr<Node> curr = root_node;
for (char ch : prefix) {
if (curr->children.find(ch) == curr->children.end()) {
return false;
}
curr = curr->children[ch];
}
return true;
}
/**
* @brief delete a word/string from a trie
* @param word string to delete from trie
*/
void delete_word(std::string word) {
std::shared_ptr<Node> curr = root_node;
std::stack<std::shared_ptr<Node>> nodes;
int cnt = 0;
for (char ch : word) {
if (curr->children.find(ch) == curr->children.end()) {
return;
}
if (curr->word_end) {
cnt++;
}
nodes.push(curr->children[ch]);
curr = curr->children[ch];
}
// Delete only when it's a word, and it has children after
// or prefix in the line
if (nodes.top()->word_end) {
nodes.top()->word_end = false;
}
// Delete only when it has no children after
// and also no prefix in the line
while (!(nodes.top()->word_end) && nodes.top()->children.empty()) {
nodes.pop();
nodes.top()->children.erase(word.back());
word.pop_back();
}
}
/**
* @brief helper function to predict/recommend words that starts with a
* given prefix from the end of prefix's node iterate through all the child
* nodes by recursively appending all the possible words below the trie
* @param prefix string to recommend the words
* @param element node at the end of the given prefix
* @param results list to store the all possible words
* @returns list of recommended words
*/
std::vector<std::string> get_all_words(std::vector<std::string> results,
const std::shared_ptr<Node>& element,
std::string prefix) {
if (element->word_end) {
results.push_back(prefix);
}
if (element->children.empty()) {
return results;
}
for (auto const& x : element->children) {
std::string key = "";
key = x.first;
prefix += key;
results =
get_all_words(results, element->children[x.first], prefix);
prefix.pop_back();
}
return results;
}
/**
* @brief predict/recommend a word that starts with a given prefix
* @param prefix string to search for
* @returns list of recommended words
*/
std::vector<std::string> predict_words(const std::string& prefix) {
std::vector<std::string> result;
std::shared_ptr<Node> curr = root_node;
// traversing until the end of the given prefix in trie
for (char ch : prefix) {
if (curr->children.find(ch) == curr->children.end()) {
return result;
}
curr = curr->children[ch];
}
// if the given prefix is the only word without children
if (curr->word_end && curr->children.empty()) {
result.push_back(prefix);
return result;
}
result = get_all_words(
result, curr,
prefix); ///< iteratively and recursively get the recommended words
return result;
}
};
} // namespace trie_using_hashmap
} // namespace data_structures
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
data_structures::trie_using_hashmap::Trie obj;
// Inserting data into trie using the insert
// method and testing it with search method
obj.insert("app");
obj.insert("abscond");
obj.insert("about");
obj.insert("apps");
obj.insert("apen");
obj.insert("apples");
obj.insert("apple");
obj.insert("approach");
obj.insert("bus");
obj.insert("buses");
obj.insert("Apple");
obj.insert("Bounce");
assert(!obj.search("appy"));
std::cout << "appy is not a word in trie" << std::endl;
assert(!obj.search("car"));
std::cout << "car is not a word in trie" << std::endl;
assert(obj.search("app"));
assert(obj.search("apple"));
assert(obj.search("apples"));
assert(obj.search("apps"));
assert(obj.search("apen"));
assert(obj.search("approach"));
assert(obj.search("about"));
assert(obj.search("abscond"));
assert(obj.search("bus"));
assert(obj.search("buses"));
assert(obj.search("Bounce"));
assert(obj.search("Apple"));
std::cout << "All the Inserted words are present in the trie" << std::endl;
// test for startwith prefix method
assert(!obj.startwith("approachs"));
assert(obj.startwith("approach"));
assert(obj.startwith("about"));
assert(!obj.startwith("appy"));
assert(obj.startwith("abscond"));
assert(obj.startwith("bus"));
assert(obj.startwith("buses"));
assert(obj.startwith("Bounce"));
assert(obj.startwith("Apple"));
assert(obj.startwith("abs"));
assert(obj.startwith("b"));
assert(obj.startwith("bus"));
assert(obj.startwith("Bo"));
assert(obj.startwith("A"));
assert(!obj.startwith("Ca"));
assert(!obj.startwith("C"));
std::cout << "All the tests passed for startwith method" << std::endl;
// test for predict_words/recommendation of words based on a given prefix
std::vector<std::string> pred_words = obj.predict_words("a");
for (const std::string& str : obj.predict_words("a")) {
std::cout << str << std::endl;
}
assert(pred_words.size() == 8);
std::cout << "Returned all words that start with prefix a " << std::endl;
pred_words = obj.predict_words("app");
for (const std::string& str : pred_words) {
std::cout << str << std::endl;
}
assert(pred_words.size() == 5);
std::cout << "Returned all words that start with prefix app " << std::endl;
pred_words = obj.predict_words("A");
for (const std::string& str : pred_words) {
std::cout << str << std::endl;
}
assert(pred_words.size() == 1);
std::cout << "Returned all words that start with prefix A " << std::endl;
pred_words = obj.predict_words("bu");
for (const std::string& str : pred_words) {
std::cout << str << std::endl;
}
assert(pred_words.size() == 2);
std::cout << "Returned all words that start with prefix bu " << std::endl;
// tests for delete method
obj.delete_word("app");
assert(!obj.search("app"));
std::cout << "word app is deleted sucessful" << std::endl;
pred_words = obj.predict_words("app");
for (const std::string& str : pred_words) {
std::cout << str << std::endl;
}
assert(pred_words.size() == 4);
std::cout << "app is deleted sucessful" << std::endl;
// test case for Chinese language
obj.insert("苹果");
assert(obj.startwith(""));
pred_words = obj.predict_words("h");
assert(pred_words.size() == 0);
std::cout << "No word starts with prefix h in trie" << std::endl;
std::cout << "All tests passed" << std::endl;
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementaions
return 0;
}