From 9c022935d7d8f04e92b8a3b4686d7034c3e76c01 Mon Sep 17 00:00:00 2001 From: Dmitry Malinin Date: Sat, 13 Mar 2021 16:40:45 +0300 Subject: [PATCH] Chapter 3; question 1 "Three in One"; Multistack solution --- CMakeLists.txt | 1 + .../chapter_03_includes.h | 1 + .../problem_03_01_threeInOne.cpp | 54 +++++++++++++++++++ .../problem_03_01_threeInOne.h | 51 ++++++++++++++++++ tests.cpp | 36 +++++++++++++ 5 files changed, 143 insertions(+) create mode 100644 cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.cpp create mode 100644 cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a93a419..902fa4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ set(SOURCE_FILES # CHAPTER 2 # .cpp files not included because they are template functions implemented in .h files # CHAPTER 3 + cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.cpp cpp_solutions/chapter_03_stacks_and_queues/problem_03_06_animalShelter.cpp # CHAPTER 4 cpp_solutions/chapter_04_trees_and_graphs/problem_04_07_buildOrder.cpp diff --git a/cpp_solutions/chapter_03_stacks_and_queues/chapter_03_includes.h b/cpp_solutions/chapter_03_stacks_and_queues/chapter_03_includes.h index cbb2d21..ffe04f5 100644 --- a/cpp_solutions/chapter_03_stacks_and_queues/chapter_03_includes.h +++ b/cpp_solutions/chapter_03_stacks_and_queues/chapter_03_includes.h @@ -1,4 +1,5 @@ #pragma once +#include "problem_03_01_threeInOne.h" #include "problem_03_02_StackMin.h" #include "problem_03_04_QueueViaStacks.h" #include "problem_03_05_sortStack.h" diff --git a/cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.cpp b/cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.cpp new file mode 100644 index 0000000..3b36f3f --- /dev/null +++ b/cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.cpp @@ -0,0 +1,54 @@ +#include + +#include "problem_03_01_threeInOne.h" + +namespace chapter_03 { + +MultiStack::MultiStack(const std::size_t stack_num) : + data(stack_num * 10 + 1), data_idx(1), stack_heads(stack_num, 0), free_list_head(0), stack_num(stack_num) +{} + +void MultiStack::push(const std::size_t stack_num, const TVal & val) { + assert(stack_num < this->stack_num); + + if(data_idx >= data.capacity()) { + data.resize(data.capacity() * 2); + } + + std::size_t & stack_head = stack_heads[stack_num]; // zero by default + + if(free_list_head > 0) { + const auto free_list_head_new = data[free_list_head].first; + data[free_list_head].first = stack_head; // the index of the previous item + data[free_list_head].second = val; + stack_head = free_list_head; + free_list_head = free_list_head_new; + } else { + data[data_idx].first = stack_head; // the index of the previous item + data[data_idx].second = val; + stack_head = data_idx; + ++data_idx; + } +} + +MultiStack::TVal MultiStack::pop(const std::size_t stack_num) { + assert(stack_num < this->stack_num); + + std::size_t & stack_head = stack_heads[stack_num]; // zero by default + assert(stack_head > 0); + const auto stack_head_prev = stack_head; + stack_head = data[stack_head_prev].first; + data[stack_head_prev].first = free_list_head; + free_list_head = stack_head_prev; + return data[stack_head_prev].second; +} + +MultiStack::TVal & MultiStack::get(const std::size_t stack_num) { + assert(stack_num < this->stack_num); + const std::size_t stack_head = stack_heads[stack_num]; // zero by default + assert(stack_head > 0); + return data[stack_head].second; +} + +} + diff --git a/cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.h b/cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.h new file mode 100644 index 0000000..50ece13 --- /dev/null +++ b/cpp_solutions/chapter_03_stacks_and_queues/problem_03_01_threeInOne.h @@ -0,0 +1,51 @@ +/* +Chapter 03 - Problem 01 - Three in One + +Problem Statement: +Describe how you could use a single array to implement three stacks + +Explanation: + Each stack item has two elements: an index of the previous item and a payload. + + For + push(0, 11); + push(1, 21); + push(0, 12); + push(1, 22); + push(0, 13); + + The data array would be + [(0, 0), (0, 11), (0, 21), (1, 12), (2, 22), (3, 13)] + + In this array, the first stack head index is 5 with the previous index 3 and the payload 13 + Second stack head index is 4 with the previous index 2 and payload 22 + +Time complexity: amortized O(1) +Space complexity: O(2n) +*/ + +#pragma once +#include +#include + +namespace chapter_03{ +class MultiStack { +public: + typedef int TVal; + + // + typedef std::pair TPair; + + MultiStack(const std::size_t stack_num); + + void push(const std::size_t stack_num, const TVal & val); + TVal pop(const std::size_t stack_num); + TVal & get(const std::size_t stack_num); +private: + std::vector data; + std::size_t data_idx; + std::vector stack_heads; + std::size_t free_list_head; + const std::size_t stack_num; +}; +}; // namespace chapter_03 diff --git a/tests.cpp b/tests.cpp index d564692..903a5bd 100644 --- a/tests.cpp +++ b/tests.cpp @@ -315,6 +315,42 @@ TEST_CASE("Chapter 02 - Problem 08 - findLoop()", "test") { REQUIRE(static_cast*>(nullptr) == chapter_02::findLoop(static_cast*>(nullptr))); } +TEST_CASE("Chapter 03 - Three in one", "test"){ + constexpr const int max_int = 10000; + constexpr const int stack_max = 10; + + static std::random_device r; + static std::default_random_engine r_eng(r()); + static std::uniform_int_distribution<> distr(0, max_int); + + const std::size_t stack_count = abs(distr(r_eng)) % stack_max + 1; + std::vector> arrays(stack_count); + chapter_03::MultiStack stack(stack_count); + + for(int i = 1000; --i >= 0;) { + const std::size_t stack_i = static_cast(distr(r_eng)) % stack_count; + const chapter_03::MultiStack::TVal val = distr(r_eng); + arrays[stack_i].push_back(val); + stack.push(stack_i, val); + } + + for(int i = 25; --i >= 0;) { + const std::size_t stack_i = static_cast(distr(r_eng)) % stack_count; + assert(arrays[stack_i].size() > 0); + arrays[stack_i].pop_back(); + stack.pop(stack_i); + } + + for(std::size_t stack_i = 0; stack_i < stack_count; ++stack_i) { + auto & ar = arrays[stack_i]; + + for(std::size_t j = ar.size(); j > 1; --j) { + assert(stack.pop(stack_i) == ar.back()); + ar.pop_back(); + } + } +} + TEST_CASE("Chapter 03 - Stack", "test"){ chapter_03::Stack myStack; for (int i = 1; i <= 4; i++){