diff --git a/CMakeLists.txt b/CMakeLists.txt index 890e907..b1204fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,12 +18,20 @@ FetchContent_MakeAvailable(SFML) add_executable(SortLab src/main.cpp src/App.cpp + src/App_audio.cpp src/Array.cpp + src/Sorter.cpp + src/UI.cpp + src/sorters/BubbleSorter.cpp + src/sorters/SelectionSorter.cpp + src/sorters/InsertionSorter.cpp + src/sorters/MergeSorter.cpp + src/sorters/QuickSorter.cpp ) target_include_directories(SortLab PRIVATE ${CMAKE_SOURCE_DIR}/include) -target_link_libraries(SortLab PRIVATE sfml-graphics sfml-window sfml-system) +target_link_libraries(SortLab PRIVATE sfml-graphics sfml-window sfml-system sfml-audio) if(WIN32) diff --git a/assets/fonts/Roboto-Regular.ttf b/assets/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000..ddee473 Binary files /dev/null and b/assets/fonts/Roboto-Regular.ttf differ diff --git a/include/App.hpp b/include/App.hpp index 7ea5cda..db26d86 100644 --- a/include/App.hpp +++ b/include/App.hpp @@ -1,6 +1,10 @@ #pragma once #include +#include +#include #include "Array.hpp" +#include "Sorter.hpp" +#include "UI.hpp" class App { public: @@ -11,7 +15,26 @@ private: void handleEvents(); void update(float dt); void render(); + void switchSorter(std::unique_ptr newSorter); + void generateBeepSound(); + void playBeep(float pitch); sf::RenderWindow window_; Array array_; + std::unique_ptr currentSorter_; + UI ui_; + bool isPlaying_; + float timeSinceLastStep_; + float stepDelay_; + + sf::SoundBuffer beepBuffer_; + sf::Sound beepSound_; + + bool isSweeping_; + int sweepIndex_; + float sweepTimer_; + float sweepDelay_; + + size_t lastComparisons_; + size_t lastSwaps_; }; diff --git a/include/Array.hpp b/include/Array.hpp index cbe91ca..6a5e7a4 100644 --- a/include/Array.hpp +++ b/include/Array.hpp @@ -15,8 +15,16 @@ public: void setValue(int index, float value); void setState(int index, State state); void resetStates(); + void resetCounters(); + + size_t getComparisons() const; + size_t getSwaps() const; + void incrementComparisons(); + void incrementSwaps(); private: std::vector data_; std::vector states_; + size_t comparisons_; + size_t swaps_; }; diff --git a/include/Sorter.hpp b/include/Sorter.hpp index e69de29..fffd93a 100644 --- a/include/Sorter.hpp +++ b/include/Sorter.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "Array.hpp" +#include + +class Sorter { +public: + virtual ~Sorter() = default; + + virtual void step(Array& array) = 0; + virtual bool isFinished() const = 0; + virtual std::string getName() const = 0; + virtual void reset() = 0; +}; diff --git a/include/UI.hpp b/include/UI.hpp index e69de29..e4efea0 100644 --- a/include/UI.hpp +++ b/include/UI.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include "Sorter.hpp" +#include + +class UI { +public: + UI(); + + void update(const Sorter& sorter, bool isPlaying, bool isFinished, float stepDelay, const Array& array); + void draw(sf::RenderWindow& window); + +private: + sf::Font font_; + sf::Text algorithmText_; + sf::Text stateText_; + sf::Text comparisonsText_; + sf::Text swapsText_; + sf::Text speedText_; + sf::Text controlsText_; + bool fontLoaded_; +}; diff --git a/include/sorters/BubbleSorter.hpp b/include/sorters/BubbleSorter.hpp index e69de29..2d8f8c4 100644 --- a/include/sorters/BubbleSorter.hpp +++ b/include/sorters/BubbleSorter.hpp @@ -0,0 +1,21 @@ +#pragma once +#include "Sorter.hpp" + +class BubbleSorter : public Sorter { +public: + BubbleSorter(); + + void step(Array& array) override; + bool isFinished() const override; + std::string getName() const override; + void reset() override; + +private: + enum class Phase { COMPARING, SWAPPING, NEXT }; + + int i_; + int j_; + int n_; + bool finished_; + Phase phase_; +}; diff --git a/include/sorters/InsertionSorter.hpp b/include/sorters/InsertionSorter.hpp index e69de29..b9ca211 100644 --- a/include/sorters/InsertionSorter.hpp +++ b/include/sorters/InsertionSorter.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "Sorter.hpp" + +class InsertionSorter : public Sorter { +public: + InsertionSorter(); + + void step(Array& array) override; + bool isFinished() const override; + std::string getName() const override; + void reset() override; + +private: + enum class Phase { COMPARING, SHIFTING, INSERTING, NEXT }; + + int i_; + int j_; + int n_; + float key_; + bool finished_; + Phase phase_; +}; diff --git a/include/sorters/MergeSorter.hpp b/include/sorters/MergeSorter.hpp index e69de29..45ac940 100644 --- a/include/sorters/MergeSorter.hpp +++ b/include/sorters/MergeSorter.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "Sorter.hpp" +#include + +class MergeSorter : public Sorter { +public: + MergeSorter(); + + void step(Array& array) override; + bool isFinished() const override; + std::string getName() const override; + void reset() override; + +private: + enum class Phase { MERGING, COPYING_LEFT, COPYING_RIGHT, COPYING_BACK, NEXT_MERGE }; + + int currentSize_; + int leftStart_; + int mid_; + int rightEnd_; + int leftIndex_; + int rightIndex_; + int mergeIndex_; + std::vector temp_; + bool finished_; + Phase phase_; + int n_; +}; diff --git a/include/sorters/QuickSorter.hpp b/include/sorters/QuickSorter.hpp index e69de29..5f6749f 100644 --- a/include/sorters/QuickSorter.hpp +++ b/include/sorters/QuickSorter.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "Sorter.hpp" +#include + +class QuickSorter : public Sorter { +public: + QuickSorter(); + + void step(Array& array) override; + bool isFinished() const override; + std::string getName() const override; + void reset() override; + +private: + enum class Phase { PARTITIONING, SWAPPING_PIVOT, PUSHING_RANGES }; + + struct Range { + int low; + int high; + }; + + std::vector stack_; + int currentLow_; + int currentHigh_; + int pivotIndex_; + int i_; + int j_; + float pivotValue_; + bool finished_; + Phase phase_; + int n_; +}; diff --git a/include/sorters/SelectionSorter.hpp b/include/sorters/SelectionSorter.hpp index e69de29..a200fc9 100644 --- a/include/sorters/SelectionSorter.hpp +++ b/include/sorters/SelectionSorter.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "Sorter.hpp" + +class SelectionSorter : public Sorter { +public: + SelectionSorter(); + + void step(Array& array) override; + bool isFinished() const override; + std::string getName() const override; + void reset() override; + +private: + enum class Phase { FINDING_MIN, SWAPPING, NEXT }; + + int i_; + int j_; + int minIndex_; + int n_; + bool finished_; + Phase phase_; +}; diff --git a/src/App.cpp b/src/App.cpp index feb83e0..5a714ed 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -1,7 +1,28 @@ #include "App.hpp" +#include "sorters/BubbleSorter.hpp" +#include "sorters/SelectionSorter.hpp" +#include "sorters/InsertionSorter.hpp" +#include "sorters/MergeSorter.hpp" +#include "sorters/QuickSorter.hpp" -App::App() : window_(sf::VideoMode(1280, 720), "SortLab"), array_(100) { - window_.setFramerateLimit(60); +App::App() + : window_(sf::VideoMode(1280, 720), "SortLab") + , array_(100) + , currentSorter_(std::make_unique()) + , ui_() + , isPlaying_(false) + , timeSinceLastStep_(0.0f) + , stepDelay_(0.01f) + , isSweeping_(false) + , sweepIndex_(0) + , sweepTimer_(0.0f) + , sweepDelay_(0.005f) + , lastComparisons_(0) + , lastSwaps_(0) { + window_.setFramerateLimit(60); + generateBeepSound(); + beepSound_.setBuffer(beepBuffer_); + beepSound_.setVolume(15.0f); } void App::run() { @@ -20,14 +41,129 @@ void App::handleEvents() { if (event.type == sf::Event::Closed) { window_.close(); } - if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::R) { - array_.shuffle(); + + if (event.type == sf::Event::KeyPressed) { + switch (event.key.code) { + case sf::Keyboard::Space: + isPlaying_ = !isPlaying_; + break; + + case sf::Keyboard::Right: + if (!isPlaying_ && !currentSorter_->isFinished()) { + currentSorter_->step(array_); + } + break; + + case sf::Keyboard::Up: + stepDelay_ = (stepDelay_ > 0.001f) ? stepDelay_ * 0.5f : 0.001f; + if (stepDelay_ < 0.001f) stepDelay_ = 0.001f; + break; + + case sf::Keyboard::Down: + stepDelay_ = (stepDelay_ < 0.5f) ? stepDelay_ * 2.0f : 0.5f; + if (stepDelay_ > 0.5f) stepDelay_ = 0.5f; + break; + + case sf::Keyboard::Num1: + switchSorter(std::make_unique()); + break; + + case sf::Keyboard::Num2: + switchSorter(std::make_unique()); + break; + + case sf::Keyboard::Num3: + switchSorter(std::make_unique()); + break; + + case sf::Keyboard::Num4: + switchSorter(std::make_unique()); + break; + + case sf::Keyboard::Num5: + switchSorter(std::make_unique()); + break; + + case sf::Keyboard::R: + array_.shuffle(); + array_.resetStates(); + array_.resetCounters(); + currentSorter_->reset(); + isPlaying_ = false; + timeSinceLastStep_ = 0.0f; + isSweeping_ = false; + sweepIndex_ = 0; + lastComparisons_ = 0; + lastSwaps_ = 0; + break; + + default: + break; + } } } } void App::update(float dt) { - + ui_.update(*currentSorter_, isPlaying_, currentSorter_->isFinished(), stepDelay_, array_); + + if (isSweeping_) { + sweepTimer_ += dt; + + if (sweepTimer_ >= sweepDelay_) { + if (sweepIndex_ < array_.getSize()) { + array_.setState(sweepIndex_, Array::State::SORTED); + + float normalizedValue = array_.getValue(sweepIndex_) / static_cast(array_.getSize()); + float pitch = 0.5f + normalizedValue * 1.5f; + playBeep(pitch); + + sweepIndex_++; + sweepTimer_ = 0.0f; + } else { + isSweeping_ = false; + } + } + return; + } + + if (isPlaying_ && !currentSorter_->isFinished()) { + timeSinceLastStep_ += dt; + + if (timeSinceLastStep_ >= stepDelay_) { + size_t beforeComparisons = array_.getComparisons(); + size_t beforeSwaps = array_.getSwaps(); + + currentSorter_->step(array_); + + size_t afterComparisons = array_.getComparisons(); + size_t afterSwaps = array_.getSwaps(); + + if (afterComparisons > beforeComparisons || afterSwaps > beforeSwaps) { + float avgPitch = 1.0f; + + for (int i = 0; i < array_.getSize(); ++i) { + if (array_.getState(i) == Array::State::COMPARE || + array_.getState(i) == Array::State::SWAP) { + float normalizedValue = array_.getValue(i) / static_cast(array_.getSize()); + avgPitch = 0.5f + normalizedValue * 1.5f; + break; + } + } + + playBeep(avgPitch); + } + + timeSinceLastStep_ = 0.0f; + + if (currentSorter_->isFinished()) { + array_.resetStates(); + isSweeping_ = true; + sweepIndex_ = 0; + sweepTimer_ = 0.0f; + } + } + } } void App::render() { @@ -52,5 +188,20 @@ void App::render() { window_.draw(bar); } + ui_.draw(window_); + window_.display(); } + +void App::switchSorter(std::unique_ptr newSorter) { + currentSorter_ = std::move(newSorter); + array_.shuffle(); + array_.resetStates(); + array_.resetCounters(); + isPlaying_ = false; + timeSinceLastStep_ = 0.0f; + isSweeping_ = false; + sweepIndex_ = 0; + lastComparisons_ = 0; + lastSwaps_ = 0; +} diff --git a/src/App_audio.cpp b/src/App_audio.cpp new file mode 100644 index 0000000..c054824 --- /dev/null +++ b/src/App_audio.cpp @@ -0,0 +1,30 @@ +#include "App.hpp" +#include +#include + +void App::generateBeepSound() { + const unsigned int sampleRate = 44100; + const float duration = 0.02f; + const unsigned int sampleCount = static_cast(sampleRate * duration); + + std::vector samples(sampleCount); + + const float frequency = 440.0f; + const float amplitude = 3000.0f; + + for (unsigned int i = 0; i < sampleCount; ++i) { + float t = static_cast(i) / sampleRate; + float envelope = 1.0f - (t / duration); + float value = amplitude * envelope * std::sin(2.0f * 3.14159f * frequency * t); + samples[i] = static_cast(value); + } + + beepBuffer_.loadFromSamples(samples.data(), sampleCount, 1, sampleRate); +} + +void App::playBeep(float pitch) { + if (beepSound_.getStatus() != sf::Sound::Playing) { + beepSound_.setPitch(pitch); + beepSound_.play(); + } +} diff --git a/src/Array.cpp b/src/Array.cpp index ecdd2d9..04770ee 100644 --- a/src/Array.cpp +++ b/src/Array.cpp @@ -1,6 +1,8 @@ #include "Array.hpp" +#include +#include -Array::Array(int size) { +Array::Array(int size) : comparisons_(0), swaps_(0) { data_.resize(size); states_.resize(size, State::NORMAL); shuffle(); @@ -28,3 +30,24 @@ void Array::setState(int index, State state) { states_[index] = state; } void Array::resetStates() { std::fill(states_.begin(), states_.end(), State::NORMAL); } + +void Array::resetCounters() { + comparisons_ = 0; + swaps_ = 0; +} + +size_t Array::getComparisons() const { + return comparisons_; +} + +size_t Array::getSwaps() const { + return swaps_; +} + +void Array::incrementComparisons() { + comparisons_++; +} + +void Array::incrementSwaps() { + swaps_++; +} diff --git a/src/Sorter.cpp b/src/Sorter.cpp index e69de29..a4af018 100644 --- a/src/Sorter.cpp +++ b/src/Sorter.cpp @@ -0,0 +1 @@ +#include "Sorter.hpp" diff --git a/src/UI.cpp b/src/UI.cpp index e69de29..702f7e3 100644 --- a/src/UI.cpp +++ b/src/UI.cpp @@ -0,0 +1,82 @@ +#include "UI.hpp" +#include + +UI::UI() : fontLoaded_(false) { + if (!font_.loadFromFile("assets/fonts/Roboto-Regular.ttf")) { + std::cerr << "Failed to load font" << std::endl; + return; + } + + fontLoaded_ = true; + + algorithmText_.setFont(font_); + algorithmText_.setCharacterSize(24); + algorithmText_.setFillColor(sf::Color::White); + algorithmText_.setPosition(20.0f, 20.0f); + + stateText_.setFont(font_); + stateText_.setCharacterSize(20); + stateText_.setFillColor(sf::Color::White); + stateText_.setPosition(20.0f, 55.0f); + + comparisonsText_.setFont(font_); + comparisonsText_.setCharacterSize(18); + comparisonsText_.setFillColor(sf::Color(200, 200, 200)); + comparisonsText_.setPosition(20.0f, 90.0f); + + swapsText_.setFont(font_); + swapsText_.setCharacterSize(18); + swapsText_.setFillColor(sf::Color(200, 200, 200)); + swapsText_.setPosition(20.0f, 115.0f); + + speedText_.setFont(font_); + speedText_.setCharacterSize(18); + speedText_.setFillColor(sf::Color(200, 200, 200)); + speedText_.setPosition(20.0f, 140.0f); + + controlsText_.setFont(font_); + controlsText_.setCharacterSize(14); + controlsText_.setFillColor(sf::Color(150, 150, 150)); + controlsText_.setPosition(20.0f, 175.0f); + controlsText_.setString("[1-5] Algorithms [Space] Play/Pause [Right] Step [Up/Down] Speed [R] Shuffle"); +} + +void UI::update(const Sorter& sorter, bool isPlaying, bool isFinished, float stepDelay, const Array& array) { + if (!fontLoaded_) { + return; + } + + algorithmText_.setString("Algorithm: " + sorter.getName()); + + std::string state; + if (isFinished) { + state = "Status: Finished"; + stateText_.setFillColor(sf::Color::Green); + } else if (isPlaying) { + state = "Status: Playing"; + stateText_.setFillColor(sf::Color::Yellow); + } else { + state = "Status: Paused"; + stateText_.setFillColor(sf::Color::White); + } + stateText_.setString(state); + + comparisonsText_.setString("Comparisons: " + std::to_string(array.getComparisons())); + swapsText_.setString("Swaps: " + std::to_string(array.getSwaps())); + + int delayMs = static_cast(stepDelay * 1000.0f); + speedText_.setString("Delay: " + std::to_string(delayMs) + "ms"); +} + +void UI::draw(sf::RenderWindow& window) { + if (!fontLoaded_) { + return; + } + + window.draw(algorithmText_); + window.draw(stateText_); + window.draw(comparisonsText_); + window.draw(swapsText_); + window.draw(speedText_); + window.draw(controlsText_); +} diff --git a/src/sorters/BubbleSorter.cpp b/src/sorters/BubbleSorter.cpp index e69de29..4bdd452 100644 --- a/src/sorters/BubbleSorter.cpp +++ b/src/sorters/BubbleSorter.cpp @@ -0,0 +1,72 @@ +#include "sorters/BubbleSorter.hpp" + +BubbleSorter::BubbleSorter() + : i_(0), j_(0), n_(0), finished_(false), phase_(Phase::COMPARING) { +} + +void BubbleSorter::step(Array& array) { + if (finished_) { + return; + } + + if (n_ == 0) { + n_ = array.getSize(); + } + + if (phase_ == Phase::COMPARING) { + if (j_ >= n_ - i_ - 1) { + i_++; + j_ = 0; + + if (i_ >= n_ - 1) { + array.resetStates(); + for (int k = 0; k < n_; ++k) { + array.setState(k, Array::State::SORTED); + } + finished_ = true; + return; + } + } + + array.resetStates(); + array.setState(j_, Array::State::COMPARE); + array.setState(j_ + 1, Array::State::COMPARE); + + array.incrementComparisons(); + + if (array.getValue(j_) > array.getValue(j_ + 1)) { + phase_ = Phase::SWAPPING; + } else { + phase_ = Phase::NEXT; + } + } else if (phase_ == Phase::SWAPPING) { + array.setState(j_, Array::State::SWAP); + array.setState(j_ + 1, Array::State::SWAP); + + float temp = array.getValue(j_); + array.setValue(j_, array.getValue(j_ + 1)); + array.setValue(j_ + 1, temp); + + array.incrementSwaps(); + phase_ = Phase::NEXT; + } else if (phase_ == Phase::NEXT) { + j_++; + phase_ = Phase::COMPARING; + } +} + +bool BubbleSorter::isFinished() const { + return finished_; +} + +std::string BubbleSorter::getName() const { + return "Bubble Sort"; +} + +void BubbleSorter::reset() { + i_ = 0; + j_ = 0; + n_ = 0; + finished_ = false; + phase_ = Phase::COMPARING; +} diff --git a/src/sorters/InsertionSorter.cpp b/src/sorters/InsertionSorter.cpp index e69de29..b2aad41 100644 --- a/src/sorters/InsertionSorter.cpp +++ b/src/sorters/InsertionSorter.cpp @@ -0,0 +1,77 @@ +#include "sorters/InsertionSorter.hpp" + +InsertionSorter::InsertionSorter() + : i_(1), j_(0), n_(0), key_(0.0f), finished_(false), phase_(Phase::COMPARING) { +} + +void InsertionSorter::step(Array& array) { + if (finished_) { + return; + } + + if (n_ == 0) { + n_ = array.getSize(); + array.setState(0, Array::State::SORTED); + } + + if (phase_ == Phase::COMPARING) { + if (i_ >= n_) { + array.resetStates(); + for (int k = 0; k < n_; ++k) { + array.setState(k, Array::State::SORTED); + } + finished_ = true; + return; + } + + key_ = array.getValue(i_); + j_ = i_ - 1; + phase_ = Phase::SHIFTING; + } else if (phase_ == Phase::SHIFTING) { + if (j_ >= 0) { + array.resetStates(); + array.setState(j_, Array::State::COMPARE); + array.setState(j_ + 1, Array::State::SWAP); + + array.incrementComparisons(); + + if (array.getValue(j_) > key_) { + array.setValue(j_ + 1, array.getValue(j_)); + array.incrementSwaps(); + j_--; + } else { + phase_ = Phase::INSERTING; + } + } else { + phase_ = Phase::INSERTING; + } + } else if (phase_ == Phase::INSERTING) { + array.setValue(j_ + 1, key_); + + for (int k = 0; k <= i_; ++k) { + array.setState(k, Array::State::SORTED); + } + + phase_ = Phase::NEXT; + } else if (phase_ == Phase::NEXT) { + i_++; + phase_ = Phase::COMPARING; + } +} + +bool InsertionSorter::isFinished() const { + return finished_; +} + +std::string InsertionSorter::getName() const { + return "Insertion Sort"; +} + +void InsertionSorter::reset() { + i_ = 1; + j_ = 0; + n_ = 0; + key_ = 0.0f; + finished_ = false; + phase_ = Phase::COMPARING; +} diff --git a/src/sorters/MergeSorter.cpp b/src/sorters/MergeSorter.cpp index e69de29..0ea130a 100644 --- a/src/sorters/MergeSorter.cpp +++ b/src/sorters/MergeSorter.cpp @@ -0,0 +1,136 @@ +#include "sorters/MergeSorter.hpp" + +MergeSorter::MergeSorter() + : currentSize_(1), leftStart_(0), mid_(0), rightEnd_(0) + , leftIndex_(0), rightIndex_(0), mergeIndex_(0) + , finished_(false), phase_(Phase::MERGING), n_(0) { +} + +void MergeSorter::step(Array& array) { + if (finished_) { + return; + } + + if (n_ == 0) { + n_ = array.getSize(); + temp_.resize(n_); + } + + if (currentSize_ >= n_) { + array.resetStates(); + for (int k = 0; k < n_; ++k) { + array.setState(k, Array::State::SORTED); + } + finished_ = true; + return; + } + + if (phase_ == Phase::MERGING) { + if (leftStart_ >= n_ - 1) { + currentSize_ *= 2; + leftStart_ = 0; + return; + } + + mid_ = leftStart_ + currentSize_ - 1; + rightEnd_ = (leftStart_ + 2 * currentSize_ - 1 < n_ - 1) + ? leftStart_ + 2 * currentSize_ - 1 + : n_ - 1; + + if (mid_ >= n_) { + mid_ = n_ - 1; + } + + leftIndex_ = leftStart_; + rightIndex_ = mid_ + 1; + mergeIndex_ = 0; + + for (int k = leftStart_; k <= rightEnd_; ++k) { + temp_[mergeIndex_++] = array.getValue(k); + } + + leftIndex_ = 0; + rightIndex_ = mid_ - leftStart_ + 1; + mergeIndex_ = leftStart_; + + phase_ = Phase::COPYING_BACK; + } else if (phase_ == Phase::COPYING_BACK) { + int leftEnd = mid_ - leftStart_; + int rightEndLocal = rightEnd_ - leftStart_; + + if (leftIndex_ <= leftEnd && rightIndex_ <= rightEndLocal) { + array.resetStates(); + array.setState(mergeIndex_, Array::State::SWAP); + array.setState(leftStart_ + leftIndex_, Array::State::COMPARE); + array.setState(leftStart_ + rightIndex_, Array::State::COMPARE); + + array.incrementComparisons(); + + if (temp_[leftIndex_] <= temp_[rightIndex_]) { + array.setValue(mergeIndex_, temp_[leftIndex_]); + leftIndex_++; + } else { + array.setValue(mergeIndex_, temp_[rightIndex_]); + rightIndex_++; + } + + array.incrementSwaps(); + mergeIndex_++; + } else { + phase_ = Phase::COPYING_LEFT; + } + } else if (phase_ == Phase::COPYING_LEFT) { + int leftEnd = mid_ - leftStart_; + + if (leftIndex_ <= leftEnd) { + array.resetStates(); + array.setState(mergeIndex_, Array::State::SWAP); + + array.setValue(mergeIndex_, temp_[leftIndex_]); + leftIndex_++; + mergeIndex_++; + array.incrementSwaps(); + } else { + phase_ = Phase::COPYING_RIGHT; + } + } else if (phase_ == Phase::COPYING_RIGHT) { + int rightEndLocal = rightEnd_ - leftStart_; + + if (rightIndex_ <= rightEndLocal) { + array.resetStates(); + array.setState(mergeIndex_, Array::State::SWAP); + + array.setValue(mergeIndex_, temp_[rightIndex_]); + rightIndex_++; + mergeIndex_++; + array.incrementSwaps(); + } else { + phase_ = Phase::NEXT_MERGE; + } + } else if (phase_ == Phase::NEXT_MERGE) { + leftStart_ += 2 * currentSize_; + phase_ = Phase::MERGING; + } +} + +bool MergeSorter::isFinished() const { + return finished_; +} + +std::string MergeSorter::getName() const { + return "Merge Sort"; +} + +void MergeSorter::reset() { + currentSize_ = 1; + leftStart_ = 0; + mid_ = 0; + rightEnd_ = 0; + leftIndex_ = 0; + rightIndex_ = 0; + mergeIndex_ = 0; + temp_.clear(); + finished_ = false; + phase_ = Phase::MERGING; + n_ = 0; +} diff --git a/src/sorters/QuickSorter.cpp b/src/sorters/QuickSorter.cpp index e69de29..3888fc9 100644 --- a/src/sorters/QuickSorter.cpp +++ b/src/sorters/QuickSorter.cpp @@ -0,0 +1,122 @@ +#include "sorters/QuickSorter.hpp" + +QuickSorter::QuickSorter() + : currentLow_(0), currentHigh_(0), pivotIndex_(0), i_(0), j_(0) + , pivotValue_(0.0f), finished_(false), phase_(Phase::PARTITIONING), n_(0) { +} + +void QuickSorter::step(Array& array) { + if (finished_) { + return; + } + + if (n_ == 0) { + n_ = array.getSize(); + stack_.push_back({0, n_ - 1}); + } + + if (stack_.empty()) { + array.resetStates(); + for (int k = 0; k < n_; ++k) { + array.setState(k, Array::State::SORTED); + } + finished_ = true; + return; + } + + if (phase_ == Phase::PARTITIONING) { + if (j_ == currentLow_) { + Range range = stack_.back(); + stack_.pop_back(); + + if (range.low >= range.high) { + if (stack_.empty()) { + array.resetStates(); + for (int k = 0; k < n_; ++k) { + array.setState(k, Array::State::SORTED); + } + finished_ = true; + } + return; + } + + currentLow_ = range.low; + currentHigh_ = range.high; + pivotIndex_ = currentHigh_; + pivotValue_ = array.getValue(pivotIndex_); + i_ = currentLow_ - 1; + j_ = currentLow_; + } + + if (j_ < currentHigh_) { + array.resetStates(); + array.setState(j_, Array::State::COMPARE); + array.setState(pivotIndex_, Array::State::SWAP); + + array.incrementComparisons(); + + if (array.getValue(j_) < pivotValue_) { + i_++; + + if (i_ != j_) { + array.setState(i_, Array::State::SWAP); + + float temp = array.getValue(i_); + array.setValue(i_, array.getValue(j_)); + array.setValue(j_, temp); + + array.incrementSwaps(); + } + } + + j_++; + } else { + phase_ = Phase::SWAPPING_PIVOT; + } + } else if (phase_ == Phase::SWAPPING_PIVOT) { + array.resetStates(); + array.setState(i_ + 1, Array::State::SWAP); + array.setState(pivotIndex_, Array::State::SWAP); + + float temp = array.getValue(i_ + 1); + array.setValue(i_ + 1, array.getValue(pivotIndex_)); + array.setValue(pivotIndex_, temp); + + array.incrementSwaps(); + pivotIndex_ = i_ + 1; + + phase_ = Phase::PUSHING_RANGES; + } else if (phase_ == Phase::PUSHING_RANGES) { + if (pivotIndex_ - 1 > currentLow_) { + stack_.push_back({currentLow_, pivotIndex_ - 1}); + } + + if (pivotIndex_ + 1 < currentHigh_) { + stack_.push_back({pivotIndex_ + 1, currentHigh_}); + } + + j_ = currentLow_; + phase_ = Phase::PARTITIONING; + } +} + +bool QuickSorter::isFinished() const { + return finished_; +} + +std::string QuickSorter::getName() const { + return "Quick Sort"; +} + +void QuickSorter::reset() { + stack_.clear(); + currentLow_ = 0; + currentHigh_ = 0; + pivotIndex_ = 0; + i_ = 0; + j_ = 0; + pivotValue_ = 0.0f; + finished_ = false; + phase_ = Phase::PARTITIONING; + n_ = 0; +} diff --git a/src/sorters/SelectionSorter.cpp b/src/sorters/SelectionSorter.cpp index e69de29..10bdf0b 100644 --- a/src/sorters/SelectionSorter.cpp +++ b/src/sorters/SelectionSorter.cpp @@ -0,0 +1,86 @@ +#include "sorters/SelectionSorter.hpp" + +SelectionSorter::SelectionSorter() + : i_(0), j_(0), minIndex_(0), n_(0), finished_(false), phase_(Phase::FINDING_MIN) { +} + +void SelectionSorter::step(Array& array) { + if (finished_) { + return; + } + + if (n_ == 0) { + n_ = array.getSize(); + minIndex_ = 0; + } + + if (phase_ == Phase::FINDING_MIN) { + if (j_ == i_) { + minIndex_ = i_; + j_++; + } + + if (j_ < n_) { + array.resetStates(); + array.setState(i_, Array::State::COMPARE); + array.setState(j_, Array::State::COMPARE); + array.setState(minIndex_, Array::State::SWAP); + + array.incrementComparisons(); + + if (array.getValue(j_) < array.getValue(minIndex_)) { + minIndex_ = j_; + } + + j_++; + } else { + phase_ = Phase::SWAPPING; + } + } else if (phase_ == Phase::SWAPPING) { + if (minIndex_ != i_) { + array.resetStates(); + array.setState(i_, Array::State::SWAP); + array.setState(minIndex_, Array::State::SWAP); + + float temp = array.getValue(i_); + array.setValue(i_, array.getValue(minIndex_)); + array.setValue(minIndex_, temp); + + array.incrementSwaps(); + } + + array.setState(i_, Array::State::SORTED); + phase_ = Phase::NEXT; + } else if (phase_ == Phase::NEXT) { + i_++; + + if (i_ >= n_ - 1) { + array.resetStates(); + for (int k = 0; k < n_; ++k) { + array.setState(k, Array::State::SORTED); + } + finished_ = true; + return; + } + + j_ = i_; + phase_ = Phase::FINDING_MIN; + } +} + +bool SelectionSorter::isFinished() const { + return finished_; +} + +std::string SelectionSorter::getName() const { + return "Selection Sort"; +} + +void SelectionSorter::reset() { + i_ = 0; + j_ = 0; + minIndex_ = 0; + n_ = 0; + finished_ = false; + phase_ = Phase::FINDING_MIN; +}