Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AVL Tree and Knight's Tour #462

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ add_executable(n_queens
test/algorithm/backtracking/n_queens.cpp)
target_link_libraries(n_queens test_runner)

# Knight's Tour
add_executable(knights_tour
test/algorithm/backtracking/knights_tour.cpp)
target_link_libraries(knights_tour test_runner)


# -------------------
# Dynamic programming
# -------------------
Expand Down Expand Up @@ -226,3 +232,8 @@ add_executable(fenwick_tree
test/data_structure/tree/fenwick_tree.cpp)
target_link_libraries(fenwick_tree test_runner)

# AVL tree
add_executable(avl_tree
test/data_structure/tree/avl_tree.cpp)
target_link_libraries(avl_tree test_runner)

141 changes: 141 additions & 0 deletions cpp/include/algorithm/backtracking/knights_tour.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Knight's Tour Problem
----------------
Find a sequence of moves for a knight on a chessboard
such that the knight visits every square exactly once.

Time complexity
---------------
O(8^(N^2)), where N is the length of the chess board

Space complexity
----------------
O(N^2), where N is the length of the chess board.
*/

#ifndef KNIGHTS_TOUR_HPP
#define KNIGHTS_TOUR_HPP

#include <iostream>
#include <vector>

typedef std::vector<std::vector<int>> Board;

const int MAX_KNIGHT_MOVES = 8;
const int moves_x[MAX_KNIGHT_MOVES] = {2, 1, -1, -2, -2, -1, 1, 2};
const int moves_y[MAX_KNIGHT_MOVES] = {1, 2, 2, 1, -1, -2, -2, -1};

/*
KnightsTourSolver
-----------------
Wrapper class for solving the Knight's Tour problem.
*/

class KnightsTourSolver {
size_t N;
bool is_solved;
Board solution;

public:
KnightsTourSolver(const size_t);
bool has_solution() const;
Board get_solution() const;
void print_solution() const;
void demonstrate_solution(); // Added for direct demonstration

private:
void solve();
bool find_tour(Board&, int, int, int);
bool is_safe(const Board&, int, int) const;
};

/*
Constructor
-----------
*/

KnightsTourSolver::KnightsTourSolver(const size_t board_size) {
N = board_size;
solution.resize(N, std::vector<int>(N, -1));
is_solved = false;
solve();
}

/*
Public interface
==========================================================================
*/

bool KnightsTourSolver::has_solution() const {
return is_solved;
}

Board KnightsTourSolver::get_solution() const {
return solution;
}

void KnightsTourSolver::print_solution() const {
for (const auto& row : solution) {
for (int num : row) {
std::cout.width(4);
std::cout << num << " ";
}
std::cout << "\n";
}
}

void KnightsTourSolver::demonstrate_solution() {
if (has_solution()) {
std::cout << "A solution exists for the " << N << "x" << N << " board:\n";
print_solution();
} else {
std::cout << "No solution exists for the " << N << "x" << N << " board.\n";
}
}

/*
Private methods
==========================================================================
*/

void KnightsTourSolver::solve() {
solution[0][0] = 0; // Start from the top-left corner
if (find_tour(solution, 0, 0, 1)) {
is_solved = true;
}
}

bool KnightsTourSolver::find_tour(Board& board, int x, int y, int move_i) {
if (move_i == N * N)
return true;

for (int k = 0; k < MAX_KNIGHT_MOVES; k++) {
int next_x = x + moves_x[k];
int next_y = y + moves_y[k];
if (is_safe(board, next_x, next_y)) {
board[next_x][next_y] = move_i;
if (find_tour(board, next_x, next_y, move_i + 1))
return true;
board[next_x][next_y] = -1; // backtrack
}
}

return false;
}

bool KnightsTourSolver::is_safe(const Board& board, int x, int y) const {
return x >= 0 && x < N && y >= 0 && y < N && board[x][y] == -1;
}

/*
Test or Demonstrate the Knight's Tour solution without a main function.
*/

int main() {
int board_size = 8; // Standard chessboard size
KnightsTourSolver solver(board_size);
solver.demonstrate_solution();
return 0;
}

#endif // KNIGHTS_TOUR_HPP
231 changes: 231 additions & 0 deletions cpp/include/data_structure/tree/avl_tree.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
/*
AVL Tree
------------------
An AVL tree is a type of binary search tree that automatically keeps itself
balanced. In an AVL tree, the height difference between the left and right
subtrees of any node (known as the balance factor) is at most one. This balance
is maintained through rotations, which are structural changes to the tree
that help in preserving its height properties. Operations like insertion, deletion,
and search can be performed in O(log n) time, ensuring efficient data management.
*/

#ifndef AVL_TREE_HPP
#define AVL_TREE_HPP

#include <algorithm>
#include <vector>
#include <stack>

using namespace std;

const int INF = INT_MAX;

