diff --git a/Stacks&Queues/CMakeLists.txt b/Stacks&Queues/CMakeLists.txt new file mode 100644 index 0000000..0905ef2 --- /dev/null +++ b/Stacks&Queues/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 4.0) +project(Stacks_Queues) + +set(CMAKE_CXX_STANDARD 20) + +add_executable(Stacks_Queues main.cpp + TStack.cpp + TStack.h + TQueue.cpp + TQueue.h + FUtils.h) diff --git a/Stacks&Queues/FUtils.h b/Stacks&Queues/FUtils.h new file mode 100644 index 0000000..b442cdf --- /dev/null +++ b/Stacks&Queues/FUtils.h @@ -0,0 +1,183 @@ +#ifndef STACKS_QUEUES_FUTILS_H +#define STACKS_QUEUES_FUTILS_H + +#include +#include +#include +#include "TQueue.h" +#include "TStack.h" + +constexpr int GRID_ROWS = 100; +constexpr int GRID_COLS = 100; + + +// Stack is perfect here because of the structure and behaviour of stacks - LIFO +// When we push the string in it will send the first char to the bottom of the stack +// When we push the string back out it will pop the last char first, then the second to last, then third and so on +// Time and space complexity is O(n) - each char pushed and popped exactly once and +// helper string "reverse clone" is needed for output +inline std::string ReverseString(const std::string& input) +{ + if (input.size() > MAX_SIZE) + throw std::overflow_error("Input longer than MAX_SIZE"); + TStack s; + for (char c : input) + s.Push(c); + std::string output; + output.reserve(input.size()); + while (!s.IsEmpty()) + { + output.push_back(s.Pop()); + } + return output; +} + +// Time = O(n) - push 2 .. n once and pop each once +// Space = O(1) - fixed size array inside TStack +inline long long Factorial(const int base) +{ + if (base < 0) + throw std::invalid_argument("n must be >= 0"); + if (base == 0 || base == 1) + return 1; + if (base > MAX_SIZE) + throw std::overflow_error("n exceeds MAX_SIZE"); + TStack s; + for (int i = 2; i <= base; ++i) + s.Push(i); + long long result = 1; + while (!s.IsEmpty()) + result *= s.Pop(); + return result; +} + +// Time = O(arrivals + toServe) +// Space = O(1) - fixed size queue +inline void SimulateWaitLine(const int arrivals, int toServe, TQueue& queue) +{ + static int nextId = 1; + // arrivals + for (int i = 1; i <= arrivals; ++i) { + queue.Enqueue(nextId); + std::cout << "Arrives: " << nextId << std::endl; + nextId++; + } + + // served + for (int i = 0; i < toServe && !queue.IsEmpty(); ++i) { + std::cout << "Served: " << queue.Dequeue() << std::endl; + } +} + +// O(1) both - just checking if true or false +inline bool InBounds (int r, int c) +{ + return r >= 0 && r < GRID_ROWS && c >= 0 && c < GRID_COLS; +} + +// O(r * c) +inline void ResetVisited(bool visited[GRID_ROWS][GRID_COLS]) +{ + for (int r = 0; r < GRID_ROWS; ++r) { + for (int c = 0; c < GRID_COLS; ++c) { + visited[r][c] = false; + } + } +} + +inline int EncodePos(int r, int c) { + return r * GRID_COLS + c; +} + +inline void DecodePos(int code, int& r, int& c) { + r = code / GRID_COLS; + c = code % GRID_COLS; +} + +// Time = O( r * c) worst case +// Space is O(1) +inline bool DFSFindZero(const int grid[GRID_ROWS][GRID_COLS], bool visited[GRID_ROWS][GRID_COLS], + int startR, int startC, int& outR, int& outC) +{ + TStack s; + + // mark start immediately to avoid multiple pushes + visited[startR][startC] = true; + s.Push(EncodePos(startR, startC)); + + while (!s.IsEmpty()) + { + int code = s.Pop(); + int r, c; DecodePos(code, r, c); + + if (grid[r][c] == 0) { + outR = r; outC = c; + return true; + } + + // Push neighbours, marking visited when discovered + if (InBounds(r - 1, c) && !visited[r - 1][c]) { + visited[r - 1][c] = true; + s.Push(EncodePos(r - 1, c)); // up + } + if (InBounds(r, c + 1) && !visited[r][c + 1]) { + visited[r][c + 1] = true; + s.Push(EncodePos(r, c + 1)); // right + } + if (InBounds(r + 1, c) && !visited[r + 1][c]) { + visited[r + 1][c] = true; + s.Push(EncodePos(r + 1, c)); // down + } + if (InBounds(r, c - 1) && !visited[r][c - 1]) { + visited[r][c - 1] = true; + s.Push(EncodePos(r, c - 1)); // left + } + } + return false; +} + +// Same complexity as DFS +inline bool BFSFindZero(const int grid[GRID_ROWS][GRID_COLS], bool visited[GRID_ROWS][GRID_COLS], + int startR, int startC, int& outR, int& outC) +{ + TQueue q; + + // mark start immediately to avoid duplicate enqueues + visited[startR][startC] = true; + q.Enqueue(EncodePos(startR, startC)); + + while (!q.IsEmpty()) + { + int code = q.Dequeue(); + int r, c; DecodePos(code, r, c); + + if (grid[r][c] == 0) { + outR = r; outC = c; + return true; + } + + // Enqueue neighbours, marking visited on discovery + if (InBounds(r - 1, c) && !visited[r - 1][c]) { + visited[r - 1][c] = true; + q.Enqueue(EncodePos(r - 1, c)); // up + } + if (InBounds(r, c + 1) && !visited[r][c + 1]) { + visited[r][c + 1] = true; + q.Enqueue(EncodePos(r, c + 1)); // right + } + if (InBounds(r + 1, c) && !visited[r + 1][c]) { + visited[r + 1][c] = true; + q.Enqueue(EncodePos(r + 1, c)); // down + } + if (InBounds(r, c - 1) && !visited[r][c - 1]) { + visited[r][c - 1] = true; + q.Enqueue(EncodePos(r, c - 1)); // left + } + } + return false; +} + + + + +#endif //STACKS_QUEUES_FUTILS_H \ No newline at end of file diff --git a/Stacks&Queues/TQueue.cpp b/Stacks&Queues/TQueue.cpp new file mode 100644 index 0000000..cb00bd5 --- /dev/null +++ b/Stacks&Queues/TQueue.cpp @@ -0,0 +1,55 @@ +#include "TQueue.h" +#include + + +// Time and space O(1) - only adds to the end of the queue and wraps around when needed +void TQueue::Enqueue(const int item) +{ + if (IsFull()) + throw std::overflow_error("Queue Overflow"); + queue[tail] = item; + tail = (tail + 1) % MAX_SIZE; + count++; +} + +// Both O(1) +int TQueue::Dequeue() +{ + if (IsEmpty()) + throw std::underflow_error("Empty Queue"); + const int item = queue[head]; + head = (head + 1) % MAX_SIZE; + count--; + return item; +} + +// Both O(1) +int TQueue::Peek() const +{ + if (IsEmpty()) + throw std::underflow_error("Empty Queue"); + return queue[head]; +} + +// Both O(1) +bool TQueue::IsEmpty() const +{ + return count == 0; +} + +bool TQueue::IsFull() const +{ + return count == MAX_SIZE; +} + +int TQueue::GetTail() const +{ + if (IsEmpty()) + throw std::underflow_error("Empty Queue"); + return tail; +} + + + + + diff --git a/Stacks&Queues/TQueue.h b/Stacks&Queues/TQueue.h new file mode 100644 index 0000000..03f3c2d --- /dev/null +++ b/Stacks&Queues/TQueue.h @@ -0,0 +1,25 @@ +#ifndef STACKS_QUEUES_TQUEUE_H +#define STACKS_QUEUES_TQUEUE_H + +#define MAX_SIZE (100 * 100) + + +class TQueue { + private: + int queue[MAX_SIZE] {}; + int head = 0; + int tail = 0; + int count = 0; + + public: + TQueue() = default; + ~TQueue() = default; + + void Enqueue(int item); + int Dequeue(); + [[nodiscard]] int GetTail() const; + [[nodiscard]] int Peek() const; + [[nodiscard]] bool IsEmpty() const; + [[nodiscard]] bool IsFull() const; +}; +#endif //STACKS_QUEUES_TQUEUE_H \ No newline at end of file diff --git a/Stacks&Queues/TStack.cpp b/Stacks&Queues/TStack.cpp new file mode 100644 index 0000000..6e94aa5 --- /dev/null +++ b/Stacks&Queues/TStack.cpp @@ -0,0 +1,43 @@ +#include "TStack.h" +#include + +// Time complexity O(1) - always append to the end of the array and use that as the top of the stack +// Space complexity O(1) - no need to save helper variables, just place on top of existing, size-static stack +void TStack::Push(const int item) +{ + if (top >= MAX_SIZE) + throw std::overflow_error("Stack overflow"); + stack[top++] = item; +} + + +// Time and space complexity both O(1) - Only works with the top element so if you have +// 5 or 500 elements in the stack the result will be the same +// Only returns and removes top element +int TStack::Pop() +{ + if (top == 0) + throw std::underflow_error("Stack underflow"); + return stack[--top]; +} + +// Time and space complexity O(1) - only returns the top element +int TStack::Peek() const +{ + if (top == 0) + throw std::underflow_error("Stack underflow"); + return stack[top - 1]; +} + +// O(1) for both, checks to see if the stack is empty or not +// doesn't determine exact amount - just makes sure it has one +bool TStack::IsEmpty() const +{ + return top == 0; +} + + + + + + diff --git a/Stacks&Queues/TStack.h b/Stacks&Queues/TStack.h new file mode 100644 index 0000000..e9c3c02 --- /dev/null +++ b/Stacks&Queues/TStack.h @@ -0,0 +1,23 @@ +#ifndef STACKS_QUEUES_TSTACK_H +#define STACKS_QUEUES_TSTACK_H + +#define MAX_SIZE (100 * 100) + + +class TStack { +private: + int stack[MAX_SIZE]{}; + int top = 0; + +public: + TStack() = default; + ~TStack() = default; + + void Push(int item); + [[nodiscard]] int Pop(); + [[nodiscard]] int Peek() const; + [[nodiscard]] bool IsEmpty() const; + +}; + +#endif //STACKS_QUEUES_TSTACK_H \ No newline at end of file diff --git a/Stacks&Queues/main.cpp b/Stacks&Queues/main.cpp new file mode 100644 index 0000000..bac665c --- /dev/null +++ b/Stacks&Queues/main.cpp @@ -0,0 +1,48 @@ +#include +#include "FUtils.h" + +TQueue q; + +int main() +{ + // --- Part 2: quick demos --- + std::cout << "Reverse(\"stackqueue\") = " << ReverseString("stackqueue") << "\n"; + std::cout << "Factorial(6) = " << Factorial(6) << "\n"; + + TQueue q; + std::cout << "\n-- Wait line simulation --\n"; + SimulateWaitLine(5, 2, q); // 5 arrive, serve 2 now + SimulateWaitLine(3, 6, q); // 3 arrive, then serve the rest + + // --- Part 3.6: set up grid and visited arrays --- + std::srand(static_cast(std::time(nullptr))); + int grid[GRID_ROWS][GRID_COLS]; + bool visitedDFS[GRID_ROWS][GRID_COLS]; + bool visitedBFS[GRID_ROWS][GRID_COLS]; + + for (int r = 0; r < GRID_ROWS; ++r) + for (int c = 0; c < GRID_COLS; ++c) { + grid[r][c] = std::rand() % 10; // 0..9 + visitedDFS[r][c] = false; + visitedBFS[r][c] = false; + } + + int startR = std::rand() % GRID_ROWS; + int startC = std::rand() % GRID_COLS; + std::cout << "\nStart cell: (" << startR << ", " << startC + << ") value=" << grid[startR][startC] << "\n"; + + // --- Part 3.7: DFS --- + int dR=-1, dC=-1; + bool dfsFound = DFSFindZero(grid, visitedDFS, startR, startC, dR, dC); + if (dfsFound) std::cout << "[DFS] Found 0 at (" << dR << "," << dC << ")\n"; + else std::cout << "[DFS] No 0 found\n"; + + // --- Part 3.8: BFS --- + int bR=-1, bC=-1; + bool bfsFound = BFSFindZero(grid, visitedBFS, startR, startC, bR, bC); + if (bfsFound) std::cout << "[BFS] Found 0 at (" << bR << "," << bC << ")\n"; + else std::cout << "[BFS] No 0 found\n"; + + return 0; +} \ No newline at end of file