Skip to content

Instantly share code, notes, and snippets.

@goldsborough
Created November 3, 2015 23:19
Show Gist options
  • Save goldsborough/1e42a0e12f120a435a37 to your computer and use it in GitHub Desktop.
Save goldsborough/1e42a0e12f120a435a37 to your computer and use it in GitHub Desktop.
Some heap practice.
template<typename T>
class MaxHeap
{
public:
using size_t = std::size_t;
static const std::size_t minimum_capacity;
MaxHeap(std::size_t capacity = minimum_capacity)
: _data(new T[capacity])
, _size(0)
, _capacity(capacity)
{ }
MaxHeap(const std::initializer_list<T>& list,
std::size_t capacity = minimum_capacity)
: _size(0)
{
_capacity = std::max(capacity, list.size());
_data = new T[_capacity];
for (const auto& item : list) insert(item);
}
MaxHeap(const MaxHeap& other)
: _data(new T[other._size])
, _size(other._size)
, _capacity(other._capacity)
{
std::copy(other._data, other._data + _size, _data);
}
MaxHeap(MaxHeap&& other) noexcept
: MaxHeap()
{
swap(other);
}
MaxHeap& operator=(MaxHeap other)
{
swap(other);
return *this;
}
void swap(MaxHeap& other) noexcept
{
// Enable ADL
using std::swap;
swap(_data, other._data);
swap(_size, other._size);
swap(_capacity, other._capacity);
}
friend void swap(MaxHeap& first, MaxHeap& second) noexcept
{
first.swap(second);
}
~MaxHeap()
{
delete [] _data;
}
void insert(const T& item)
{
if (++_size == _capacity) _resize();
_data[_size] = item;
_swim(_size);
}
const T& top()
{
if (is_empty())
{
throw std::out_of_range("No item to pop!");
}
return _data[1];
}
T pop()
{
if (is_empty())
{
throw std::out_of_range("No item to pop!");
}
auto item = _data[1];
_swap(1, _size);
if (--_size == _capacity/4) _resize();
_sink(1);
return item;
}
void clear()
{
delete [] _data;
_size = 0;
_capacity = minimum_capacity;
_data = new T[_capacity];
}
size_t size() const
{
return _size;
}
bool is_empty() const
{
return _size == 0;
}
private:
constexpr inline size_t _left(size_t index) const
{
return 2 * index;
}
constexpr inline size_t _right(size_t index) const
{
return 2 * index + 1;
}
constexpr inline size_t _parent(size_t index) const
{
return (index == 1) ? 1 : index/2;
}
void _swim(size_t index)
{
auto parent = _parent(index);
while (_data[parent] < _data[index])
{
_swap(parent, index);
index = parent;
parent = _parent(parent);
}
}
void _sink(size_t index)
{
while (index < _size)
{
auto left = _left(index);
if (left > _size) break;
auto child = _right(index);
if (child > _size || _data[left] > _data[child]) child = left;
if (_data[child] > _data[index]) _swap(child, index);
else break;
index = child;
}
}
inline void _swap(size_t first, size_t second)
{
std::swap(_data[first], _data[second]);
}
void _resize()
{
size_t new_capacity = std::max(minimum_capacity, _size * 2);
auto old = _data;
_data = new T[new_capacity];
std::copy(old, old + _size, _data);
_capacity = new_capacity;
delete [] old;
}
T* _data;
size_t _size;
size_t _capacity;
};
template<typename T>
const std::size_t MaxHeap<T>::minimum_capacity = 10;
template<typename Iterator>
class HeapSort
{
public:
void operator()(Iterator begin, Iterator end)
{
auto i = begin;
std::advance(i, std::distance(begin, end)/2);
for (auto stop = std::prev(begin); i != stop; --i)
{
_sink(begin, end, i);
}
for (--end; end != begin; --end)
{
std::swap(*begin, *end);
_sink(begin, end, begin);
}
}
private:
constexpr inline Iterator _left(Iterator begin, Iterator iterator) const
{
std::advance(iterator, std::distance(begin, iterator));
return iterator;
}
constexpr inline Iterator _right(Iterator begin, Iterator iterator) const
{
iterator = _left(begin, iterator);
return ++iterator;
}
void _sink(Iterator begin, Iterator end, Iterator iterator)
{
while (iterator < end)
{
auto left = _left(begin, iterator);
if (left >= end) break;
auto child = _right(begin, iterator);
if (child >= end || *left > *child) child = left;
if (*child > *iterator)
{
std::swap(*child, *iterator);
}
else break;
iterator = child;
}
}
};
template<typename Iterator>
void heap_sort(Iterator begin, Iterator end)
{
HeapSort<Iterator> sort;
sort(begin, end);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment