diff --git a/TP5/tas.py b/TP5/tas.py index edbb5d45f0e2127a0b45bb9daa3f1644cd6845be..ceae06d27245c34dca2eca552b79050d8408d3c6 100644 --- a/TP5/tas.py +++ b/TP5/tas.py @@ -1,320 +1,72 @@ -#!/usr/bin/env python - -class RefElement(object): - def __init__(self, noeud, get_tas): - self.ref = noeud - self.get_tas = get_tas - self.existe = True - - def __str__(self): - if self.existe: - return "<Tas Binomial Référant à '%s'>" % str(self.ref.val) - else: - return "<Référence du tas inexistante>" - - def descendre(self, new_key): - # Met à jour la priorité de l'élément. - assert self.existe - assert self.ref.ref == self - self.ref.descendre(new_key) - - def supprimer(self): - # Retire l'élément du tas. - self.descendre(self) - v = self.get_tas().extraireMin() - assert not self.existe - assert v is self.ref.valeur - - def dans_tas(self, tas): - """Retourne True si l'élément appartient au tas entré en paramètre; - False sinon. - """ - return self.existe and self.get_tas() == tas - - def __lt__(self, autre): - "Agit comme une positive infinie: Toujours True." - return True - - def __gt__(self, autre): - "Agit comme une négative infinie: Toujours False." - return False - - -class TasBinomial(object): - class Noeud(object): - def __init__(self, get_tas, index, valeur=None): - self.niveau = 0 - self.parent = None - self.suivant = None - self.fils = None - self.index = index - self.ref = RefElement(self, get_tas) - if valeur == None: - valeur = index - self.valeur = valeur - - def __str__(self): - def k(x): return str(x.index) if x else 'NIL' - return '(Valeur:%s, Fils:%s, Suivant:%s)' % (k(self), k(self.fils), k(self.suivant)) - - def link(self, other): - "Crée un sous arbre." - other.parent = self - other.suivant = self.fils - self.fils = other - self.niveau += 1 - - def descendre(self, new_key): - noeud = self - assert new_key < noeud.index - noeud.index = new_key - cur = noeud - parent = cur.parent - while parent and cur.index < parent.index: - # need to bubble up - # swap refs - parent.ref.ref, cur.ref.ref = cur, parent - parent.ref, cur.ref = cur.ref, parent.ref - # now swap keys and payload - parent.index, cur.index = cur.index, parent.index - parent.valeur, cur.valeur = cur.valeur, parent.valeur - # step up - cur = parent - parent = cur.parent - - @staticmethod - def roots_merge(h1, h2): - # Union de deux tas, ordonné par degré. - # Retourne une nouvelle racine. - if not h1: - return h2 - if not h2: - return h1 - if h1.niveau < h2.niveau: - h = h1 - h1 = h.suivant - else: - h = h2 - h2 = h2.suivant - p = h - while h2 and h1: - if h1.niveau < h2.niveau: - p.suivant = h1 - h1 = h1.suivant - else: - p.suivant = h2 - h2 = h2.suivant - p = p.suivant - if h2: - p.suivant = h2 - else: - p.suivant = h1 - return h - - @staticmethod - def roots_reverse(h): - # Inverse la liste des racine du tas. - # Retourn la nouvelle racine. Nettoie aussi la référence des parents. - if not h: - return None - tail = None - suivant = h - h.parent = None - while h.suivant: - suivant = h.suivant - h.suivant = tail - tail = h - h = suivant - h.parent = None - h.suivant = tail - return h - - class __Ref(object): - def __init__(self, h): - self.tas = h - self.ref = None - - def get_ref_tas(self): - if not self.ref: - return self +class Noeud: + def __init__(self, key): + self.key = key + self.children = [] + self.degree = 0 + + +class TasBinomial: + def __init__(self): + self.arbres = [] + + def union(self, nouveau_tas): + self.arbres.extend(nouveau_tas.arbres) + self.arbres.sort(key=lambda x: x.degree) + i = 0 + while i < len(self.arbres) - 1: + if self.arbres[i].degree == self.arbres[i + 1].degree: + if self.arbres[i].key > self.arbres[i + 1].key: + self.arbres[i], self.arbres[i + + 1] = self.arbres[i + 1], self.arbres[i] + self.arbres[i].children.append(self.arbres[i + 1]) + del self.arbres[i + 1] else: - # compact - self.ref = self.ref.get_ref_tas() - return self.ref - - def get_tas(self): - return self.get_ref_tas().get_tas - - def __init__(self, list=[]): - # Populate a new heap with the (key, value) pairs in 'lst'. - # If the elements of lst are not subscriptable, then they are treated as - # opaque elements and inserted into the heap themselves. - self.racine = None - self.taille = 0 - self.ref = TasBinomial.__Ref(self) - for x in list: - try: - self.inserer(x[0], x[1]) - except TypeError: - self.inserer(x) + i += 1 - def inserer(self, key, value=None): - # Insert 'value' in to the heap with priority 'key'. If 'value' is omitted, - # then 'key' is used as the value. - # Returns a reference (of type ItemRef) to the internal node in the tree. - # Use this reference to delete the key or to change its priority. - n = TasBinomial.Noeud(self.ref.get_tas, key, value) - self.__union(n) - self.taille += 1 - return n.ref + def inserer(self, key): + nouveau_tas = TasBinomial() + nouveau_tas.arbres.append(Noeud(key)) + self.union(nouveau_tas) - def union(self, other): - # Merge 'other' into 'self'. Returns None. - # Note: This is a destructive operation; 'other' is an empty heap afterwards. - self.taille = self.taille + other.taille - h2 = other.racine - self.__union(h2) - other.ref.ref = self.ref - other.__init__() - - def min(self): - # Returns the value with the minimum key (= highest priority) in the heap - # without removing it, or None if the heap is empty. - pos = self.__min() - return pos[0].valeur if pos else None - - def extraire_min(self): - # Returns the value with the minimum key (= highest priority) in the heap - # AND removes it from the heap, or None if the heap is empty. - # - # find mininum - pos = self.__min() - if not pos: + def get_min(self): + if not self.arbres: return None - else: - (x, prev) = pos - # remove from list - if prev: - prev.suivant = x.suivant - else: - self.racine = x.suivant - fils = TasBinomial.Noeud.roots_reverse(x.fils) - self.__union(fils) - x.ref.existe = False - self.taille -= 1 - return x.valeur - - def __nonzero__(self): - # True si le tas n'est pas vide; False sinon. - return self.tas != None - - def __len__(self): - # Retourne le nombre d'élément dans le tas. - return self.taille - - def __setitem__(self, key, value): - # Insertion. - # H[key] = value équivaut à H.insert(key, value) - self.inserer(key, value) - - def __iadd__(self, other): - # Merge. - # a += b équivaut à a.union(b). - self.union(other) - return self - - def suivant(self): - # Returns the value with the minimum key (= highest priority) in the hseap - # AND removes it from the heap; raises StopIteration if the heap is empty. - if self.racine: - return self.extraire_min() - else: - raise StopIteration - - def __contains__(self, ref): - # Test whether a given reference 'ref' (of RefElement) is in this heap. - if type(ref) != RefElement: - raise TypeError - else: - return ref.dans_tas(self) + min_node = self.arbres[0] + for arbre in self.arbres: + if arbre.key < min_node.key: + min_node = arbre + return min_node.key - def __min(self): - if not self.racine: + def extraire_min(self): + if not self.arbres: return None - min = self.racine - min_prev = None - prev = min - cur = min.suivant - while cur: - if cur.index < min.index: - min = cur - min_prev = prev - prev = cur - cur = cur.suivant - return (min, min_prev) - - def __union(self, h2): - if not h2: - # nothing to do - return - - h1 = self.racine - - if not h1: - self.racine = h2 - return - - h1 = TasBinomial.Noeud.roots_merge(h1, h2) - prev = None - x = h1 - next = x.suivant - while next: - if x.niveau != next.niveau or \ - (next.suivant and next.suivant.niveau == x.niveau): - prev = x - x = next - elif x.index <= next.index: - # x becomes the root of next - x.suivant = next.suivant - x.link(next) - else: - # next becomes the root of x - if not prev: - # update the "master" head - h1 = next - else: - # just update previous link - prev.suivant = next - next.link(x) - # x is not toplevel anymore, update ref by advancing - x = next - next = x.suivant - self.racine = h1 - - -def créerTas(list=[]): - # Création d'un nouveau tas en utilisant *list* qui est une séquence de (clé, valeur) - # Avec la clé - return TasBinomial(list) + min_node = self.arbres[0] + min_idx = 0 + for i, arbre in enumerate(self.arbres): + if arbre.key < min_node.key: + min_node = arbre + min_idx = i + del self.arbres[min_idx] + tas_enfant = TasBinomial() + tas_enfant.arbres = min_node.children + self.union(tas_enfant) + return min_node.key if __name__ == "__main__": - tokens1 = [10, 12, 11, 1, 5, 22, 99, 20, 70, 60, 65, 23, 6, 4] + + # Exemple d'utilisation : + tokens1 = [10, [12, 11, 1], 5, 22, 99, [20, 70, 60, 65, 23], 6, 4] tokens2 = [80, 19, 51, 30, 82, 65, 45, 55, 75, 88, 28, 27, 3, 6, 7, 2] - tas1 = créerTas(tokens1) - tas2 = créerTas(tokens2) - h3 = créerTas() - # print(tas1.racine) - # print(tas2.racine) - # tas1.union(tas2) - # print(tas1.taille) - h3.inserer(50) - h3.inserer(3) - print(h3.racine) - print(h3.taille) - h3.inserer(5) - h3.inserer(2) - h3.inserer(24) - print(h3.racine) - print(h3.taille) + tas = TasBinomial() + tas.inserer(5) + tas.inserer(3) + tas.inserer(10) + tas.inserer(2) + tas.inserer(12) + tas.inserer(20) + + print("Min:", tas.get_min()) + print("Extract Min:", tas.extraire_min()) + print("Min:", tas.get_min())