File indexing completed on 2024-05-12 16:01:59

0001 /* This file is part of the Calligra libraries
0002    SPDX-FileCopyrightText: 2001 Werner Trobin <trobin@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef priority_queue_h
0008 #define priority_queue_h
0009 
0010 #include <vector>
0011 #include <QString>
0012 #include <QHash>
0013 #include <kis_debug.h>
0014 
0015 // Better put all those internal classes in some namespace to avoid clashes
0016 // as the names are quite generic
0017 namespace CalligraFilter
0018 {
0019 
0020 /**
0021  * This PriorityQueue class is implemented as "upside down" heap, i.e. the item
0022  * with the \b smallest key is at the root of the heap.
0023  * If you feel like using that class your template parameter has to have a public
0024  * method "unsigned int key() const" which returns - surprise - the key. The
0025  * supplied key must not be "negative." We use UINT_MAX as value to represent
0026  * "infinity" for the shortest path algorithm.
0027  * As this is a very specialized class we also demand a "void setIndex(int i)"
0028  * method in order to tell nodes where they are located inside the heap. This is
0029  * a very ugly approach, but it's the only way I see if you want to avoid a O(n)
0030  * search for the item where you decreased the key :}
0031  * Just to make it even worse we also use a "int index() const" method
0032  * to fetch the index... well, you most likely would need one anyway ;)
0033  * Note: This class is pointer based (like QPtr*) - if you create PriorityQueue<X>
0034  * we actually operate on X* ! We don't care about deleting your pointers at all.
0035  * We don't copy them, we don't create new ones,... - you own them, you have
0036  * to delete them :)
0037  *
0038  * In case you change a key value make sure to call keyDecreased and pass the
0039  * item you touched. This is running in O(log n) according to Cormen...
0040  *
0041  * All the ideas are stol^H^H^H^Hborrowed from "Introduction to Algorithms",
0042  * Cormen et al
0043  *
0044  * @author Werner Trobin <trobin@kde.org>
0045  */
0046 template<class T> class PriorityQueue
0047 {
0048 
0049 public:
0050     PriorityQueue() {}
0051     PriorityQueue(const PriorityQueue<T>& rhs) : m_vector(rhs.m_vector) {}
0052     PriorityQueue(const QHash<QByteArray, T*>& items);
0053     ~PriorityQueue() {}
0054 
0055     PriorityQueue<T> &operator=(const PriorityQueue<T>& rhs) {
0056         m_vector = rhs.m_vector; return *this;
0057     }
0058     bool operator==(const PriorityQueue<T>& rhs) {
0059         return m_vector == rhs.m_vector;
0060     }
0061 
0062     unsigned int count() const {
0063         return m_vector.size();
0064     }
0065     bool isEmpty() const {
0066         return m_vector.empty();
0067     }
0068 
0069     void insert(T* item);
0070 
0071     /**
0072      * Call this method after decreasing the key of the ith item. The heap
0073      * properties will no longer be valid if you either forget to call that
0074      * method, or if you \b increase the key.
0075      */
0076     void keyDecreased(T* item);
0077 
0078     T* extractMinimum();
0079 
0080     /**
0081      * For debugging
0082      */
0083     void dump() const;
0084 
0085 private:
0086     // Note: We have to use a 1-based index here, and we get/return 0-based ones
0087     int parent(int i) {
0088         return ((i + 1) >> 1) - 1;
0089     }
0090     int left(int i) {
0091         return ((i + 1) << 1) - 1;
0092     }
0093     int right(int i) {
0094         return (i + 1) << 1;
0095     }
0096 
0097     void heapify(int i);
0098     // item is !=0 for sure
0099     void bubbleUp(T* item, int i);
0100     // Builds the heap in the vector in O(n)
0101     void buildHeap();
0102 
0103     std::vector<T*> m_vector;
0104 };
0105 
0106 template<class T>
0107 PriorityQueue<T>::PriorityQueue(const QHash<QByteArray, T*>& items)
0108     : m_vector(items.count())
0109 {
0110     // First put all items into the vector
0111     int i = 0;
0112     Q_FOREACH (T* item, items) {
0113         item->setIndex(i);
0114         m_vector[i] = item;
0115         ++i;
0116     }
0117     // Then build a heap in that vector
0118     buildHeap();
0119 }
0120 
0121 template<class T>
0122 void PriorityQueue<T>::insert(T* item)
0123 {
0124     if (!item)
0125         return;
0126     int i = static_cast<int>(m_vector.size());
0127     m_vector.push_back(0);   // extend the vector by one item. i == index to the last item
0128     bubbleUp(item, i);
0129 }
0130 
0131 template<class T>
0132 void PriorityQueue<T>::keyDecreased(T* item)
0133 {
0134     if (!item)
0135         return;
0136     bubbleUp(item, item->index());
0137 }
0138 
0139 template<class T>
0140 T* PriorityQueue<T>::extractMinimum()
0141 {
0142     if (m_vector.size() < 1)
0143         return 0;
0144     T *min = m_vector[ 0 ];
0145     m_vector[ 0 ] = m_vector[ m_vector.size() - 1 ];
0146     // update the index
0147     m_vector[ 0 ]->setIndex(0);
0148     m_vector.pop_back();
0149     heapify(0);
0150     return min;
0151 }
0152 
0153 template<class T>
0154 void PriorityQueue<T>::dump() const
0155 {
0156     dbgFile << "++++++++++ PriorityQueue::dump ++++++++++";
0157     QString out;
0158     int size = static_cast<int>(m_vector.size());
0159     for (int i = 0; i < size; ++i) {
0160         if (m_vector[ i ]->index() != i)
0161             out += " ERROR: index out of sync. Should be " + QString::number(i) + ", is " +
0162                    QString::number(m_vector[ i ]->index()) + ". ";
0163         out += QString::number(m_vector[ i ]->key()) + ", ";
0164     }
0165     if (out.isEmpty())
0166         out = "(empty)";
0167     dbgFile << out;
0168     dbgFile << "++++++++++ PriorityQueue::dump (done) ++++++++++";
0169 }
0170 
0171 template<class T>
0172 void PriorityQueue<T>::heapify(int i)
0173 {
0174     int l = left(i);
0175     int r = right(i);
0176     int size = static_cast<int>(m_vector.size());
0177     int smallest;
0178 
0179     if (l < size && i < size && m_vector[ l ]->key() < m_vector[ i ]->key())
0180         smallest = l;
0181     else
0182         smallest = i;
0183 
0184     if (r < size && m_vector[ r ]->key() < m_vector[ smallest ]->key())
0185         smallest = r;
0186 
0187     if (smallest != i) {
0188         T* tmp = m_vector[ i ];
0189         m_vector[ i ] = m_vector[ smallest ];
0190         // update indices
0191         m_vector[ i ]->setIndex(i);
0192         tmp->setIndex(smallest);
0193         m_vector[ smallest ] = tmp;
0194         heapify(smallest);
0195     }
0196 }
0197 
0198 template<class T>
0199 void PriorityQueue<T>::bubbleUp(T* item, int i)
0200 {
0201     int p = parent(i);
0202     while (i > 0 && m_vector[ p ]->key() > item->key()) {
0203         // update the index first
0204         m_vector[ p ]->setIndex(i);
0205         // then move it there
0206         m_vector[ i ] = m_vector[ p ];
0207         i = p;
0208         p = parent(i);
0209     }
0210     item->setIndex(i);
0211     m_vector[ i ] = item;
0212 }
0213 
0214 template<class T>
0215 void PriorityQueue<T>::buildHeap()
0216 {
0217     // from size() / 2 down to 1
0218     for (int i = (m_vector.size() >> 1) - 1; i >= 0; --i)
0219         heapify(i);
0220 }
0221 
0222 } // namespace Calligra
0223 
0224 #endif // priority_queue_h