vcglib/apps/nexus/tristripper/heap_array.h

275 lines
6.8 KiB
C++

// heap_array.h: interface for the heap_array class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautré.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautré
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Semi-dynamic indexed heap
// *************************
//
// Current version: 1.00 BETA 1 (24/10/2002)
//
// Comment: heap_array acts like a normal heap, you can push elements
// and then get the greatest one.
// However you cannot push any more element once an element
// has been removed (pop, erase, etc...).
// Elements can be modified after they've been pushed into
// the heap via their indice.
//
// History: -
//
//////////////////////////////////////////////////////////////////////
#pragma once
// namespace common_structures
namespace common_structures {
template <class T, class CmpT = std::less<T> >
class heap_array
{
public:
struct heap_is_locked { };
// heap_array main interface. Pre = PreCondition, Post = PostCondition
heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked())
void clear(); // Post: ((size() == 0) && ! locked())
void reserve(size_t Size);
size_t size() const;
bool empty() const;
bool locked() const;
bool removed(size_t i) const; // Pre: (valid(i))
bool valid(size_t i) const;
const T & top() const; // Pre: (! empty())
const T & peek(size_t i) const; // Pre: (valid(i) && ! removed(i))
const T & operator [] (size_t i) const; // Pre: (valid(i) && ! removed(i))
size_t push(const T & Elem); // Pre: (! locked()) else throw (heap_is_locked)
void pop(); // Pre: (! empty()) Post: (locked())
void erase(size_t i); // Pre: (valid(i) && ! removed(i)) Post: (locked())
void update(size_t i, const T & Elem); // Pre: (valid(i) && ! removed(i)) Post: (locked())
protected:
struct linker {
linker(const T & Elem, size_t i) : m_Elem(Elem), m_Indice(i) { }
T m_Elem;
size_t m_Indice;
};
typedef std::vector<linker> linked_heap;
typedef std::vector<size_t> finder;
void Adjust(size_t i);
void Swap(size_t a, size_t b);
bool Less(const linker & a, const linker & b) const;
linked_heap m_Heap;
finder m_Finder;
CmpT m_Compare;
bool m_Locked;
};
//////////////////////////////////////////////////////////////////////////
// heap_indexed Inline functions
//////////////////////////////////////////////////////////////////////////
template <class T, class CmpT>
inline void heap_array<T, CmpT>::clear() {
m_Heap.clear();
m_Finder.clear();
m_Locked = false;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::empty() const {
return m_Heap.empty();
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::locked() const {
return m_Locked;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::reserve(size_t Size) {
m_Heap.reserve(Size);
m_Finder.reserve(Size);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::size() const {
return m_Heap.size();
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::top() const {
// Debug check to ensure heap is not empty
assert(! empty());
return m_Heap.front().m_Elem;
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::peek(size_t i) const {
// Debug check to ensure element is still present
assert(! removed(i));
return (m_Heap[m_Finder[i]].m_Elem);
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::operator [] (size_t i) const {
return peek(i);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::pop() {
m_Locked = true;
// Debug check to ensure heap is not empty
assert(! empty());
Swap(0, size() - 1);
m_Heap.pop_back();
Adjust(0);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::push(const T & Elem) {
if (m_Locked)
throw heap_is_locked();
size_t Id = size();
m_Finder.push_back(Id);
m_Heap.push_back(linker(Elem, Id));
Adjust(Id);
return Id;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::erase(size_t i) {
m_Locked = true;
// Debug check to ensure element is still present
assert(! removed(i));
size_t j = m_Finder[i];
Swap(j, size() - 1);
m_Heap.pop_back();
Adjust(j);
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::removed(size_t i) const {
return (m_Finder[i] >= m_Heap.size());
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::valid(size_t i) const {
return (i < m_Finder.size());
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::update(size_t i, const T & Elem) {
// Debug check to ensure element is still present
assert(! removed(i));
size_t j = m_Finder[i];
m_Heap[j].m_Elem = Elem;
Adjust(j);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Adjust(size_t i) {
size_t j;
// Check the upper part of the heap
for (j = i; (j > 0) && (Less(m_Heap[(j - 1) / 2], m_Heap[j])); j = ((j - 1) / 2))
Swap(j, (j - 1) / 2);
// Check the lower part of the heap
for (i = j; (j = 2 * i + 1) < size(); i = j) {
if ((j + 1 < size()) && (Less(m_Heap[j], m_Heap[j + 1])))
++j;
if (Less(m_Heap[j], m_Heap[i]))
return;
Swap(i, j);
}
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Swap(size_t a, size_t b) {
std::swap(m_Heap[a], m_Heap[b]);
// use (size_t &) to get rid of a bogus compile warning
(size_t &) (m_Finder[(m_Heap[a].m_Indice)]) = a;
(size_t &) (m_Finder[(m_Heap[b].m_Indice)]) = b;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const {
return m_Compare(a.m_Elem, b.m_Elem);
}
}; // namespace common_structures