Adding 3rd assignment, stacks and queues
This commit is contained in:
11
Stacks&Queues/CMakeLists.txt
Normal file
11
Stacks&Queues/CMakeLists.txt
Normal file
@@ -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)
|
||||
183
Stacks&Queues/FUtils.h
Normal file
183
Stacks&Queues/FUtils.h
Normal file
@@ -0,0 +1,183 @@
|
||||
#ifndef STACKS_QUEUES_FUTILS_H
|
||||
#define STACKS_QUEUES_FUTILS_H
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#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
|
||||
55
Stacks&Queues/TQueue.cpp
Normal file
55
Stacks&Queues/TQueue.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "TQueue.h"
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
Stacks&Queues/TQueue.h
Normal file
25
Stacks&Queues/TQueue.h
Normal file
@@ -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
|
||||
43
Stacks&Queues/TStack.cpp
Normal file
43
Stacks&Queues/TStack.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "TStack.h"
|
||||
#include <iostream>
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
Stacks&Queues/TStack.h
Normal file
23
Stacks&Queues/TStack.h
Normal file
@@ -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
|
||||
48
Stacks&Queues/main.cpp
Normal file
48
Stacks&Queues/main.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <ctime>
|
||||
#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<unsigned>(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;
|
||||
}
|
||||
Reference in New Issue
Block a user