struct Node {
int value;
int height;
Node* left_child;
Node* right_child;
};

class AVLTree {
private:
Node* root;

Node* get_node(int value);
int height(Node* node);
int balance_factor(Node* node);
Node* right_rotate(Node* y);
Node* left_rotate(Node* x);
Node* insert_helper(Node* node, int value);
Node* remove_helper(Node* node, int value);
void inorder_traversal_helper(Node* node, vector<int>& values);

public:
AVLTree();
bool insert(int value);
bool remove(int value);
bool search(int value);
vector<int> inorder_traversal();
};

Node* AVLTree::get_node(int value) {
Node* newNode = new Node();
newNode->value = value;
newNode->height = 1;
newNode->left_child = newNode->right_child = nullptr;
return newNode;
}

int AVLTree::height(Node* node) {
if (node == nullptr) return 0;
return node->height;
}

int AVLTree::balance_factor(Node* node) {
if (node == nullptr) return 0;
return height(node->left_child) - height(node->right_child);
}

Node* AVLTree::right_rotate(Node* y) {
Node* x = y->left_child;
Node* T2 = x->right_child;

// Perform rotation
x->right_child = y;
y->left_child = T2;

// Update heights
y->height = 1 + max(height(y->left_child), height(y->right_child));
x->height = 1 + max(height(x->left_child), height(x->right_child));

return x;
}

Node* AVLTree::left_rotate(Node* x) {
Node* y = x->right_child;
Node* T2 = y->left_child;

// Perform rotation
y->left_child = x;
x->right_child = T2;

// Update heights
x->height = 1 + max(height(x->left_child), height(x->right_child));
y->height = 1 + max(height(y->left_child), height(y->right_child));

return y;
}

Node* AVLTree::insert_helper(Node* node, int value) {
if (node == nullptr) return get_node(value);

if (value < node->value)
node->left_child = insert_helper(node->left_child, value);
else if (value > node->value)
node->right_child = insert_helper(node->right_child, value);
else
return node; // Duplicate values not allowed

// Update height of this node
node->height = 1 + max(height(node->left_child), height(node->right_child));

// Get the balance factor
int balance = balance_factor(node);

// Left Left Case
if (balance > 1 && value < node->left_child->value)
return right_rotate(node);

// Right Right Case
if (balance < -1 && value > node->right_child->value)
return left_rotate(node);

// Left Right Case
if (balance > 1 && value > node->left_child->value) {
node->left_child = left_rotate(node->left_child);
return right_rotate(node);
}

// Right Left Case
if (balance < -1 && value < node->right_child->value) {
node->right_child = right_rotate(node->right_child);
return left_rotate(node);
}

return node;
}

Node* AVLTree::remove_helper(Node* node, int value) {
if (node == nullptr) return node;

if (value < node->value)
node->left_child = remove_helper(node->left_child, value);
else if (value > node->value)
node->right_child = remove_helper(node->right_child, value);
else {
if (node->left_child == nullptr || node->right_child == nullptr) {
Node* temp = node->left_child ? node->left_child : node->right_child;

if (temp == nullptr) {
temp = node;
node = nullptr;
} else {
*node = *temp;
}

delete temp;
} else {
Node* temp = node->right_child;
while (temp->left_child != nullptr) temp = temp->left_child;
node->value = temp->value;
node->right_child = remove_helper(node->right_child, temp->value);
}
}

if (node == nullptr) return node;

node->height = 1 + max(height(node->left_child), height(node->right_child));

int balance = balance_factor(node);

if (balance > 1 && balance_factor(node->left_child) >= 0)
return right_rotate(node);

if (balance > 1 && balance_factor(node->left_child) < 0) {
node->left_child = left_rotate(node->left_child);
return right_rotate(node);
}

if (balance < -1 && balance_factor(node->right_child) <= 0)
return left_rotate(node);

if (balance < -1 && balance_factor(node->right_child) > 0) {
node->right_child = right_rotate(node->right_child);
return left_rotate(node);
}

return node;
}

AVLTree::AVLTree() {
root = nullptr;
}

bool AVLTree::insert(int value) {
root = insert_helper(root, value);
return true;
}

bool AVLTree::remove(int value) {
if (!search(value)) return false;
root = remove_helper(root, value);
return true;
}

bool AVLTree::search(int value) {
Node* current = root;
while (current != nullptr) {
if (value < current->value)
current = current->left_child;
else if (value > current->value)
current = current->right_child;
else
return true; // Found
}
return false; // Not found
}

void AVLTree::inorder_traversal_helper(Node* node, vector<int>& values) {
if (node == nullptr) return;
inorder_traversal_helper(node->left_child, values);
values.push_back(node->value);
inorder_traversal_helper(node->right_child, values);
}

vector<int> AVLTree::inorder_traversal() {
vector<int> values;
inorder_traversal_helper(root, values);
return values;
}

#endif
Loading