[init]
This commit is contained in:
commit
63825f1849
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
build
|
||||||
|
cmake-build-*
|
||||||
|
.idea
|
||||||
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.default.compilerPath": "/usr/bin/gcc",
|
||||||
|
"files.associations": {
|
||||||
|
"span": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
87
CMakeLists.txt
Executable file
87
CMakeLists.txt
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
project(AlgEng-Uebung)
|
||||||
|
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
add_executable(Sorter framework/runner.cpp
|
||||||
|
src/container.cpp src/container.hpp
|
||||||
|
src/sorter.cpp src/sorter.hpp)
|
||||||
|
target_link_libraries(Sorter PUBLIC Threads::Threads)
|
||||||
|
|
||||||
|
target_compile_features(Sorter PRIVATE cxx_std_20)
|
||||||
|
|
||||||
|
find_package(
|
||||||
|
Python
|
||||||
|
COMPONENTS Interpreter
|
||||||
|
REQUIRED)
|
||||||
|
|
||||||
|
set(result_file ${CMAKE_CURRENT_LIST_DIR}/result.txt)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${result_file}
|
||||||
|
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/eval.py run
|
||||||
|
--build-dir ${CMAKE_CURRENT_BINARY_DIR} ${result_file}
|
||||||
|
COMMENT "Running experiment"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
DEPENDS Sorter eval.py)
|
||||||
|
|
||||||
|
add_custom_target(run DEPENDS ${result_file})
|
||||||
|
|
||||||
|
set(plot_file ${CMAKE_CURRENT_LIST_DIR}/plot.pdf)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${plot_file}
|
||||||
|
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/eval.py plot
|
||||||
|
${result_file}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
COMMENT "Plotting results"
|
||||||
|
DEPENDS ${result_file} eval.py)
|
||||||
|
|
||||||
|
add_custom_target(plot DEPENDS ${plot_file})
|
||||||
|
|
||||||
|
set(submission_file ${CMAKE_CURRENT_LIST_DIR}/submission.zip)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${submission_file}
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E tar cv ${submission_file} --format=zip
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/container.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/container.hpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/sorter.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/sorter.hpp
|
||||||
|
${plot_file}
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/description.md
|
||||||
|
COMMENT "Creating submission"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
DEPENDS ${plot_file} ${CMAKE_CURRENT_LIST_DIR}/description.md)
|
||||||
|
|
||||||
|
|
||||||
|
add_custom_target(submission DEPENDS ${submission_file})
|
||||||
|
|
||||||
|
set(dist_file_list
|
||||||
|
CMakeLists.txt
|
||||||
|
CMakePresets.json
|
||||||
|
description.md
|
||||||
|
eval.py
|
||||||
|
framework/runner.cpp
|
||||||
|
Pipfile
|
||||||
|
README.md
|
||||||
|
src/container.cpp
|
||||||
|
src/container.hpp
|
||||||
|
src/sorter.cpp
|
||||||
|
src/sorter.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(framework_dist_file "ae-sorting.zip")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${framework_dist_file}
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND} -E tar cv ${framework_dist_file} --format=zip
|
||||||
|
${dist_file_list}
|
||||||
|
COMMENT "Creating framework dist archive"
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(framework DEPENDS ${framework_dist_file})
|
||||||
19
CMakePresets.json
Executable file
19
CMakePresets.json
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buildPresets": [
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"configurePreset": "release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12
Pipfile
Executable file
12
Pipfile
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
matplotlib = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.12"
|
||||||
44
README.md
Executable file
44
README.md
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
# Programming exercise
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
- UNIX-like OS, or WSL for Windows
|
||||||
|
- `gcc`, `g++` >= 11
|
||||||
|
- `CMake` >= 3.19 [^1]
|
||||||
|
- `python` and the package `matplotlib` (alternatively, you can use `pipenv` [^2] and the provided `Pipfile`)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Implement your solution in `src/`, and describe it in `description.md`.
|
||||||
|
You can also adjust the evaluation code in `framework/` and `eval.py`, if you want.
|
||||||
|
|
||||||
|
1. Compile your code using
|
||||||
|
|
||||||
|
```console
|
||||||
|
cmake --preset release
|
||||||
|
cmake --build --preset release
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the experiment via `eval.py run`. The output will be written to `result.txt`.
|
||||||
|
```console
|
||||||
|
python ./eval.py run result.txt
|
||||||
|
# or
|
||||||
|
cmake --build --preset release --target run
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create a plot via `eval.py plot`. This will create a PDF file named `plot.pdf`.
|
||||||
|
```console
|
||||||
|
python ./eval.py plot results.txt
|
||||||
|
# or
|
||||||
|
cmake --build --preset release --target plot
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Describe your solution in `description.md`.
|
||||||
|
|
||||||
|
5. Using `cmake`, create `submission.zip`, which will contain your source code, description and plots.
|
||||||
|
```console
|
||||||
|
cmake --build --preset release --target submission
|
||||||
|
```
|
||||||
|
|
||||||
|
[^1]: https://cmake.org/download/
|
||||||
|
[^2]: https://pipenv.pypa.io/en/latest/
|
||||||
|
|
||||||
2
description.md
Executable file
2
description.md
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
# Description of your algorithm/datastructure
|
||||||
|
Describe/explain your design decisions briefly (~10 sentences).
|
||||||
89
eval.py
Executable file
89
eval.py
Executable file
@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def run_experiment(output_file, build_dir):
|
||||||
|
# The number of threads is not currently used, it's just here in case you want to parallelize your code.
|
||||||
|
for threads in [1]:
|
||||||
|
for size in [1e2, 1e3, 1e4 + 1, 1e5, 1e6 - 1, 1e7]:
|
||||||
|
print("Measuring p=" + str(threads) + " n=" + str(size))
|
||||||
|
executable = Path(build_dir) / "Sorter"
|
||||||
|
returncode = subprocess.call([executable, str(size), str(threads)], stdout=output_file)
|
||||||
|
if returncode != 0:
|
||||||
|
print("Program crashed")
|
||||||
|
|
||||||
|
def make_plot(result_file):
|
||||||
|
plots = dict()
|
||||||
|
maxDuration = 0
|
||||||
|
for line in result_file:
|
||||||
|
if line.startswith("RESULT"):
|
||||||
|
line = line[len("RESULT "):].strip()
|
||||||
|
parts = line.split()
|
||||||
|
measurement = {}
|
||||||
|
for part in parts:
|
||||||
|
key, value = part.split('=')
|
||||||
|
measurement[key] = value
|
||||||
|
|
||||||
|
n = int(round(int(measurement["n"]), -1))
|
||||||
|
t = int(measurement["t"])
|
||||||
|
name = measurement["name"]
|
||||||
|
durationNanoseconds = int(measurement["durationNanoseconds"])
|
||||||
|
constructorNanoseconds = int(measurement["constructorNanoseconds"])
|
||||||
|
|
||||||
|
if t not in plots:
|
||||||
|
plots[t] = dict()
|
||||||
|
if name not in plots[t]:
|
||||||
|
plots[t][name] = list()
|
||||||
|
plots[t][name + " (constructor)"] = list()
|
||||||
|
plots[t][name].append((n, durationNanoseconds / n))
|
||||||
|
plots[t][name + " (constructor)"].append((n, constructorNanoseconds / n))
|
||||||
|
maxDuration = max(maxDuration, max(durationNanoseconds, constructorNanoseconds))
|
||||||
|
|
||||||
|
fig, axs = plt.subplots(len(plots))
|
||||||
|
|
||||||
|
for i, t in enumerate(plots):
|
||||||
|
if len(plots) > 1:
|
||||||
|
axs[i].set_title(f"#p={t}")
|
||||||
|
for name in plots[t]:
|
||||||
|
axs[i].plot(*zip(*plots[t][name]), label=name, marker='x')
|
||||||
|
axs[i].plot(*zip(*plots[t][name + " (constructor)"]), label=name + " (constructor)", marker='+')
|
||||||
|
axs[i].set_xscale('log')
|
||||||
|
else:
|
||||||
|
axs.plot(*zip(*plots[t][name]), label=name, marker='x')
|
||||||
|
axs.plot(*zip(*plots[t][name + " (constructor)"]), label=name + " (constructor)", marker='+')
|
||||||
|
axs.set_xscale('log')
|
||||||
|
|
||||||
|
if len(plots) > 1:
|
||||||
|
for ax in axs.flat:
|
||||||
|
ax.set(xlabel='n', ylabel='Running time per element (ns)')
|
||||||
|
ax.legend()
|
||||||
|
else:
|
||||||
|
axs.set(xlabel='n', ylabel='Running time per element (ns)')
|
||||||
|
axs.legend()
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
|
||||||
|
plt.savefig("plot.pdf")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='evaluation tools')
|
||||||
|
# subcommands run and plot
|
||||||
|
subparsers = parser.add_subparsers(dest='command')
|
||||||
|
run_parser = subparsers.add_parser('run')
|
||||||
|
run_parser.add_argument('output_file', type=argparse.FileType('w'), help='output file')
|
||||||
|
run_parser.add_argument("--build-dir", default="build", help="build directory")
|
||||||
|
plot_parser = subparsers.add_parser('plot')
|
||||||
|
plot_parser.add_argument('result_file', type=argparse.FileType('r'), help='result file')
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.command == 'run':
|
||||||
|
run_experiment(args.output_file, args.build_dir)
|
||||||
|
elif args.command == 'plot':
|
||||||
|
make_plot(args.result_file)
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
103
framework/runner.cpp
Executable file
103
framework/runner.cpp
Executable file
@ -0,0 +1,103 @@
|
|||||||
|
#include "../src/container.hpp"
|
||||||
|
#include "../src/sorter.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
auto generate_uniform(std::size_t n) {
|
||||||
|
std::vector<std::uint64_t> input(n);
|
||||||
|
|
||||||
|
std::mt19937 gen(n);
|
||||||
|
std::uniform_int_distribution<std::uint64_t> dist;
|
||||||
|
std::ranges::generate(input, [&] { return dist(gen); });
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runExperiment(std::string_view name,
|
||||||
|
auto container_factory,
|
||||||
|
auto sort_func,
|
||||||
|
int argc, char **argv) {
|
||||||
|
std::size_t n = 1e6;
|
||||||
|
std::size_t num_threads = 1;
|
||||||
|
|
||||||
|
if (argc == 3) {
|
||||||
|
n = std::stol(argv[1]);
|
||||||
|
num_threads = std::stoi(argv[2]);
|
||||||
|
} else {
|
||||||
|
// The number of threads is just here in case you want to parallelize your code.
|
||||||
|
// It's not currently used.
|
||||||
|
std::cerr << "Number of threads not specified!\n";
|
||||||
|
std::cerr << "Usage: " << argv[0] << " <n> <num_threads>\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto input = generate_uniform(n);
|
||||||
|
|
||||||
|
const auto solution = [&] {
|
||||||
|
auto v = input;
|
||||||
|
std::ranges::sort(v);
|
||||||
|
return v;
|
||||||
|
}();
|
||||||
|
|
||||||
|
int iterations = 0;
|
||||||
|
long totalNanoseconds = 0;
|
||||||
|
long totalNanosecondsFactory = 0;
|
||||||
|
int maxIterations = 10'000;
|
||||||
|
|
||||||
|
while (totalNanoseconds < 1000 * 1000) {
|
||||||
|
if (iterations >= maxIterations) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point ctor = std::chrono::steady_clock::now();
|
||||||
|
auto to_sort = container_factory(input);
|
||||||
|
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||||
|
sort_func(to_sort);
|
||||||
|
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||||
|
totalNanoseconds +=
|
||||||
|
std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin)
|
||||||
|
.count();
|
||||||
|
totalNanosecondsFactory +=
|
||||||
|
std::chrono::duration_cast<std::chrono::nanoseconds>(begin - ctor)
|
||||||
|
.count();
|
||||||
|
iterations++;
|
||||||
|
|
||||||
|
if (not std::ranges::equal(to_sort.to_view(), solution)) {
|
||||||
|
std::cerr << "Output of " << name << " is not correct!\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "RESULT"
|
||||||
|
<< " name=" << name << " n=" << n << " t=" << num_threads
|
||||||
|
<< " iterations=" << iterations
|
||||||
|
<< " durationNanoseconds=" << totalNanoseconds / iterations
|
||||||
|
<< " totalDurationNanoseconds=" << totalNanoseconds
|
||||||
|
<< " constructorNanoseconds=" << totalNanosecondsFactory / iterations
|
||||||
|
<< " totalConstructorNanoseconds=" << totalNanosecondsFactory
|
||||||
|
<< '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
runExperiment("sort",
|
||||||
|
[](const auto& data) {
|
||||||
|
return ae::container(data);
|
||||||
|
},
|
||||||
|
[](ae::container& data) {
|
||||||
|
ae::sorter{}.sort(data);
|
||||||
|
}, argc, argv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
6
result.txt
Normal file
6
result.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
RESULT name=sort n=100 t=1 iterations=1530 durationNanoseconds=653 totalDurationNanoseconds=1000022 constructorNanoseconds=233 totalConstructorNanoseconds=356900
|
||||||
|
RESULT name=sort n=1000 t=1 iterations=76 durationNanoseconds=13288 totalDurationNanoseconds=1009961 constructorNanoseconds=598 totalConstructorNanoseconds=45480
|
||||||
|
RESULT name=sort n=10001 t=1 iterations=3 durationNanoseconds=465803 totalDurationNanoseconds=1397411 constructorNanoseconds=26923 totalConstructorNanoseconds=80770
|
||||||
|
RESULT name=sort n=100000 t=1 iterations=1 durationNanoseconds=6197415 totalDurationNanoseconds=6197415 constructorNanoseconds=790010 totalConstructorNanoseconds=790010
|
||||||
|
RESULT name=sort n=999999 t=1 iterations=1 durationNanoseconds=67456368 totalDurationNanoseconds=67456368 constructorNanoseconds=5975124 totalConstructorNanoseconds=5975124
|
||||||
|
RESULT name=sort n=10000000 t=1 iterations=1 durationNanoseconds=756668481 totalDurationNanoseconds=756668481 constructorNanoseconds=55741740 totalConstructorNanoseconds=55741740
|
||||||
23
src/container.cpp
Executable file
23
src/container.cpp
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#include "container.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
namespace ae {
|
||||||
|
|
||||||
|
container::container(std::span<const element_type> data) {
|
||||||
|
// TODO create your datastructure from the given data
|
||||||
|
|
||||||
|
// The code below is a simple example splitting the data into 16 blocks,
|
||||||
|
// but you may find other options better suited for your sorting algorithm.
|
||||||
|
constexpr std::size_t num_blocks = 16;
|
||||||
|
const std::ptrdiff_t elements_per_block = (data.size() + num_blocks - 1) / num_blocks;
|
||||||
|
|
||||||
|
for (auto first = data.begin(); first < data.end();) {
|
||||||
|
const auto last = (data.end() - first) < elements_per_block ? data.end() : first + elements_per_block;
|
||||||
|
placeholder_.emplace_back(first, last);
|
||||||
|
first = last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ae
|
||||||
36
src/container.hpp
Executable file
36
src/container.hpp
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <ranges>
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ae {
|
||||||
|
|
||||||
|
class sorter;
|
||||||
|
|
||||||
|
class container {
|
||||||
|
friend class sorter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using element_type = std::uint64_t;
|
||||||
|
|
||||||
|
explicit container(std::span<const element_type> data);
|
||||||
|
|
||||||
|
// TODO You may also add additional functions (or data members).
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TODO define your data layout
|
||||||
|
// Your datastructure should consist of multiple blocks of data, which don't
|
||||||
|
// necessarily have to be vectors.
|
||||||
|
std::vector<std::vector<element_type>> placeholder_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] auto to_view() const {
|
||||||
|
return std::views::join(placeholder_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ae
|
||||||
35
src/sorter.cpp
Executable file
35
src/sorter.cpp
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#include "sorter.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace ae {
|
||||||
|
|
||||||
|
void sorter::sort(container& data) {
|
||||||
|
// TODO Implement your sorting algorithm
|
||||||
|
for (auto i = 1uz; i < data.placeholder_.size(); ++i) {
|
||||||
|
std::ranges::copy(data.placeholder_[i], std::back_inserter(data.placeholder_[0]));
|
||||||
|
data.placeholder_[i].clear();
|
||||||
|
}
|
||||||
|
std::ranges::sort(data.placeholder_[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sorter::msd_inplace_radix_sort(std::span<container::element_type> range, size_t passes, size_t digit) {
|
||||||
|
if (digit == passes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lower = std::begin(range);
|
||||||
|
auto upper = std::end(range);
|
||||||
|
|
||||||
|
for (auto element = lower; element < std::end(range);) {
|
||||||
|
// Mask out the <digit>-last bit and check if it is set
|
||||||
|
if ((*element & (1uz << sizeof(container::element_type) * 8 - digit))) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ae
|
||||||
15
src/sorter.hpp
Executable file
15
src/sorter.hpp
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "container.hpp"
|
||||||
|
|
||||||
|
namespace ae {
|
||||||
|
|
||||||
|
class sorter {
|
||||||
|
public:
|
||||||
|
void sort(container& data);
|
||||||
|
|
||||||
|
// TODO You may add additional functions or data members to the sorter.
|
||||||
|
void msd_inplace_radix_sort(std::span<container::element_type> range, size_t passes, size_t digit = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ae
|
||||||
Loading…
x
Reference in New Issue
Block a user