MVector.hpp
#ifndef MVector_hpp
#define MVector_hpp
#include <vector>
#include <cassert>
#include <ostream>
#include <cstdlib>
#include <ctime>
// Class that represents a mathematical vector
class MVector
{
public:
// constructors
MVector() {}
explicit MVector(int n) : v(n) {}
MVector(int n, double x) : v(n, x) {}
MVector(std::initializer_list<double> l) : v(l) {}
// access element (lvalue) (see example sheet 5, q5.6)
double &operator[](size_t index)
{
// assert(index >=0 && index < size());
return v[index];
}
// access element (rvalue) (see example sheet 5, q5.7)
double operator[](size_t index) const {
// assert(index >= 0 && index < size());
return v[index];
}
size_t size() const { return v.size(); } // number of elements
void swap(int i, int j) {
auto temp = v[i];
v[i] = v[j];
v[j] = temp;
}
void initialise_random(double xmin, double xmax) {
std::srand(std::time(NULL));
size_t s = v.size();
for (size_t i=0; i<s; i++) {
v[i] = xmin + (xmax-xmin) * rand()/static_cast<double>(RAND_MAX);
}
}
friend std::ostream& operator <<(std::ostream& stream, const MVector v) {
for (size_t i = 0; i < v.size() - 1; ++i) {
stream << v[i] << ", ";
}
stream << v[v.size() - 1] << std::endl;
return stream;
}
private:
std::vector<double> v;
};
#endif /* MVector_hpp */
sort.hpp
#ifndef sort_h
#define sort_h
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <cmath>
#include "MVector.hpp"
// bubble sort
namespace BubbleSort{
void bubble(MVector &v) {
const size_t n = v.size();
for (int i=0; i<n; ++i) {
for (int j=0; j<n; ++j) {
if (v[i] < v[j]) {
v.swap(i, j);
}
}
}
};
} // namespace BubbleSort
// quick sort
namespace QuickSort{
int partition(MVector &v, int low, int high) {
auto pivot = v[high];
int idx = low - 1;
for (int j = low; j < high; j++) {
if (v[j] <= pivot) {
++idx;
v.swap(idx, j);
}
}
v.swap(idx + 1, high);
return idx + 1;
}
void quick_recursive(MVector &v, int start, int end) {
if (start < end) {
auto i = partition(v, start, end);
quick_recursive(v, start, i-1);
quick_recursive(v, i+1, end);
}
}
void quick(MVector &v) { quick_recursive(v, 0, v.size()-1); }
} // namespace QuickSort
// heap sort
namespace HeapSort {
void heap_from_root(MVector& v, int i, int n) {
int largest = i;
int l = 2 * i + 1, r = 2 * i + 2;
if (l < n && v[l] > v[largest]) {
largest = l;
}
if (r < n && v[r] > v[largest]) {
largest = r;
}
if (largest != i) {
v.swap(largest, i);
heap_from_root(v, largest, n);
}
}
void heap(MVector &v) {
const int n = v.size();
for (int i = n / 2 - 1; i >= 0; --i) {
heap_from_root(v, i, n);
}
for (int i = n - 1; i > 0; --i) {
v.swap(0, i);
heap_from_root(v, 0, i);
}
}
} // namespace HeapSort
enum SortMethod {
bubble,
quick,
heap
};
void Benchmark(std::vector<std::vector<MVector>> Vecs, const std::string path, const SortMethod &method) {
// TODO: modify output stream
std::fstream file_stream;
file_stream.open(path, std::fstream::out);
file_stream << std::fixed;
file_stream << std::setprecision(6);
file_stream << "size,"
<< "time"
<< std::endl;
size_t iter = Vecs[0].size();
for (auto &Vec : Vecs) {
if (method == bubble && Vec[0].size() > 5000) continue;
double t = 0.0;
auto t1 = std::clock();
for (auto &v : Vec){
switch (method) {
case bubble:
BubbleSort::bubble(v);
break;
case quick:
QuickSort::quick(v);
break;
case heap:
HeapSort::heap(v);
break;
}
t += (double) (std::clock() - t1) / CLOCKS_PER_SEC;
}
file_stream << Vec[0].size() << ','
<< t / iter << std::endl;
}
file_stream.close();
}
#endif /* sort_h */
main.hpp
#include <unordered_map>
#include "MVector.hpp"
#include "sort.hpp"
void WriteMVec(const std::string &file_path, const MVector &v) {
std::fstream file_stream;
file_stream.open(file_path, std::fstream::out);
file_stream << v;
file_stream.close();
}
// for Task 4.2.1 & Task 4.2.2
void T() {
MVector v(100000);
v.initialise_random(1, 100000);
std::cout << v;
WriteMVec("Mvec.txt", v); // change for the path of output
};
int main(int argc, const char * argv[]) {
// T(); // for Task 4.2.1 & Task 4.2.2
// Task 4.2.3 begins
// create test cases with various lengths
int iter = 10;
std::vector<int> test_sizes;
for (int i = 100; i <= 20000; i += 100) {
test_sizes.push_back(i);
}
// randomly initialise vecs
std::vector<std::vector<MVector>> Vecs;
for (auto &size : test_sizes) {
std::vector<MVector> Vec(iter);
for (int i=0; i<iter; ++i) {
MVector v(size);
v.initialise_random(0, 1000);
Vec[i] = std::move(v);
}
Vecs.emplace_back(Vec);
}
std::string path = "./"; // change for your own
std::unordered_map<SortMethod, std::string> method = {
{quick, "quick"},
{heap, "heap"},
{bubble, "bubble"}
};
// Benchmark time costs
for (auto &[k, v] : method) {
auto f = path + v + ".txt";
std::cout << f << std::endl;
Benchmark(Vecs, f, k);
}
// Task 4.3.2 ends
}
subplot.py
import os
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
def plot():
output_file = filter(lambda x: x.endswith(".txt") and not x.startswith("MV"), os.listdir())
for i, f in enumerate(output_file):
fig, ax = plt.subplots(1, 1, figsize=(10, 7))
with open(f, 'r') as file:
lines = []
for l, line in enumerate(file.readlines()):
if l == 0: continue
lines.append(list(map(float, line.split(','))))
x, y = zip(*lines)
# if i == 0:
# ax[0, 1].plot(x, y)
# ax[0, 1].set_title(f.split('.')[0])
# elif i == 1:
# ax[1, 0].plot(x, y)
# ax[1, 0].set_title(f.split('.')[0])
# else:
# ax[1, 1].plot(x, y)
# ax[1, 1].set_title(f.split('.')[0])
ax.plot(x, y, label=f.split('.')[0])
ax.set_title(f.split('.')[0])
ax.set_xlabel(r"$n$")
ax.set_ylabel("time/s")
# ax.legend()
# plt.show()
fig.savefig(os.path.join(os.getcwd(), f"{f.split('.')[0]}.png"))
def scatter():
output_file = filter(lambda x: x.endswith(".txt") and not x.startswith("MV"), os.listdir())
for i, f in enumerate(output_file):
fig, ax = plt.subplots(1, 1, figsize=(10, 7))
with open(f, 'r') as file:
lines = []
for l, line in enumerate(file.readlines()):
if l == 0: continue
lines.append(list(map(float, line.split(','))))
x, y = zip(*lines)
# if i == 0:
# ax[0, 1].plot(x, y)
# ax[0, 1].set_title(f.split('.')[0])
# elif i == 1:
# ax[1, 0].plot(x, y)
# ax[1, 0].set_title(f.split('.')[0])
# else:
# ax[1, 1].plot(x, y)
# ax[1, 1].set_title(f.split('.')[0])
sns.regplot(x=np.array(x)**2 if 'bubble' in f else np.array(x)*np.log(np.array(x)), y=np.array(y))
ax.set_title(f.split('.')[0])
ax.set_xlabel(r"$n^2$" if "bubble" in f else r"$nlogn$")
ax.set_ylabel("time/s")
# ax.legend()
# plt.show()
fig.savefig(os.path.join(os.getcwd(), f"{f.split('.')[0]}_scatter.png"))
if __name__ == "__main__":
plot()
scatter()