123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <vector>
- // A min-heap is a binary tree whose nodes have weights and with the
- // constraint that the weight of a parent node is less than or equal to the
- // weights of its children. This data structure may be used as a priority
- // queue. If the std::priority_queue interface suffices for your needs, use
- // that instead. However, for some geometric algorithms, that interface is
- // insufficient for optimal performance. For example, if you have a polyline
- // vertices that you want to decimate, each vertex's weight depends on its
- // neighbors' locations. If the minimum-weight vertex is removed from the
- // min-heap, the neighboring vertex weights must be updated--something that
- // is O(1) time when you store the vertices as a doubly linked list. The
- // neighbors are already in the min-heap, so modifying their weights without
- // removing then from--and then reinserting into--the min-heap requires they
- // must be moved to their proper places to restore the invariant of the
- // min-heap. With std::priority_queue, you have no direct access to the
- // modified vertices, forcing you to search for those vertices, remove them,
- // update their weights, and re-insert them. The min-heap implementation here
- // does support the update without removal and reinsertion.
- //
- // The ValueType represents the weight and it must support comparisons
- // "<" and "<=". Additional information can be stored in the min-heap for
- // convenient access; this is stored as the KeyType. In the (open) polyline
- // decimation example, the KeyType is a structure that stores indices to
- // a vertex and its neighbors. The following code illustrates the creation
- // and use of the min-heap. The Weight() function is whatever you choose to
- // guide which vertices are removed first from the polyline.
- //
- // struct Vertex { int previous, current, next; };
- // int numVertices = <number of polyline vertices>;
- // std::vector<Vector<N, Real>> positions(numVertices);
- // <assign all positions[*]>;
- // MinHeap<Vertex, Real> minHeap(numVertices);
- // std::vector<MinHeap<Vertex, Real>::Record*> records(numVertices);
- // for (int i = 0; i < numVertices; ++i)
- // {
- // Vertex vertex;
- // vertex.previous = (i + numVertices - 1) % numVertices;
- // vertex.current = i;
- // vertex.next = (i + 1) % numVertices;
- // records[i] = minHeap.Insert(vertex, Weight(positions, vertex));
- // }
- //
- // while (minHeap.GetNumElements() >= 2)
- // {
- // Vertex vertex;
- // Real weight;
- // minHeap.Remove(vertex, weight);
- // <consume the 'vertex' according to your application's needs>;
- //
- // // Remove 'vertex' from the doubly linked list.
- // Vertex& vp = records[vertex.previous]->key;
- // Vertex& vc = records[vertex.current]->key;
- // Vertex& vn = records[vertex.next]->key;
- // vp.next = vc.next;
- // vn.previous = vc.previous;
- //
- // // Update the neighbors' weights in the min-heap.
- // minHeap.Update(records[vertex.previous], Weight(positions, vp));
- // minHeap.Update(records[vertex.next], Weight(positions, vn));
- // }
- namespace WwiseGTE
- {
- template <typename KeyType, typename ValueType>
- class MinHeap
- {
- public:
- struct Record
- {
- KeyType key;
- ValueType value;
- int index;
- };
- // Construction. The record 'value' members are uninitialized for
- // native types chosen for ValueType. If ValueType is of class type,
- // then the default constructor is used to set the 'value' members.
- MinHeap(int maxElements = 0)
- {
- Reset(maxElements);
- }
- MinHeap(MinHeap const& minHeap)
- {
- *this = minHeap;
- }
- // Assignment.
- MinHeap& operator=(MinHeap const& minHeap)
- {
- mNumElements = minHeap.mNumElements;
- mRecords = minHeap.mRecords;
- mPointers.resize(minHeap.mPointers.size());
- for (auto& record : mRecords)
- {
- mPointers[record.index] = &record;
- }
- return *this;
- }
- // Clear the min-heap so that it has the specified max elements,
- // mNumElements is zero, and mPointers are set to the natural ordering
- // of mRecords.
- void Reset(int maxElements)
- {
- mNumElements = 0;
- if (maxElements > 0)
- {
- mRecords.resize(maxElements);
- mPointers.resize(maxElements);
- for (int i = 0; i < maxElements; ++i)
- {
- mPointers[i] = &mRecords[i];
- mPointers[i]->index = i;
- }
- }
- else
- {
- mRecords.clear();
- mPointers.clear();
- }
- }
- // Get the remaining number of elements in the min-heap. This number
- // is in the range {0..maxElements}.
- inline int GetNumElements() const
- {
- return mNumElements;
- }
- // Get the root of the min-heap. The return value is 'true' whenever
- // the min-heap is not empty. This function reads the root but does
- // not remove the element from the min-heap.
- bool GetMinimum(KeyType& key, ValueType& value) const
- {
- if (mNumElements > 0)
- {
- key = mPointers[0]->key;
- value = mPointers[0]->value;
- return true;
- }
- else
- {
- return false;
- }
- }
- // Insert into the min-heap the 'value' that corresponds to the 'key'.
- // The return value is a pointer to the heap record that stores a copy
- // of 'value', and the pointer value is constant for the life of the
- // min-heap. If you must update a member of the min-heap, say, as
- // illustrated in the polyline decimation example, pass the pointer to
- // Update:
- // auto* valueRecord = minHeap.Insert(key, value);
- // <do whatever>;
- // minHeap.Update(valueRecord, newValue).
- Record* Insert(KeyType const& key, ValueType const& value)
- {
- // Return immediately when the heap is full.
- if (mNumElements == static_cast<int>(mRecords.size()))
- {
- return nullptr;
- }
- // Store the input information in the last heap record, which is
- // the last leaf in the tree.
- int child = mNumElements++;
- Record* record = mPointers[child];
- record->key = key;
- record->value = value;
- // Propagate the information toward the root of the tree until it
- // reaches its correct position, thus restoring the tree to a
- // valid heap.
- while (child > 0)
- {
- int parent = (child - 1) / 2;
- if (mPointers[parent]->value <= value)
- {
- // The parent has a value smaller than or equal to the
- // child's value, so we now have a valid heap.
- break;
- }
- // The parent has a larger value than the child's value. Swap
- // the parent and child:
- // Move the parent into the child's slot.
- mPointers[child] = mPointers[parent];
- mPointers[child]->index = child;
- // Move the child into the parent's slot.
- mPointers[parent] = record;
- mPointers[parent]->index = parent;
- child = parent;
- }
- return mPointers[child];
- }
- // Remove the root of the heap and return its 'key' and 'value
- // members. The root contains the minimum value of all heap elements.
- // The return value is 'true' whenever the min-heap was not empty
- // before the Remove call.
- bool Remove(KeyType& key, ValueType& value)
- {
- // Return immediately when the heap is empty.
- if (mNumElements == 0)
- {
- return false;
- }
- // Get the information from the root of the heap.
- Record* root = mPointers[0];
- key = root->key;
- value = root->value;
- // Restore the tree to a heap. Abstractly, record is the new root
- // of the heap. It is moved down the tree via parent-child swaps
- // until it is in a location that restores the tree to a heap.
- int last = --mNumElements;
- Record* record = mPointers[last];
- int parent = 0, child = 1;
- while (child <= last)
- {
- if (child < last)
- {
- // Select the child with smallest value to be the one that
- // is swapped with the parent, if necessary.
- int childP1 = child + 1;
- if (mPointers[childP1]->value < mPointers[child]->value)
- {
- child = childP1;
- }
- }
- if (record->value <= mPointers[child]->value)
- {
- // The tree is now a heap.
- break;
- }
- // Move the child into the parent's slot.
- mPointers[parent] = mPointers[child];
- mPointers[parent]->index = parent;
- parent = child;
- child = 2 * child + 1;
- }
- // The previous 'last' record was moved to the root and propagated
- // down the tree to its final resting place, restoring the tree to
- // a heap. The slot mPointers[parent] is that resting place.
- mPointers[parent] = record;
- mPointers[parent]->index = parent;
- // The old root record must not be lost. Attach it to the slot
- // that contained the old last record.
- mPointers[last] = root;
- mPointers[last]->index = last;
- return true;
- }
- // The value of a heap record must be modified through this function
- // call. The side effect is that the heap is updated accordingly to
- // restore the data structure to a min-heap. The input 'record'
- // should be a pointer returned by Insert(value); see the comments for
- // the Insert() function.
- void Update(Record* record, ValueType const& value)
- {
- // Return immediately on invalid record.
- if (!record)
- {
- return;
- }
- int parent, child, childP1, maxChild;
- if (record->value < value)
- {
- record->value = value;
- // The new value is larger than the old value. Propagate it
- // toward the leaves.
- parent = record->index;
- child = 2 * parent + 1;
- while (child < mNumElements)
- {
- // At least one child exists. Locate the one of maximum
- // value.
- childP1 = child + 1;
- if (childP1 < mNumElements)
- {
- // Two children exist.
- if (mPointers[child]->value <= mPointers[childP1]->value)
- {
- maxChild = child;
- }
- else
- {
- maxChild = childP1;
- }
- }
- else
- {
- // One child exists.
- maxChild = child;
- }
- if (value <= mPointers[maxChild]->value)
- {
- // The new value is in the correct place to restore
- // the tree to a heap.
- break;
- }
- // The child has a larger value than the parent's value.
- // Swap the parent and child:
- // Move the child into the parent's slot.
- mPointers[parent] = mPointers[maxChild];
- mPointers[parent]->index = parent;
- // Move the parent into the child's slot.
- mPointers[maxChild] = record;
- mPointers[maxChild]->index = maxChild;
- parent = maxChild;
- child = 2 * parent + 1;
- }
- }
- else if (value < record->value)
- {
- record->value = value;
- // The new weight is smaller than the old weight. Propagate
- // it toward the root.
- child = record->index;
- while (child > 0)
- {
- // A parent exists.
- parent = (child - 1) / 2;
- if (mPointers[parent]->value <= value)
- {
- // The new value is in the correct place to restore
- // the tree to a heap.
- break;
- }
- // The parent has a smaller value than the child's value.
- // Swap the child and parent.
- // Move the parent into the child's slot.
- mPointers[child] = mPointers[parent];
- mPointers[child]->index = child;
- // Move the child into the parent's slot.
- mPointers[parent] = record;
- mPointers[parent]->index = parent;
- child = parent;
- }
- }
- }
- // Support for debugging. The functions test whether the data
- // structure is a valid min-heap.
- bool IsValid() const
- {
- for (int child = 0; child < mNumElements; ++child)
- {
- int parent = (child - 1) / 2;
- if (parent > 0)
- {
- if (mPointers[child]->value < mPointers[parent]->value)
- {
- return false;
- }
- if (mPointers[parent]->index != parent)
- {
- return false;
- }
- }
- }
- return true;
- }
- private:
- // A 2-level storage system is used. The pointers have two roles.
- // Firstly, they are unique to each inserted value in order to support
- // the Update() capability of the min-heap. Secondly, they avoid
- // potentially expensive copying of Record objects as sorting occurs
- // in the heap.
- int mNumElements;
- std::vector<Record> mRecords;
- std::vector<Record*> mPointers;
- };
- }
|