Automne 1998
Automne 1998
type arbre ::= Feuille nat | Noeud nat arbre arbreDans de tels arbres, tant les feuilles que les noeuds internes conservent de l'information (nombre naturel).
Définissons aussi quelques opérations sur ds tels arbres:
infos :: arbre -> sequence{nat} infos(Feuille n) = [n] infos(Noeud n a1 a2) = infos(a1) || [n] || infos(a2) nbNoeuds :: arbre -> nat nbNoeuds(Feuille n) = 1 nbNoeuds(Noeud n a1 a2) = nbNoeuds(a1) + nbNoeuds(a2) + 1
Montrez (par induction) que pour tout arbre a, la propriété suivante est satisfaite:
nbNoeuds(a) = length( infos(a) )
Note: Vous pouvez utiliser la propriété suivante (sans la démontrer):
Algorithme produit( a, b: nat ) prod: nat prod <-- 0 TANTQUE b > 0 FAIRE SI b MOD 2 = 1 ALORS prod <- prod + a FIN b <- b / 2 a <- 2 * a FIN RETOURNER prod FIN
Quelle est la complexité asymptotique de cet algorithme? Justifiez.
[9] b) L'algorithme suivant permet de trouver le minimum et le maximum d'une séquence s de nombres naturels (le résultat est une paire de nombres, paire indiquée par ``(min, max)''):Algorithme min_max( s: sequence{nat} ) (min, max): (nat, nat) SI length(s) = 1 ALORS min <- s[0] max <- s[0] SINON (min1, max1) <- min_max( s[0..length(s)/2-1] ) (min2, max2) <- min_max( s[length(s)/2..length(s)-1] ) min <- min1 < min2 ? min1 : min2 max <- max1 > max2 ? max1 : max2 FIN RETOURNER (min, max) FIN
Quelques éléments à souligner:
public class C implements T {
private PriorityQueue pq;
private int suivant;
public C() {
pq = new PriorityQueue( new IntegerComparator() );
suivant = 1;
}
public int m1() { return pq.size(); }
public boolean m2() { return pq.isEmpty(); }
public Object m3() throws TException {
try {
return pq.minElement();
}
catch( RuntimeException ce ) {
throw new TException( "??" );
}
}
public void m4( Object element ) {
pq.insertItem( new Integer(suivant), element );
suivant = (suivant % Integer.MAX_VALUE) + 1;
}
public Object m5() throws TException {
if ( ! pq.isEmpty() ) {
return pq.removeMinElement();
} else {
throw new TException( "??" );
}
}
}
private Object trouver( Sequence s, Object k, int low, int high ) { // On suppose qu'un Comparator c est accessible pour comparer les cles. if ( low > high ) return NO_SUCH_KEY; else if ( low == high ) { Item item = ((Item) s.elemAtRank(low)); return item.key() == k ? item.element() : NO_SUCH_KEY; } else { Item iteml = ((Item) s.elemAtRank(low)); Item itemh = ((Item) s.elementAtRank(high)); if ( c.isEqualTo(k, iteml.key()) ) return iteml.element(); if ( c.isEqualTo(k, itemh.key()) ) return itemh.element(); if ( c.isGreaterThan(k, iteml.key()) && c.isLessThan(l, itemh.key()) ) return trouver( s, k, low+1, high-1 ); return NO_SUCH_KEY; } }
L'appel initial à cette procédure pour fouiller une séquence s se fait alors comme suit:
return trouver( s, k, 0, s.size()-1 );
Quelle sera la complexité asymptotique de cette méthode (en fonction de la taille de s, qu'on suppose égale à n) si la séquence s est mise en oeuvre avec une liste doublement chaînée plutôt qu'avec un tableau d'items? Justifiez votre réponse.
6. Tas (16 pts) Note: Dans les questions qui suivent, la structure de tas est toujours telle que la clé minimum est conservée à la racine de l'arbre (conceptuellement) associé au tas. [4] a) Dans une structure de tas vue comme un arbre binaire complet partiellement ordonné, que peut-on dire concernant la position dans le tas de la clé la plus grande, en supposant que chaque clé est unique? Expliquez birèvement. [4] b) Dans une structure de tas représentée par un tableau d'items, est-ce qu'un tableau trié en ordre croissant forme effectivement un tas? Expliquez! [8] c) Soit l'algorithme suivant qui calcule la somme des k plus petits éléments de A, un tableau d'entiers naturels:Algorithme sommePartielle( A: array[1..n] OF nat, k: nat ) somme: nat DEBUT construireTas( A ) // Definition omise: cf. plus bas. somme <- 0 POUR j <- 1 A k FAIRE somme <- somme + A[1] echanger A[1] <-> A[n-j+1] entasser( A, 1, n-j ) FIN RETOURNER somme FIN Algorithme entasser( A: array[1..n] OF nat, i: nat, k: nat ) DEBUT SI 2*i <= k & A[2*i] < A[i] ALORS min <- 2*i SINON min <- i SI 2*i+1 <= k & A[2*i+1] < A[min] ALORS min <- 2*i+1 SI min != i ALORS echanger A[i] <-> A[min] entasser( A, min, k ) FIN
Supposons alors une classe Arbre définie (partiellement) comme suit:
public class Arbre implements SimpleTree { private NoeudEF racine; private int taille; ... }
Écrivez (en Java) la classe locale permettant, pour un noeud donné, d'énumerer ses enfants. Plus précisément, définissez la classe locale EnumerationChildren dont une instance est créée lors d'un appel à children.
public Enumeration children( Position p ) { return new EnumerationChildren(p); }