139 lines
3.7 KiB
C++
139 lines
3.7 KiB
C++
Heap::Heap()
|
|
: buckets(new HeapNode*[1]), lastAllocatedBucket(-1),
|
|
bucketArraySize(1), lastNode(-1) {
|
|
}
|
|
|
|
void Heap::init(int _id, int _factor) { this->id = _id; this->factor = (float)_factor; }
|
|
|
|
void Heap::insert(float key, Chose* value) {
|
|
++lastNode;
|
|
if (getBucket(lastNode) > lastAllocatedBucket) {
|
|
allocateBucket();
|
|
}
|
|
buckets[getBucket(lastNode)][getIndex(lastNode)].key = key;
|
|
buckets[getBucket(lastNode)][getIndex(lastNode)].value = value;
|
|
siftUp(lastNode);
|
|
}
|
|
|
|
void Heap::remove(Chose* value) {
|
|
int node = value->lod.heaps[id];
|
|
|
|
if (node == lastNode) { // On a supprimé le dernier noeud.
|
|
--lastNode;
|
|
// + 1 pour garder au moins un bucket "en cache".
|
|
if (getBucket(lastNode) + 1 < lastAllocatedBucket)
|
|
freeBucket();
|
|
return;
|
|
}
|
|
|
|
buckets[getBucket(node)][getIndex(node)] = \
|
|
buckets[getBucket(lastNode)][getIndex(lastNode)];
|
|
|
|
--lastNode;
|
|
|
|
// + 1 pour garder au moins un bucket "en cache".
|
|
if (getBucket(lastNode) + 1 < lastAllocatedBucket) {
|
|
freeBucket();
|
|
}
|
|
|
|
siftDown(node);
|
|
}
|
|
|
|
bool Heap::lessThan(float a, float b) {
|
|
return (a * factor < b * factor);
|
|
}
|
|
|
|
Chose* Heap::popIfLessThan(float key) {
|
|
if (lastNode >= 0 && buckets[0][0].key * factor < key * factor) {
|
|
Chose* ret = buckets[0][0].value;
|
|
remove(ret);
|
|
return ret;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void Heap::siftUp(int node) {
|
|
HeapNode* n;
|
|
HeapNode* np;
|
|
while (true) {
|
|
n = &(buckets[getBucket(node)][getIndex(node)]);
|
|
if (node <= 0)
|
|
break;
|
|
int p = parent(node);
|
|
np = &(buckets[getBucket(p)][getIndex(p)]);
|
|
if (n->key * factor >= np->key * factor) //!!!!!
|
|
break;
|
|
HeapNode temp = *n;
|
|
*n = *np;
|
|
*np = temp;
|
|
// mettre à jour le champ lod.heaps[id] de l'ancien parent qu'on
|
|
// vient de descendre.
|
|
n->value->lod.heaps[id] = node;
|
|
node = p;
|
|
}
|
|
// après les break; qui sortent de la boucle, on a déjà actualisé
|
|
// le pointeur `n` vers buckets[getBucket(node)][getIndex(node)].
|
|
n->value->lod.heaps[id] = node;
|
|
}
|
|
|
|
void Heap::siftDown(int node) {
|
|
HeapNode* n;
|
|
HeapNode* nlc;
|
|
HeapNode* nrc;
|
|
while (true) {
|
|
n = &(buckets[getBucket(node)][getIndex(node)]);
|
|
int lc = leftchild(node);
|
|
int rc = rightchild(node);
|
|
nlc = &(buckets[getBucket(lc)][getIndex(lc)]);
|
|
nrc = &(buckets[getBucket(rc)][getIndex(rc)]);
|
|
// exchLeft et exchRight peuvent être tout deux true. Dans ce
|
|
// cas, c'est exchRight qui gagne.
|
|
bool exchLeft = (lc <= lastNode) && (n->key * factor > nlc->key * factor);
|
|
bool exchRight = (rc <= lastNode) && (n->key * factor > nrc->key * factor);
|
|
exchRight = exchRight && (nlc->key * factor > nrc->key * factor);
|
|
if ((!exchLeft) && (!exchRight))
|
|
break;
|
|
HeapNode temp = *n;
|
|
if (exchRight) {
|
|
*n = *nrc;
|
|
*nrc = temp;
|
|
} else {
|
|
*n = *nlc;
|
|
*nlc = temp;
|
|
}
|
|
// mettre à jour le champ lod.heaps[id] de l'ancien fils qu'on
|
|
// vient de remonter.
|
|
n->value->lod.heaps[id] = node;
|
|
node = (exchRight ? rc : lc);
|
|
}
|
|
// après les break; qui sortent de la boucle, on a déjà actualisé
|
|
// le pointeur `n` vers buckets[getBucket(node)][getIndex(node)].
|
|
n->value->lod.heaps[id] = node;
|
|
}
|
|
|
|
void Heap::allocateBucket() {
|
|
++lastAllocatedBucket;
|
|
if (lastAllocatedBucket >= bucketArraySize) {
|
|
HeapNode** old = buckets;
|
|
buckets = new HeapNode*[bucketArraySize*2];
|
|
for (int i = 0; i < lastAllocatedBucket; i++)
|
|
buckets[i] = old[i];
|
|
delete[] old;
|
|
bucketArraySize *= 2;
|
|
}
|
|
buckets[lastAllocatedBucket] = new HeapNode[bucketSize];
|
|
}
|
|
|
|
void Heap::freeBucket() {
|
|
delete[] buckets[lastAllocatedBucket];
|
|
--lastAllocatedBucket;
|
|
if (lastAllocatedBucket * 4 < bucketArraySize && bucketArraySize > 1) {
|
|
HeapNode** old = buckets;
|
|
buckets = new HeapNode*[bucketArraySize/2];
|
|
for (int i = 0; i <= lastAllocatedBucket; i++)
|
|
buckets[i] = old[i];
|
|
delete[] old;
|
|
bucketArraySize /= 2;
|
|
}
|
|
}
|