Cod sursa(job #2460184)

Utilizator andreioneaAndrei Onea andreionea Data 23 septembrie 2019 01:58:36
Problema Sortare prin comparare Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.13 kb
#include <fstream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <functional>

constexpr auto SMALL_SORT_THRESHOLD = 500;

void make_heap(std::vector<uint32_t>& v, uint32_t fst, uint32_t lst)
{
    const auto size = lst - fst;
    if (size <= 1) {
        return;
    }
    if ((size == 2)) {
        std::swap(v[fst], v[fst + (v[fst] > v[fst + 1])]);
        return;
    }
    for (auto i = size / 2; i >= 1; --i) {
        for (auto j = i; j <= (size / 2);) {
            const auto leftIdx = j * 2;
            const auto rightIdx = leftIdx + 1;
            std::reference_wrapper<uint32_t> leftChild  = std::ref(v[leftIdx + fst - 1]);
            std::reference_wrapper<uint32_t> rightChild = std::ref(v[rightIdx + fst - 1]);

            auto bestIdx = j;
            std::reference_wrapper<uint32_t> best = std::ref(v[j + fst - 1]);
            std::reference_wrapper<uint32_t> curr = best;
            if (leftChild < best) {
                bestIdx = leftIdx;
                best = leftChild;
            }
            if (rightChild < best) {
                bestIdx = rightIdx;
                best = rightChild;
            }
            if (bestIdx == j)
                break;
            std::swap(best.get(), curr.get());
            j = bestIdx;
        } 
    }
    if (size & 1) {
        for (auto idx = size; idx > 1; idx /= 2) {
            auto currentIdx = idx + fst - 1;
            auto parentIdx = idx / 2 + fst - 1;
            if (v[currentIdx] < v[parentIdx]) {
                std::swap(v[currentIdx], v[parentIdx]);
            } else {
                return;
            }
        }
    }
}

void small_sort(std::vector<uint32_t>& v, uint32_t fst, uint32_t lst)
{
    // Make a heap, then use selection sort
    make_heap(v, fst, lst + 1);
    for (size_t i = fst + 2; i <= lst; ++i) {
        uint32_t bubble = v[i];
        uint32_t right = i;
        uint32_t left = right;
        while (v[--left] > bubble)
        {
            v[right--] = v[left];
        }
        v[right] = bubble;
    }
}

void qsort(std::vector<uint32_t>& v, uint32_t left, uint32_t right) {
    if (right <= left)
        return;
    if ((right - left + 1) <= SMALL_SORT_THRESHOLD) {
        small_sort(v, left, right);
        return;
    }
    const auto mid = (left + right) / 2;
    const auto rnd = left + rand() % (right - left);
    std::swap(v[mid], v[rnd]);
    const auto pivot = v[mid];
    auto i1 = left;
    auto i2 = right;
    while (true) {
        while((v[i1] < pivot)) ++i1;
        while((v[i2] > pivot))  --i2;
        if (i1 <= i2) {
            std::swap(v[i1], v[i2]);
            ++i1;
            --i2;
        } else {
            break;
        }
    }
    qsort(v, left, i2);
    qsort(v, i1, right);
}

int main()
{
    std::srand(std::time(nullptr));
    std::ifstream fin("algsort.in");
    std::ofstream fout("algsort.out");
    std::vector<uint32_t> v;
    uint32_t n;
    fin >> n;
    v.reserve(n);
    for (uint32_t i = 0; i < n; ++i) {
        uint32_t x;
        fin >> x;
        v.push_back(x);
    }
    qsort(v, 0, v.size() - 1);
    for (const auto x : v) {
        fout << x << " ";
    }
    return 0;
}