diff options
author | Pixel <> | 2001-02-28 11:40:25 +0000 |
---|---|---|
committer | Pixel <> | 2001-02-28 11:40:25 +0000 |
commit | 833d20a69fe17ab846c153e35230c66a41d8fca9 (patch) | |
tree | 180ba073e59fee8df22cb733be2eec4c452e1b85 /lib/FHeap.cc |
Premier jetstart
Diffstat (limited to 'lib/FHeap.cc')
-rw-r--r-- | lib/FHeap.cc | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/lib/FHeap.cc b/lib/FHeap.cc new file mode 100644 index 0000000..f8a206f --- /dev/null +++ b/lib/FHeap.cc @@ -0,0 +1,340 @@ +#include <stdio.h> +#include "config.h" +#include "PCommon.h" +#include "FHeap.h" + +/* + + The Child of the Head of a FHeap is the min. + The Key of the Head of a FHeap is the number of cells. + The Degree of the Head is -1. + +*/ + +static int d; + +void FHeap::Link(FHeap * x) +{ + Right->Left = Left; + Left->Right = Right; + Father = x; + if (x->Degree++) { + Left = x->Child->Left; + Right = x->Child; + Left->Right = Right->Left = this; + } else { + x->Child = this; + Left = Right = this; + } + Mark = false; +} + +void FHeap::Rebuild(void) +{ + FHeap *A[DFMAX], *w, *x, *y; + int i, d; + + for (i = 0; i < DFMAX; i++) + A[i] = NULL; + + /* L'implémentation de la phrase du Cormen 'pour chaque noeud w de la + liste des racines de T' se fait de cette manière: comme chaque noeud + de la liste des racines se retrouvera dans le tableau A, si nous voulons + effectuer le travail sur un noeud w et qu'il se trouve déjà dans le + tableau A à l'emplacement de son propre degré, c'est que nous avons fait + le tour de la liste des racines. */ + + for (w = Child; A[w->Degree] != w; w = w->Right) { + x = w; + d = x->Degree; + while (A[d]) { + y = A[d]; + if (x->Key > y->Key) { + /* Attention, w va passer EN DESSOUS de la liste des racines. Nous devons + préserver w, puisque x == y. Donc comme x va disparaître de la liste + des racines, le prochain élément sur lequel nous travaillerons sera + x->Right. Et son prédesseur est x->Right->Left->Left, c'est à dire + x->Left. C'est pourquoi nous faisons w = x->Left maintenant. */ + w = x->Left; + SWAP(x, y); + } + y->Link(x); + A[d++] = NULL; + } + A[d] = x; + /* Nous recalculons l'éventuelle nouvelle valeur de max[T]. */ + if (ReadKey(Child) > ReadKey(w)) + Child = w; + } + + /* Contrairement au Cormen, nous n'avons pas besoin de reconstruire ici + la liste des racines de T. */ +} + +void FHeap::Dump(ostream & os) +{ + int i; + FHeap *l; + + if (Degree == -1) { + os << _(" * Head cell. (") << Key << ")\n |\n"; + d = 0; + } else { + for (i = 1; i <= d; i++) + os << " |"; + os << (Child ? "_ " : "__ ") << Key << " (" << Degree << + ")\n"; + } + if (Child) { + d++; + Child->Dump(os); + d--; + } + + l = Left->Right; + Left->Right = NULL; + if (Right) { + Right->Dump(os); + } + Left->Right = l; +} + +int FHeap::rn(void) +{ + int n = 0; + FHeap *l; + + if (Degree != -1) { + n++; + } + if (Child) { + n += Child->rn(); + } + + l = Left->Right; + Left->Right = NULL; + if (Right) { + n += Right->rn(); + } + Left->Right = l; + + return n; +} + +FHeap::FHeap(void):Father(NULL), Child(NULL), Left(this), Right(this), +Degree(-1), Mark(false) +{ + type = T_FHEAP; +} + +FHeap::FHeap(Key_t IKey, Datas_t const &IDatas):PriorityList(IKey, IDatas), +Father(NULL), Child(NULL), Left(this), Right(this), Degree(0), Mark(false) +{ + type =T_FHEAP; +#ifdef DEBUG + nc++; +#endif +} + +FHeap::~FHeap(void) +{ + FHeap *T; + + if (Child) { + delete Child; + } + if (Right != this) { + Left->Right = Right; + Right->Left = Left; + delete Right; + } +#ifdef DEBUG + nd++; +#endif +} + +Cell FHeap::Min(void) +{ + return Child; +} + +FHeap *FHeap::Insert(FHeap * E) +{ + if (Degree != -1) + exception(2, _("Insert: not over Head.")); + if (Child) { + ((FHeap *) E)->Father = NULL; + ((FHeap *) E)->Left = Child; + ((FHeap *) E)->Right = Child->Right; + Child->Right->Left = ((FHeap *) E); + Child->Right = ((FHeap *) E); + if (ReadKey(E) < (Child->Key)) { + Child = ((FHeap *) E); + } + } else { + Child = ((FHeap *) E); + } + Key++; + return E; +} + +Cell FHeap::Insert(Key_t IKey, Datas_t const &IDatas) +{ + FHeap *P; + + if (!(P = new FHeap(IKey, IDatas))) + exception(5, _("Insert: No more memory.")); + return Insert(P); +} + +Key_t FHeap::Extract_Min(Datas_t & Datas) +{ + FHeap *z, *w; + Key_t k; + + if (!(z = Child)) + exception(4, _("Extract_Min: Priority List is empty.")); + + Datas = z->Datas; + k = z->Key; + + /* Nous inversons ici l'idée du Cormen... Au lieu de procéder cas par cas, nous + mettons d'abord en globalité les pères de tous les fils de z à NULL (ce qui + nous permet de faire facilement la boucle, puisque, lorsque nous retombons + sur une cellule dont le père est NULL, cela signifie que nous avons fait + le tour) et à ce moment-là, la liste des fils de z, indexée par z fait un + superbe tas de Fibonacci que nous allons immédiatement fusionner avec le tas + en cours. De plus, nous supprimons z de la liste des racines maintenant. */ + + z->Right->Left = z->Left; + z->Left->Right = z->Right; + if ((Child = z->Right) == z) + Child = NULL; + + z->Father = NULL; + z->Left = z->Right = z; + + if (z->Child) { + for (w = z->Child; w->Father; w = w->Left) + w->Father = NULL; + z->Degree = -1; + z->Key = Child ? 0 : Key; // Pour conserver n[T] à jour. + Union(z); + } + + if (!(--Key)) { + Child = NULL; + } else { + Rebuild(); + } + + z->Child = NULL; + delete z; + + return k; +} + +PriorityList *FHeap::Union(PriorityList * P) +{ + FHeap *Temp, *T = ((FHeap *) P); + + if ((P->GetType()) != (((PriorityList *) P)->GetType())) + return GenericUnion(P); + + /* Cette fonction ne suit pas du tout l'idée du Cormen. Elle va + fusionner directement T dans le tas en cours, sans créer + d'intermédiaires. Les données internes du tas sont mises à + jour. */ + + if (!Child) { + Child = T->Child; + Key = T->Key; + } else if (T->Child) { + Child->Right->Left = T->Child; + T->Child->Right->Left = Child; + Temp = Child->Right; + Child->Right = T->Child->Right; + T->Child->Right = Temp; + if (T->Child->Key < Child->Key) + Child = T->Child; + Key += T->Key; + } + + T->Child = NULL; + return this; +} + +bool FHeap::Lower_Key(Cell x, Key_t NKey) +{ + FHeap *y, *tx = ((FHeap *) x); + + if (NKey > tx->Key) + return false; + + tx->Key = NKey; + y = tx->Father; + if ((y) && (tx->Key < y->Key)) { + Cut(tx, y); + CascadeCut(y); + } + if (NKey < Child->Key) + Child = tx; +} + +Key_t FHeap::Delete(Datas_t & Datas, Cell x) +{ + Key_t K; + + K = ReadKey(x); + + Lower_Key(x, M_INFINITY); + Extract_Min(Datas); + + return K; +} + +void FHeap::Cut(FHeap * x, FHeap * y) +{ + /* Le fait de rajouter la cellule en cours à la liste des racines de T ne + modifie en rien le comportement de min[T]. Sinon, cela voudrait dire que + le minimum est la cellule que nous déplaçons et cela est impossible car + le minimum est obligatoirement une racine. */ + + y->Degree--; + + x->Right->Left = Left; + x->Left->Right = Right; + + if (y->Child == x) { + y->Child = y->Degree ? x->Right : NULL; + } + + x->Right = Child->Right; + x->Left = Child; + + Child->Right->Left = x; + Child->Right = x; + + x->Father = NULL; + + x->Mark = false; +} + +void FHeap::CascadeCut(FHeap * y) +{ + FHeap *z = y->Father; + + if (z) { + if (!(y->Mark)) { + y->Mark = true; + } else { + Cut(y, z); + CascadeCut(z); + } + } +} + +bool FHeap::IsEmpty(void) +{ + return (!(Child)); +} |