HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcppMinor

C++ Heap Sort Implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
sortimplementationheap

Problem

Just checking if I could still do it:

#include 
#include 

std::size_t getParent(std::size_t n)
{
    return (n - 1) / 2;
}

template
void heapify(I begin, I end)
{
    std::size_t size    = std::distance(begin, end);
    for(std::size_t loop = 1;loop 
void heapPop(I begin, I end)
{
    I   last = end - 1;
    std::swap(*begin, *last);

    std::size_t size    = std::distance(begin, last);
    std::size_t current = 0;
    while(current  *(begin + child2)) ? child1 : child2;
        }
        else if (child1 
void heap_sort(I begin, I end)
{
    heapify(begin, end);
    while(begin != end)
    {
        heapPop(begin, end);
        --end;
    }
}

int main()
{
    int  data[] = {6,5,3,1,8,7,2,4};
    heap_sort(std::begin(data), std::end(data));
    std::copy(std::begin(data), std::end(data), std::ostream_iterator(std::cout, ", "));
    std::cout << "\n";
}

Solution

The heapify and parentfunctions can be avoided:

You just need the sinking logic that you already implemented. But instead of having current always starting at 0 you can set it as a parameter:

template
void sink(I begin, I end, std::size_t index)
{

    std::size_t size = std::distance(begin, end);
    std::size_t current = index;
    while (current  *(begin + child2)) ? child1 : child2;
        }
        else if (child1 < size)
        {
            goodChild = child1;
        }
        if (*(begin + current) < *(begin + goodChild))
        {
            std::swap(*(begin + current), *(begin + goodChild));
            current = goodChild;
            continue;
        }
        break;
    }
}


Due to the fact that the elements are leafs you can ignore them, so you just need to apply sink

times to build the heap:

template
void heap_sort(I begin, I end)
{
    std::size_t size = std::distance(begin, end);
    for (int i = size / 2 - 1; i > -1; --i) 
    {
        sink(begin, end, i);
    }
    while (begin != --end) 
    {
        std::swap(*begin, *end);
        sink(begin, end, 0);
    }
}


Alternative sink implementation:

IMO this implementation is more concise:

template
void sink(I begin, I end, std::size_t index)
{

    std::size_t size = std::distance(begin, end);
    std::size_t current = index;
    std::size_t child;

    std::less less;

    while ((child = 2 * current + 1) < size)
    {
        I itr_child   = begin + child;
        I itr_current = begin + current;

        if(child < size - 1 
            && less(*itr_child, *(itr_child + 1))
        {
            ++itr_child;
        }

        if (!less(*itr_current, *itr_child))
        {
            break;
        }
        std::swap(*itr_current, *itr_child);
        current = child;
    }
}

Code Snippets

template<typename I>
void sink(I begin, I end, std::size_t index)
{

    std::size_t size = std::distance(begin, end);
    std::size_t current = index;
    while (current < size)
    {
        std::size_t child1 = current * 2 + 1;
        std::size_t child2 = current * 2 + 2;
        std::size_t goodChild = current;

        if (child2 < size)
        {
            goodChild = (*(begin + child1) > *(begin + child2)) ? child1 : child2;
        }
        else if (child1 < size)
        {
            goodChild = child1;
        }
        if (*(begin + current) < *(begin + goodChild))
        {
            std::swap(*(begin + current), *(begin + goodChild));
            current = goodChild;
            continue;
        }
        break;
    }
}
template<typename I>
void heap_sort(I begin, I end)
{
    std::size_t size = std::distance(begin, end);
    for (int i = size / 2 - 1; i > -1; --i) 
    {
        sink(begin, end, i);
    }
    while (begin != --end) 
    {
        std::swap(*begin, *end);
        sink(begin, end, 0);
    }
}
template<typename I>
void sink(I begin, I end, std::size_t index)
{

    std::size_t size = std::distance(begin, end);
    std::size_t current = index;
    std::size_t child;

    std::less<decltype(*begin)> less;

    while ((child = 2 * current + 1) < size)
    {
        I itr_child   = begin + child;
        I itr_current = begin + current;

        if(child < size - 1 
            && less(*itr_child, *(itr_child + 1))
        {
            ++itr_child;
        }

        if (!less(*itr_current, *itr_child))
        {
            break;
        }
        std::swap(*itr_current, *itr_child);
        current = child;
    }
}

Context

StackExchange Code Review Q#130064, answer score: 3

Revisions (0)

No revisions yet.