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