This commit is contained in:
2026-03-05 10:35:31 +03:00
parent 11b118b3bf
commit 5a942f935f
10 changed files with 447 additions and 3 deletions
+6
View File
@@ -30,6 +30,9 @@ if(WIN32)
src/sorters/InsertionSorter.cpp src/sorters/InsertionSorter.cpp
src/sorters/MergeSorter.cpp src/sorters/MergeSorter.cpp
src/sorters/QuickSorter.cpp src/sorters/QuickSorter.cpp
src/sorters/HeapSorter.cpp
src/sorters/ShellSorter.cpp
src/sorters/RadixSorter.cpp
assets/app.rc assets/app.rc
) )
else() else()
@@ -47,6 +50,9 @@ else()
src/sorters/InsertionSorter.cpp src/sorters/InsertionSorter.cpp
src/sorters/MergeSorter.cpp src/sorters/MergeSorter.cpp
src/sorters/QuickSorter.cpp src/sorters/QuickSorter.cpp
src/sorters/HeapSorter.cpp
src/sorters/ShellSorter.cpp
src/sorters/RadixSorter.cpp
) )
endif() endif()
+4 -1
View File
@@ -33,6 +33,9 @@
| `3` | 🃏 Insertion Sort | O(n) / O(n²) / O(n²) | O(1) | | `3` | 🃏 Insertion Sort | O(n) / O(n²) / O(n²) | O(1) |
| `4` | 🔀 Merge Sort | O(n log n) / O(n log n) / O(n log n) | O(n) | | `4` | 🔀 Merge Sort | O(n log n) / O(n log n) / O(n log n) | O(n) |
| `5` | ⚡ Quick Sort | O(n log n) / O(n log n) / O(n²) | O(log n) | | `5` | ⚡ Quick Sort | O(n log n) / O(n log n) / O(n²) | O(log n) |
| `6` | 🌳 Heap Sort | O(n log n) | O(1) |
| `7` | 🐚 Shell Sort | O(n log² n) | O(1) |
| `8` | 🔢 Radix Sort | O(n·k) | O(n + k) |
--- ---
@@ -44,7 +47,7 @@
| `R` | 🔀 Перемешать массив | | `R` | 🔀 Перемешать массив |
| `→` | 👣 Один шаг (в режиме паузы) | | `→` | 👣 Один шаг (в режиме паузы) |
| `↑` / `↓` | 🐇 / 🐢 Увеличить / уменьшить скорость | | `↑` / `↓` | 🐇 / 🐢 Увеличить / уменьшить скорость |
| `1``5` | 🔢 Выбрать алгоритм | | `1``8` | 🔢 Выбрать алгоритм |
| `I` | ℹ️ Справка о программе | | `I` | ℹ️ Справка о программе |
| `Q` | 🚪 Выход | | `Q` | 🚪 Выход |
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "Sorter.hpp"
class HeapSorter : public Sorter {
public:
HeapSorter();
void step(Array& array) override;
bool isFinished() const override;
std::string getName() const override;
void reset() override;
std::string getTimeComplexity() const override;
std::string getSpaceComplexity() const override;
private:
enum class Phase { BUILDING_HEAP, HEAPIFY_DOWN, EXTRACTING, EXTRACT_SWAP, EXTRACT_HEAPIFY };
int n_;
int heapSize_;
int buildIndex_;
int extractIndex_;
int heapifyIndex_;
int leftChild_;
int rightChild_;
int largest_;
bool finished_;
Phase phase_;
bool needSwap_;
};
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "Sorter.hpp"
#include <vector>
class RadixSorter : public Sorter {
public:
RadixSorter();
void step(Array& array) override;
bool isFinished() const override;
std::string getName() const override;
void reset() override;
std::string getTimeComplexity() const override;
std::string getSpaceComplexity() const override;
private:
enum class Phase { INIT, COUNTING, PLACING, COPYING_BACK };
int n_;
int maxValue_;
int exp_;
int i_;
std::vector<int> count_;
std::vector<float> output_;
bool finished_;
Phase phase_;
};
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "Sorter.hpp"
class ShellSorter : public Sorter {
public:
ShellSorter();
void step(Array& array) override;
bool isFinished() const override;
std::string getName() const override;
void reset() override;
std::string getTimeComplexity() const override;
std::string getSpaceComplexity() const override;
private:
enum class Phase { COMPARING, SHIFTING, PLACING };
int n_;
int gap_;
int i_;
int j_;
float temp_;
bool finished_;
Phase phase_;
};
+15
View File
@@ -4,6 +4,9 @@
#include "sorters/InsertionSorter.hpp" #include "sorters/InsertionSorter.hpp"
#include "sorters/MergeSorter.hpp" #include "sorters/MergeSorter.hpp"
#include "sorters/QuickSorter.hpp" #include "sorters/QuickSorter.hpp"
#include "sorters/HeapSorter.hpp"
#include "sorters/ShellSorter.hpp"
#include "sorters/RadixSorter.hpp"
App::App() App::App()
: window_(sf::VideoMode(1600, 900), "SortLab") : window_(sf::VideoMode(1600, 900), "SortLab")
@@ -97,6 +100,18 @@ void App::handleEvents() {
switchSorter(std::make_unique<QuickSorter>()); switchSorter(std::make_unique<QuickSorter>());
break; break;
case sf::Keyboard::Num6:
switchSorter(std::make_unique<HeapSorter>());
break;
case sf::Keyboard::Num7:
switchSorter(std::make_unique<ShellSorter>());
break;
case sf::Keyboard::Num8:
switchSorter(std::make_unique<RadixSorter>());
break;
case sf::Keyboard::R: case sf::Keyboard::R:
array_.shuffle(); array_.shuffle();
array_.resetStates(); array_.resetStates();
+2 -2
View File
@@ -58,7 +58,7 @@ UI::UI() : fontLoaded_(false) {
controlsText_.setCharacterSize(30); controlsText_.setCharacterSize(30);
controlsText_.setScale(0.5f, 0.5f); controlsText_.setScale(0.5f, 0.5f);
controlsText_.setFillColor(sf::Color(200, 200, 200)); controlsText_.setFillColor(sf::Color(200, 200, 200));
controlsText_.setString("[1-5] Algorithms [Space] Play/Pause [Right] Step [Up/Down] Speed [R] Shuffle"); controlsText_.setString("[1-8] Algorithms [Space] Play/Pause [Right] Step [Up/Down] Speed [R] Shuffle");
leftBackground_.setFillColor(sf::Color(0, 0, 0, 180)); leftBackground_.setFillColor(sf::Color(0, 0, 0, 180));
rightBackground_.setFillColor(sf::Color(0, 0, 0, 180)); rightBackground_.setFillColor(sf::Color(0, 0, 0, 180));
@@ -201,7 +201,7 @@ void UI::drawInfoOverlay(sf::RenderWindow& window) {
body2.setCharacterSize(32); body2.setCharacterSize(32);
body2.setScale(0.5f, 0.5f); body2.setScale(0.5f, 0.5f);
body2.setFillColor(sf::Color(200, 200, 200)); body2.setFillColor(sf::Color(200, 200, 200));
body2.setString(toSfStr(u8"[1] Bubble Sort Время: O(n) / O(n^2) / O(n^2) Память: O(1)\n[2] Selection Sort Время: O(n^2) / O(n^2) / O(n^2) Память: O(1)\n[3] Insertion Sort Время: O(n) / O(n^2) / O(n^2) Память: O(1)\n[4] Merge Sort Время: O(n log n) / O(n log n) / O(n log n) Память: O(n)\n[5] Quick Sort Время: O(n log n) / O(n log n) / O(n^2) Память: O(log n)")); body2.setString(toSfStr(u8"[1] Bubble Sort Время: O(n) / O(n^2) / O(n^2) Память: O(1)\n[2] Selection Sort Время: O(n^2) / O(n^2) / O(n^2) Память: O(1)\n[3] Insertion Sort Время: O(n) / O(n^2) / O(n^2) Память: O(1)\n[4] Merge Sort Время: O(n log n) / O(n log n) / O(n log n) Память: O(n)\n[5] Quick Sort Время: O(n log n) / O(n log n) / O(n^2) Память: O(log n)\n[6] Heap Sort Время: O(n log n) Память: O(1)\n[7] Shell Sort Время: O(n log^2 n) Память: O(1)\n[8] Radix Sort Время: O(n*k) Память: O(n + k)"));
sf::Text section3; sf::Text section3;
section3.setFont(font_); section3.setFont(font_);
+133
View File
@@ -0,0 +1,133 @@
#include "sorters/HeapSorter.hpp"
HeapSorter::HeapSorter() {
reset();
}
void HeapSorter::step(Array& array) {
if (finished_) return;
if (n_ == 0) {
n_ = array.getSize();
if (n_ <= 1) {
finished_ = true;
return;
}
heapSize_ = n_;
buildIndex_ = n_ / 2 - 1;
phase_ = Phase::BUILDING_HEAP;
heapifyIndex_ = buildIndex_;
}
if (phase_ == Phase::BUILDING_HEAP) {
if (buildIndex_ < 0) {
phase_ = Phase::EXTRACTING;
extractIndex_ = n_ - 1;
return;
}
heapifyIndex_ = buildIndex_;
phase_ = Phase::HEAPIFY_DOWN;
needSwap_ = false; // Используем как флаг, что мы в контексте BUILD
}
else if (phase_ == Phase::HEAPIFY_DOWN || phase_ == Phase::EXTRACT_HEAPIFY) {
leftChild_ = 2 * heapifyIndex_ + 1;
rightChild_ = 2 * heapifyIndex_ + 2;
largest_ = heapifyIndex_;
array.resetStates();
array.setState(heapifyIndex_, Array::State::COMPARE);
if (leftChild_ < heapSize_) {
array.setState(leftChild_, Array::State::COMPARE);
array.incrementComparisons();
if (array.getValue(leftChild_) > array.getValue(largest_)) {
largest_ = leftChild_;
}
}
if (rightChild_ < heapSize_) {
array.setState(rightChild_, Array::State::COMPARE);
array.incrementComparisons();
if (array.getValue(rightChild_) > array.getValue(largest_)) {
largest_ = rightChild_;
}
}
if (largest_ != heapifyIndex_) {
array.setState(heapifyIndex_, Array::State::SWAP);
array.setState(largest_, Array::State::SWAP);
float temp = array.getValue(heapifyIndex_);
array.setValue(heapifyIndex_, array.getValue(largest_));
array.setValue(largest_, temp);
array.incrementSwaps();
heapifyIndex_ = largest_;
// Остаемся в текущей фазе, чтобы продолжить просеивание вниз
} else {
// Элемент на своем месте, просеивание закончено
if (phase_ == Phase::HEAPIFY_DOWN) {
buildIndex_--;
phase_ = Phase::BUILDING_HEAP;
} else {
phase_ = Phase::EXTRACTING;
}
}
}
else if (phase_ == Phase::EXTRACTING) {
if (extractIndex_ <= 0) {
array.resetStates();
for (int k = 0; k < n_; ++k) {
array.setState(k, Array::State::SORTED);
}
finished_ = true;
return;
}
phase_ = Phase::EXTRACT_SWAP;
}
else if (phase_ == Phase::EXTRACT_SWAP) {
array.resetStates();
array.setState(0, Array::State::SWAP);
array.setState(extractIndex_, Array::State::SWAP);
float temp = array.getValue(0);
array.setValue(0, array.getValue(extractIndex_));
array.setValue(extractIndex_, temp);
array.incrementSwaps();
heapSize_--;
extractIndex_--;
heapifyIndex_ = 0;
phase_ = Phase::EXTRACT_HEAPIFY;
}
}
bool HeapSorter::isFinished() const {
return finished_;
}
std::string HeapSorter::getName() const {
return "Heap Sort";
}
std::string HeapSorter::getTimeComplexity() const {
return "O(n log n)";
}
std::string HeapSorter::getSpaceComplexity() const {
return "O(1)";
}
void HeapSorter::reset() {
n_ = 0;
heapSize_ = 0;
buildIndex_ = 0;
extractIndex_ = 0;
heapifyIndex_ = 0;
leftChild_ = 0;
rightChild_ = 0;
largest_ = 0;
finished_ = false;
phase_ = Phase::BUILDING_HEAP;
needSwap_ = false;
}
+109
View File
@@ -0,0 +1,109 @@
#include "sorters/RadixSorter.hpp"
#include <cmath>
#include <algorithm>
RadixSorter::RadixSorter() {
reset();
}
void RadixSorter::step(Array& array) {
if (finished_) return;
if (n_ == 0) {
n_ = array.getSize();
maxValue_ = 0;
for (int k = 0; k < n_; ++k) {
int val = static_cast<int>(std::round(std::abs(array.getValue(k))));
if (val > maxValue_) maxValue_ = val;
}
if (maxValue_ == 0) maxValue_ = 1;
exp_ = 1;
count_.resize(10, 0);
output_.resize(n_, 0.0f);
phase_ = Phase::INIT;
}
if (phase_ == Phase::INIT) {
if (exp_ > maxValue_) {
array.resetStates();
for (int k = 0; k < n_; ++k) {
array.setState(k, Array::State::SORTED);
}
finished_ = true;
return;
}
std::fill(count_.begin(), count_.end(), 0);
i_ = 0;
phase_ = Phase::COUNTING;
} else if (phase_ == Phase::COUNTING) {
if (i_ < n_) {
array.resetStates();
array.setState(i_, Array::State::COMPARE);
int val = static_cast<int>(std::round(std::abs(array.getValue(i_))));
int digit = (val / exp_) % 10;
count_[digit]++;
array.incrementComparisons();
i_++;
} else {
for (int k = 1; k < 10; ++k) {
count_[k] += count_[k - 1];
}
i_ = n_ - 1;
phase_ = Phase::PLACING;
}
} else if (phase_ == Phase::PLACING) {
if (i_ >= 0) {
array.resetStates();
array.setState(i_, Array::State::SWAP);
int val = static_cast<int>(std::round(std::abs(array.getValue(i_))));
int digit = (val / exp_) % 10;
output_[count_[digit] - 1] = array.getValue(i_);
count_[digit]--;
array.incrementSwaps();
i_--;
} else {
i_ = 0;
phase_ = Phase::COPYING_BACK;
}
} else if (phase_ == Phase::COPYING_BACK) {
if (i_ < n_) {
array.resetStates();
array.setState(i_, Array::State::SWAP);
array.setValue(i_, output_[i_]);
i_++;
} else {
exp_ *= 10;
phase_ = Phase::INIT;
}
}
}
bool RadixSorter::isFinished() const {
return finished_;
}
std::string RadixSorter::getName() const {
return "Radix Sort";
}
std::string RadixSorter::getTimeComplexity() const {
return "O(n*k)";
}
std::string RadixSorter::getSpaceComplexity() const {
return "O(n + k)";
}
void RadixSorter::reset() {
n_ = 0;
maxValue_ = 0;
exp_ = 1;
i_ = 0;
count_.clear();
output_.clear();
finished_ = false;
phase_ = Phase::INIT;
}
+97
View File
@@ -0,0 +1,97 @@
#include "sorters/ShellSorter.hpp"
ShellSorter::ShellSorter() {
reset();
}
void ShellSorter::step(Array& array) {
if (finished_) return;
if (n_ == 0) {
n_ = array.getSize();
gap_ = n_ / 2;
i_ = gap_;
phase_ = Phase::COMPARING;
}
if (gap_ == 0) {
array.resetStates();
for (int k = 0; k < n_; ++k) {
array.setState(k, Array::State::SORTED);
}
finished_ = true;
return;
}
if (phase_ == Phase::COMPARING) {
if (i_ >= n_) {
gap_ /= 2;
i_ = gap_;
if (gap_ == 0) {
array.resetStates();
for (int k = 0; k < n_; ++k) {
array.setState(k, Array::State::SORTED);
}
finished_ = true;
}
return;
}
temp_ = array.getValue(i_);
j_ = i_;
phase_ = Phase::SHIFTING;
} else if (phase_ == Phase::SHIFTING) {
if (j_ >= gap_) {
array.resetStates();
array.setState(j_, Array::State::COMPARE);
array.setState(j_ - gap_, Array::State::COMPARE);
array.incrementComparisons();
if (array.getValue(j_ - gap_) > temp_) {
array.setState(j_, Array::State::SWAP);
array.setState(j_ - gap_, Array::State::SWAP);
array.setValue(j_, array.getValue(j_ - gap_));
array.incrementSwaps();
j_ -= gap_;
} else {
phase_ = Phase::PLACING;
}
} else {
phase_ = Phase::PLACING;
}
} else if (phase_ == Phase::PLACING) {
array.resetStates();
array.setState(j_, Array::State::SWAP);
array.setValue(j_, temp_);
i_++;
phase_ = Phase::COMPARING;
}
}
bool ShellSorter::isFinished() const {
return finished_;
}
std::string ShellSorter::getName() const {
return "Shell Sort";
}
std::string ShellSorter::getTimeComplexity() const {
return "O(n log^2 n)";
}
std::string ShellSorter::getSpaceComplexity() const {
return "O(1)";
}
void ShellSorter::reset() {
n_ = 0;
gap_ = 0;
i_ = 0;
j_ = 0;
temp_ = 0.0f;
finished_ = false;
phase_ = Phase::COMPARING;
}