gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Smarter bubbleDown() in K-ary heaps (#301)
0 2 0
default
2 files changed with 37 insertions and 43 deletions:
↑ Collapse diff ↑
Show white space 128 line context
... ...
@@ -70,172 +70,161 @@
70 70
    ///
71 71
    /// Each item has a state associated to it. It can be "in heap",
72 72
    /// "pre-heap" or "post-heap". The latter two are indifferent from the
73 73
    /// heap's point of view, but may be useful to the user.
74 74
    ///
75 75
    /// The item-int map must be initialized in such way that it assigns
76 76
    /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
77 77
    enum State {
78 78
      IN_HEAP = 0,    ///< = 0.
79 79
      PRE_HEAP = -1,  ///< = -1.
80 80
      POST_HEAP = -2  ///< = -2.
81 81
    };
82 82

	
83 83
  private:
84 84
    std::vector<Pair> _data;
85 85
    Compare _comp;
86 86
    ItemIntMap &_iim;
87 87

	
88 88
  public:
89 89
    /// \brief Constructor.
90 90
    ///
91 91
    /// Constructor.
92 92
    /// \param map A map that assigns \c int values to the items.
93 93
    /// It is used internally to handle the cross references.
94 94
    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
95 95
    explicit FouraryHeap(ItemIntMap &map) : _iim(map) {}
96 96

	
97 97
    /// \brief Constructor.
98 98
    ///
99 99
    /// Constructor.
100 100
    /// \param map A map that assigns \c int values to the items.
101 101
    /// It is used internally to handle the cross references.
102 102
    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
103 103
    /// \param comp The function object used for comparing the priorities.
104 104
    FouraryHeap(ItemIntMap &map, const Compare &comp)
105 105
      : _iim(map), _comp(comp) {}
106 106

	
107 107
    /// \brief The number of items stored in the heap.
108 108
    ///
109 109
    /// This function returns the number of items stored in the heap.
110 110
    int size() const { return _data.size(); }
111 111

	
112 112
    /// \brief Check if the heap is empty.
113 113
    ///
114 114
    /// This function returns \c true if the heap is empty.
115 115
    bool empty() const { return _data.empty(); }
116 116

	
117 117
    /// \brief Make the heap empty.
118 118
    ///
119 119
    /// This functon makes the heap empty.
120 120
    /// It does not change the cross reference map. If you want to reuse
121 121
    /// a heap that is not surely empty, you should first clear it and
122 122
    /// then you should set the cross reference map to \c PRE_HEAP
123 123
    /// for each item.
124 124
    void clear() { _data.clear(); }
125 125

	
126 126
  private:
127 127
    static int parent(int i) { return (i-1)/4; }
128 128
    static int firstChild(int i) { return 4*i+1; }
129 129

	
130 130
    bool less(const Pair &p1, const Pair &p2) const {
131 131
      return _comp(p1.second, p2.second);
132 132
    }
133 133

	
134
    int findMin(const int child, const int length) {
135
      int min=child;
136
      if( child+3<length ) {
137
        if( less(_data[child+3], _data[min]) )
138
          min=child+3;
139
        if( less(_data[child+2], _data[min]) )
140
          min=child+2;
141
        if( less(_data[child+1], _data[min]) )
142
          min=child+1;
143
      }
144
      else if( child+2<length ) {
145
        if( less(_data[child+2], _data[min]) )
146
          min=child+2;
147
        if( less(_data[child+1], _data[min]) )
148
          min=child+1;
149
      }
150
      else if( child+1<length ) {
151
        if( less(_data[child+1], _data[min]) )
152
          min=child+1;
153
      }
154
      return min;
155
    }
156

	
157 134
    void bubbleUp(int hole, Pair p) {
158 135
      int par = parent(hole);
159 136
      while( hole>0 && less(p,_data[par]) ) {
160 137
        move(_data[par],hole);
161 138
        hole = par;
162 139
        par = parent(hole);
163 140
      }
164 141
      move(p, hole);
165 142
    }
166 143

	
167 144
    void bubbleDown(int hole, Pair p, int length) {
168 145
      if( length>1 ) {
169 146
        int child = firstChild(hole);
170
        while( child<length ) {
171
          child = findMin(child, length);
172
          if( !less(_data[child], p) )
147
        while( child+3<length ) {
148
          int min=child;
149
          if( less(_data[++child], _data[min]) ) min=child;
150
          if( less(_data[++child], _data[min]) ) min=child;
151
          if( less(_data[++child], _data[min]) ) min=child;
152
          if( !less(_data[min], p) )
173 153
            goto ok;
174
          move(_data[child], hole);
175
          hole = child;
154
          move(_data[min], hole);
155
          hole = min;
176 156
          child = firstChild(hole);
177 157
        }
158
        if ( child<length ) {
159
          int min = child;
160
          if( ++child<length && less(_data[child], _data[min]) ) min=child;
161
          if( ++child<length && less(_data[child], _data[min]) ) min=child;
162
          if( less(_data[min], p) ) {
163
            move(_data[min], hole);
164
            hole = min;
165
          }
166
        }
178 167
      }
179 168
    ok:
180 169
      move(p, hole);
181 170
    }
182 171

	
183 172
    void move(const Pair &p, int i) {
184 173
      _data[i] = p;
185 174
      _iim.set(p.first, i);
186 175
    }
187 176

	
188 177
  public:
189 178
    /// \brief Insert a pair of item and priority into the heap.
190 179
    ///
191 180
    /// This function inserts \c p.first to the heap with priority
192 181
    /// \c p.second.
193 182
    /// \param p The pair to insert.
194 183
    /// \pre \c p.first must not be stored in the heap.
195 184
    void push(const Pair &p) {
196 185
      int n = _data.size();
197 186
      _data.resize(n+1);
198 187
      bubbleUp(n, p);
199 188
    }
200 189

	
201 190
    /// \brief Insert an item into the heap with the given priority.
202 191
    ///
203 192
    /// This function inserts the given item into the heap with the
204 193
    /// given priority.
205 194
    /// \param i The item to insert.
206 195
    /// \param p The priority of the item.
207 196
    /// \pre \e i must not be stored in the heap.
208 197
    void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
209 198

	
210 199
    /// \brief Return the item having minimum priority.
211 200
    ///
212 201
    /// This function returns the item having minimum priority.
213 202
    /// \pre The heap must be non-empty.
214 203
    Item top() const { return _data[0].first; }
215 204

	
216 205
    /// \brief The minimum priority.
217 206
    ///
218 207
    /// This function returns the minimum priority.
219 208
    /// \pre The heap must be non-empty.
220 209
    Prio prio() const { return _data[0].second; }
221 210

	
222 211
    /// \brief Remove the item having minimum priority.
223 212
    ///
224 213
    /// This function removes the item having minimum priority.
225 214
    /// \pre The heap must be non-empty.
226 215
    void pop() {
227 216
      int n = _data.size()-1;
228 217
      _iim.set(_data[0].first, POST_HEAP);
229 218
      if (n>0) bubbleDown(0, _data[n], n);
230 219
      _data.pop_back();
231 220
    }
232 221

	
233 222
    /// \brief Remove the given item from the heap.
234 223
    ///
235 224
    /// This function removes the given item from the heap if it is
236 225
    /// already stored.
237 226
    /// \param i The item to delete.
238 227
    /// \pre \e i must be in the heap.
239 228
    void erase(const Item &i) {
240 229
      int h = _iim[i];
241 230
      int n = _data.size()-1;
Show white space 128 line context
... ...
@@ -77,159 +77,164 @@
77 77
    ///
78 78
    /// Each item has a state associated to it. It can be "in heap",
79 79
    /// "pre-heap" or "post-heap". The latter two are indifferent from the
80 80
    /// heap's point of view, but may be useful to the user.
81 81
    ///
82 82
    /// The item-int map must be initialized in such way that it assigns
83 83
    /// \c PRE_HEAP (<tt>-1</tt>) to any element to be put in the heap.
84 84
    enum State {
85 85
      IN_HEAP = 0,    ///< = 0.
86 86
      PRE_HEAP = -1,  ///< = -1.
87 87
      POST_HEAP = -2  ///< = -2.
88 88
    };
89 89

	
90 90
  private:
91 91
    std::vector<Pair> _data;
92 92
    Compare _comp;
93 93
    ItemIntMap &_iim;
94 94

	
95 95
  public:
96 96
    /// \brief Constructor.
97 97
    ///
98 98
    /// Constructor.
99 99
    /// \param map A map that assigns \c int values to the items.
100 100
    /// It is used internally to handle the cross references.
101 101
    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
102 102
    explicit KaryHeap(ItemIntMap &map) : _iim(map) {}
103 103

	
104 104
    /// \brief Constructor.
105 105
    ///
106 106
    /// Constructor.
107 107
    /// \param map A map that assigns \c int values to the items.
108 108
    /// It is used internally to handle the cross references.
109 109
    /// The assigned value must be \c PRE_HEAP (<tt>-1</tt>) for each item.
110 110
    /// \param comp The function object used for comparing the priorities.
111 111
    KaryHeap(ItemIntMap &map, const Compare &comp)
112 112
      : _iim(map), _comp(comp) {}
113 113

	
114 114
    /// \brief The number of items stored in the heap.
115 115
    ///
116 116
    /// This function returns the number of items stored in the heap.
117 117
    int size() const { return _data.size(); }
118 118

	
119 119
    /// \brief Check if the heap is empty.
120 120
    ///
121 121
    /// This function returns \c true if the heap is empty.
122 122
    bool empty() const { return _data.empty(); }
123 123

	
124 124
    /// \brief Make the heap empty.
125 125
    ///
126 126
    /// This functon makes the heap empty.
127 127
    /// It does not change the cross reference map. If you want to reuse
128 128
    /// a heap that is not surely empty, you should first clear it and
129 129
    /// then you should set the cross reference map to \c PRE_HEAP
130 130
    /// for each item.
131 131
    void clear() { _data.clear(); }
132 132

	
133 133
  private:
134 134
    int parent(int i) { return (i-1)/K; }
135 135
    int firstChild(int i) { return K*i+1; }
136 136

	
137 137
    bool less(const Pair &p1, const Pair &p2) const {
138 138
      return _comp(p1.second, p2.second);
139 139
    }
140 140

	
141
    int findMin(const int child, const int length) {
142
      int min=child, i=1;
143
      while( i<K && child+i<length ) {
144
        if( less(_data[child+i], _data[min]) )
145
          min=child+i;
146
        ++i;
147
      }
148
      return min;
149
    }
150

	
151 141
    void bubbleUp(int hole, Pair p) {
152 142
      int par = parent(hole);
153 143
      while( hole>0 && less(p,_data[par]) ) {
154 144
        move(_data[par],hole);
155 145
        hole = par;
156 146
        par = parent(hole);
157 147
      }
158 148
      move(p, hole);
159 149
    }
160 150

	
161 151
    void bubbleDown(int hole, Pair p, int length) {
162 152
      if( length>1 ) {
163 153
        int child = firstChild(hole);
164
        while( child<length ) {
165
          child = findMin(child, length);
166
          if( !less(_data[child], p) )
154
        while( child+K<=length ) {
155
          int min=child;
156
          for (int i=1; i<K; ++i) {
157
            if( less(_data[child+i], _data[min]) )
158
              min=child+i;
159
          }
160
          if( !less(_data[min], p) )
167 161
            goto ok;
168
          move(_data[child], hole);
169
          hole = child;
162
          move(_data[min], hole);
163
          hole = min;
170 164
          child = firstChild(hole);
171 165
        }
166
        if ( child<length ) {
167
          int min = child;
168
          while (++child < length) {
169
            if( less(_data[child], _data[min]) )
170
              min=child;
171
          }
172
          if( less(_data[min], p) ) {
173
            move(_data[min], hole);
174
            hole = min;
175
          }
176
        }
172 177
      }
173 178
    ok:
174 179
      move(p, hole);
175 180
    }
176 181

	
177 182
    void move(const Pair &p, int i) {
178 183
      _data[i] = p;
179 184
      _iim.set(p.first, i);
180 185
    }
181 186

	
182 187
  public:
183 188
    /// \brief Insert a pair of item and priority into the heap.
184 189
    ///
185 190
    /// This function inserts \c p.first to the heap with priority
186 191
    /// \c p.second.
187 192
    /// \param p The pair to insert.
188 193
    /// \pre \c p.first must not be stored in the heap.
189 194
    void push(const Pair &p) {
190 195
      int n = _data.size();
191 196
      _data.resize(n+1);
192 197
      bubbleUp(n, p);
193 198
    }
194 199

	
195 200
    /// \brief Insert an item into the heap with the given priority.
196 201
    ///
197 202
    /// This function inserts the given item into the heap with the
198 203
    /// given priority.
199 204
    /// \param i The item to insert.
200 205
    /// \param p The priority of the item.
201 206
    /// \pre \e i must not be stored in the heap.
202 207
    void push(const Item &i, const Prio &p) { push(Pair(i,p)); }
203 208

	
204 209
    /// \brief Return the item having minimum priority.
205 210
    ///
206 211
    /// This function returns the item having minimum priority.
207 212
    /// \pre The heap must be non-empty.
208 213
    Item top() const { return _data[0].first; }
209 214

	
210 215
    /// \brief The minimum priority.
211 216
    ///
212 217
    /// This function returns the minimum priority.
213 218
    /// \pre The heap must be non-empty.
214 219
    Prio prio() const { return _data[0].second; }
215 220

	
216 221
    /// \brief Remove the item having minimum priority.
217 222
    ///
218 223
    /// This function removes the item having minimum priority.
219 224
    /// \pre The heap must be non-empty.
220 225
    void pop() {
221 226
      int n = _data.size()-1;
222 227
      _iim.set(_data[0].first, POST_HEAP);
223 228
      if (n>0) bubbleDown(0, _data[n], n);
224 229
      _data.pop_back();
225 230
    }
226 231

	
227 232
    /// \brief Remove the given item from the heap.
228 233
    ///
229 234
    /// This function removes the given item from the heap if it is
230 235
    /// already stored.
231 236
    /// \param i The item to delete.
232 237
    /// \pre \e i must be in the heap.
233 238
    void erase(const Item &i) {
234 239
      int h = _iim[i];
235 240
      int n = _data.size()-1;
0 comments (0 inline)