00001 /* This file is part of the KOffice libraries 00002 Copyright (C) 2001 Werner Trobin <trobin@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 * Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #ifndef priority_queue_h 00020 #define priority_queue_h 00021 00022 #include <vector> 00023 #include <QString> 00024 #include <q3asciidict.h> 00025 #include <kdebug.h> 00026 00027 // Better put all those internal classes in some namespace to avoid clashes 00028 // as the names are quite generic 00029 namespace KOffice { 00030 00057 template<class T> class PriorityQueue { 00058 00059 public: 00060 PriorityQueue() {} 00061 PriorityQueue( const PriorityQueue<T>& rhs ) : m_vector( rhs.m_vector ) {} 00062 PriorityQueue( const Q3AsciiDict<T>& items ); 00063 ~PriorityQueue() {} 00064 00065 PriorityQueue<T> &operator=( const PriorityQueue<T>& rhs ) { m_vector = rhs.m_vector; return *this; } 00066 bool operator==( const PriorityQueue<T>& rhs ) { return m_vector == rhs.m_vector; } 00067 00068 unsigned int count() const { return m_vector.size(); } 00069 bool isEmpty() const { return m_vector.empty(); } 00070 00071 void insert( T* item ); 00072 00078 void keyDecreased( T* item ); 00079 00080 T* extractMinimum(); 00081 00085 void dump() const; 00086 00087 private: 00088 // Note: We have to use a 1-based index here, and we get/return 0-based ones 00089 int parent( int i ) { return ( ( i + 1 ) >> 1 ) - 1; } 00090 int left( int i ) { return ( ( i + 1 ) << 1 ) - 1; } 00091 int right( int i ) { return ( i + 1 ) << 1; } 00092 00093 void heapify( int i ); 00094 // item is !=0 for sure 00095 void bubbleUp( T* item, int i ); 00096 // Builds the heap in the vector in O(n) 00097 void buildHeap(); 00098 00099 std::vector<T*> m_vector; 00100 }; 00101 00102 template<class T> 00103 PriorityQueue<T>::PriorityQueue( const Q3AsciiDict<T>& items ) : m_vector( items.count() ) 00104 { 00105 // First put all items into the vector 00106 Q3AsciiDictIterator<T> it( items ); 00107 for ( int i = 0; it.current(); ++it, ++i ) { 00108 it.current()->setIndex( i ); 00109 m_vector[ i ] = it.current(); 00110 } 00111 // Then build a heap in that vector 00112 buildHeap(); 00113 } 00114 00115 template<class T> 00116 void PriorityQueue<T>::insert( T* item ) 00117 { 00118 if ( !item ) 00119 return; 00120 int i = static_cast<int>( m_vector.size() ); 00121 m_vector.push_back( 0 ); // extend the vector by one item. i == index to the last item 00122 bubbleUp( item, i ); 00123 } 00124 00125 template<class T> 00126 void PriorityQueue<T>::keyDecreased( T* item ) 00127 { 00128 if ( !item ) 00129 return; 00130 bubbleUp( item, item->index() ); 00131 } 00132 00133 template<class T> 00134 T* PriorityQueue<T>::extractMinimum() 00135 { 00136 if ( m_vector.size() < 1 ) 00137 return 0; 00138 T *min = m_vector[ 0 ]; 00139 m_vector[ 0 ] = m_vector[ m_vector.size() - 1 ]; 00140 // update the index 00141 m_vector[ 0 ]->setIndex( 0 ); 00142 m_vector.pop_back(); 00143 heapify( 0 ); 00144 return min; 00145 } 00146 00147 template<class T> 00148 void PriorityQueue<T>::dump() const 00149 { 00150 kDebug( 30500 ) << "++++++++++ PriorityQueue::dump ++++++++++" << endl; 00151 QString out; 00152 int size = static_cast<int>( m_vector.size() ); 00153 for ( int i = 0; i < size; ++i ) { 00154 if ( m_vector[ i ]->index() != i ) 00155 out += " ERROR: index out of sync. Should be " + QString::number( i ) + ", is " + 00156 QString::number( m_vector[ i ]->index() ) + ". "; 00157 out += QString::number( m_vector[ i ]->key() ); 00158 out += ", "; 00159 } 00160 if ( out.isEmpty() ) 00161 out = "(empty)"; 00162 kDebug( 30500 ) << out << endl; 00163 kDebug( 30500 ) << "++++++++++ PriorityQueue::dump (done) ++++++++++" << endl; 00164 } 00165 00166 template<class T> 00167 void PriorityQueue<T>::heapify( int i ) 00168 { 00169 int l = left( i ), r = right( i ), size = static_cast<int>( m_vector.size() ); 00170 int smallest; 00171 00172 if ( l < size && m_vector[ l ]->key() < m_vector[ i ]->key() ) 00173 smallest = l; 00174 else 00175 smallest = i; 00176 if ( r < size && m_vector[ r ]->key() < m_vector[ smallest ]->key() ) 00177 smallest = r; 00178 00179 if ( smallest != i ) { 00180 T* tmp = m_vector[ i ]; 00181 m_vector[ i ] = m_vector[ smallest ]; 00182 // update indices 00183 m_vector[ i ]->setIndex( i ); 00184 tmp->setIndex( smallest ); 00185 m_vector[ smallest ] = tmp; 00186 heapify( smallest ); 00187 } 00188 } 00189 00190 template<class T> 00191 void PriorityQueue<T>::bubbleUp( T* item, int i ) 00192 { 00193 int p = parent( i ); 00194 while ( i > 0 && m_vector[ p ]->key() > item->key() ) { 00195 // update the index first 00196 m_vector[ p ]->setIndex( i ); 00197 // then move it there 00198 m_vector[ i ] = m_vector[ p ]; 00199 i = p; 00200 p = parent( i ); 00201 } 00202 item->setIndex( i ); 00203 m_vector[ i ] = item; 00204 } 00205 00206 template<class T> 00207 void PriorityQueue<T>::buildHeap() 00208 { 00209 // from size() / 2 down to 1 00210 for ( int i = ( m_vector.size() >> 1 ) - 1; i >= 0; --i ) 00211 heapify( i ); 00212 } 00213 00214 } // namespace KOffice 00215 00216 #endif // priority_queue_h