• Aucun résultat trouvé

IFT2010 Structures de données TP1 Nicola Grenon GREN3077303 jeudi le neuf février deux mille six

N/A
N/A
Protected

Academic year: 2022

Partager "IFT2010 Structures de données TP1 Nicola Grenon GREN3077303 jeudi le neuf février deux mille six"

Copied!
1
0
0

Texte intégral

(1)

IFT2010

Structures de données

TP1

Nicola Grenon GREN3077303

jeudi le neuf février deux mille six

(2)

1. a) Non. Puisque, par exemple,

f n ( )

n

5/ 2 fait partie de

O n ( )

3 , mais pas de

O n ( )

2 ni de

( ) n

3 .

2

lim

5/ 2

0

n

n n



n

5/ 2

O n ( )

2

3

lim

5/ 2 n

n n



 

n

5/ 2

O n ( )

3

n

5/ 2

( ) n

3

n

5/ 2

( ) n

3

b) Oui, des fonctions oscillantes, par exemple:

( ) sin( ) 1 ( ) cos( ) 1

f n n

g n n

 

 

Si on prend

n

2  k ( k

N

)

, alors

f n ( )

O g n( )

, mais

g n ( )

O f n( )

, toutefois, si on prend

n

2  k

 ( k

N

)

, alors

g n ( )

O f n( )

, mais

f n ( )

O g n( )

. Ce qui fait que ni f ni g n'est d'ordre de l'autre  

n n

0. cqfd.

Pour s'en convaincre on peut simplement utiliser la méthode de la limite. lim(f/n)=0 quand n=2kpi et lim(f/n)infini quand n=2kpi+pi.

c)

f n ( )

O nlog n

 

c

00  

n

0   

n n

0 tel que

f n ( )

c n

0

log n

 

( )

g nf   n  

 

c

1 0  

n

1  

n n

1 tel que

g n ( )   c

1

  n    log   n  

Posons n = k2 ,

k



On obtient: 1 1 1/ 2 1/ 2

1

1 1/ 2 2 1/ 2

( ) log log log log

g n   c nn c n    n  2 c nn c nn

Donc:

g n ( )

O n

1/ 2

log | n n k k

2

,

N

Pour généraliser, voyons si g(n) est éventuellement non-décroissant et si n1/2logn est lisse.

 g(n) est clairement éventuellement non-décroissante puiqu'elle est composée de fonctions qui le sont également. (Racine carrée, log et plafond.)

n1/2logn

2-lisse?

g n (2 )O  (2 ) log(2 ) n

1/ 2

n

?

1/ 2 1/ 2 1/ 2 1/ 2

(2 ) log(2 ) n n

2

n

(log 2 log )

n

2

n

log 2

2

n

log n

1/ 2

(2 ) log

g n

O n n

Oui, donc lisse.

g n ( )

O n

1/ 2

log n

et ce pour tout n.

d)

T n ( ) Tn   1

Posons

n

2

2k

k

 T(1)=1 T(2)=1 T(4)=2 T(16)=3 T(256)=4 T(65536)=5 etc.

 

2

 

4

 

8

 

16

( ) 1 2 3 4 ...

T n

T n

 

T n

 

T n

 

T n

 

( ) lg lg

T n

n

(3)

Par définition on a que:  

c

0  

n

0   

n n

0 tel que

T n ( )

 

c lg lg n

Prenons n0=4 et c=2

Dont nous prouvons la validité par induction:

Base:

T (4) 2 lg lg 4

   2 ≤ 21 ok!

Hypothèse:

T n ( ) 2 lg lg

 

n

Voyons pour:

T n ( ) 2 lg lg

2

 

?

n

2

 

( ) 1 2 lg 2lg

?

T n    n ( ) 1 2 lg 2 2lg lg

?

T n     n ( ) 1 2 2lg lg

?

T n    n

ce qui est avéré.

On a donc prouvé:

T n ( ) Olg lg | n n 2 ,

2k

k

Pour généraliser pour tout n, on a que T(n) est clairement non-décroisante après n=1. lglgn est aussi clairement non-décroissante pour n≥2. Et comme lglg(2n) = lg(lg2+lgn) = lg(1+lgn) ≤ clglgn (pour tout n≥4 et c=2) la fonction lglgn est donc lisse, donc on peut généraliser et affirmer que:

 

( ) lg lg T n

O n

e) Il faut démontrer que

g n ( )

n

O(1) ssi  

k 0

tel que

g n ( )

O n ( )

k .

Si

g n ( )

n

O(1), alors, par définition,  

c

0  

n

0   

n n tel que g n

0

( )

n

c1

Comme c est une constante définie, on peut dire (à nouveau par la définition, en prenant 1 comme constante multiplicative de la fonction):

( ) ( )

c

g n

O n

Il existe donc clairement un k > 0 puisqu'on a déterminé c depuis la définition de grand O.

* Je sais que cet énoncé est court et simple, mais je crois qu'il n'y a pas plus formel que l'utilisation de la définition.

(4)

2.

Il n'y a aucune façon d'implémenter en même temps les trois opérations pop, push et getMin en O(1) si on veut que getMin donne toujours une réponse correcte. Sous ces contraintes, on ne peut l'implémenter que pour qu'il donne une bonne réponse que dans certaines conditions. Voir le code suivant dans lequel les trois fonctions sont en O(1) et getMin peut retourner la valeur minimum si et seulement si la fonction pop n'a pas été utilisée depuis la dernière fois que la pile était vide ou n'a été utilisée que sur des éléments ne constituant pas la valeur minimun et un nombre de fois moins grand que le nombre total d'élément ayant la valeur minimale. Si tel n'est pas le cas, pour respecter l'ordre O(1), on perd la capacité de fournir une réponse valable à getMin.

/* IFT2010 - TP1 - Numéro 2 */

import java.util.*;

public class MiniPile {

private LinkedList data; // Contient les valeurs de la pile private int minimum, // Note le plus petit élément

frequence; // Combien de fois on retrouve cet élément minimum.

// Constructeur MiniPile() {

data = new LinkedList();

minimum = Integer.MAX_VALUE;

}

// Méthode d'ajout

public void push(int nombre) { if (nombre < minimum) {

minimum = nombre;

frequence = 1;

} else if (nombre == minimum) frequence++;

data.addFirst(new Integer(nombre));

}

// Méthode de retrait public int pop() {

if (data.isEmpty())

throw new StackUnderflowException("Pile vide");

else {

int monInt = ((Integer) data.poll()).intValue();

// On réinitialise la valeur minimum qui sera à nouveau correcte.

if (data.isEmpty()) minimum = Integer.MAX_VALUE;

// On vérifie si getMin est encore valable else if (monInt == minimum)

if (frequence-- < 2)

minimum = Integer.MIN_VALUE; // Flag: on a perdu le minimum de vue.

return monInt;

} }

// Méthode pour savoir quelle est la valeur minimale dans la pile.

public int getMin() { if (data.isEmpty())

throw new StackUnderflowException("Pile vide");

else if (minimum == Integer.MIN_VALUE)

throw new StackUnknownMinimumException("Minimum inconnu");

else

return minimum;

}

// Exceptions

static class StackUnderflowException extends RuntimeException {

private StackUnderflowException(String message) { super(message); } } static class StackUnknownMinimumException extends RuntimeException {

private StackUnknownMinimumException(String message) { super(message); } } }

Pour pouvoir avoir un getMin toujours utilisable dans la pile, il faudrait prévoir une façon quelconque de noter l'ordre des éléments selon leur valeur. Par exemple avec une deuxième liste dans laquelle push placerait les éléments en ordre. Mais alors push serait en O(n). Ou alors en effectuant une recherche séquentielle sur la valeur minimale dans la pile à chaque appel de getMin, ce qui serait aussi en O(n).

Dans tous les cas, je ne crois pas qu'il soit possible d'avoir les 3 méthodes en O(1) pour TOUS les cas.

(5)

3.

Pour faire cette implémentation, il faut simplement, que ce soit dans l'ajout d'un élément ou alors au niveau du retrait d'un élément, transvider une pile dans l'autre, effectuer l'opération, puis réinverser la pile contenant les informations. Dans l'implémentation que je présente ici, le double transvidage est fait dans l'ajout:

/* IFT2010 - TP1 - Numéro 3 */

import java.util.*;

public class Queue {

private Stack maPile; // Contient les valeurs de la queue.

private int nombreItems; // Contient le nombre d'items dans la pile

// (Pas vraiment utile pour cette implémentation, mais pour la clarté...) // Constructeur

Queue() {

maPile = new Stack();

nombreItems = 0;

}

// Méthode d'ajout

public void enqueue(Object o) { Stack tmp = new Stack();

while (!maPile.empty()) tmp.push(maPile.pop()); // On inverse la pile

tmp.push(o); // Ajout de l'élément

nombreItems++;

while (!tmp.empty()) maPile.push(tmp.pop()); // On remet dans son sens d'origine }

// Méthode de retrait public Object dequeue() {

if (isEmpty())

throw new QueueUnderflowException("Queue vide");

else {

nombreItems--;

return maPile.pop();

} }

// Méthode de test du cas de queue vide public boolean isEmpty() {

return nombreItems == 0; // On pourrait utiliser maPile.isEmpty() }

// Exceptions

static class QueueUnderflowException extends RuntimeException {

private QueueUnderflowException(String message) { super(message); } } }

Alors dequeue et isEmpty sont en O(1) de façon évidente et enqueue prend 2n+3 (n pour chaque inversion (while)) et donc est d'ordre O(n).

(6)

4. a)

En utilisant une liste doublement chaînée (ou simplement chaînée, ce qui serait suffisant), les fonctions push, peek ou pop sont directement transmises à la structure sous-jacente en s'insérant, lisant ou retirant l'élément à la position 0 de la liste. Ces 3 fonctions sont clairement de O(1) puisqu'elles n'interagissent qu'avec le premier maillon de la chaîne.

La fonction count est elle aussi directe, mais pourrait également être implémentée par un compteur indépendant (incrémentée/décrémentée dans push/pop) dans notre ADT. De la même façon que les premières fonctions, comme on n'accède qu'au contenu d'une variable privée de l'ADT, on reste dans O(1).

Les fonctions dup et exch sont également d'ordre O(1) puisqu'elles s'implémentent en utilisant un nombre fixe d'opérations non récurrentes. Ainsi, dup a besoin d'un peek et d'un push uniquement qui sont eux-mêmes O(1). Alors que exch a besoin de deux peek, deux pop et deux push et fait le transfert au moyen de deux variables temporaires de taille unitaire.

La fonction index nécessite le parcours de la liste jusqu'à la position relative souhaitée, donc O(n) ainsi qu'un push de la valeur associée.

Il y a deux façons d'implémenter le clear. Soit en se créant une nouvelle liste vide et en laissant le soin au

«garbage collector» de faire le ménage pour disposer de l'ancienne liste ou alors en la vidant élément par élément (au moyen de pop). L'opération nécessite O(n) puisqu'il faut éliminer n objets de toute façon.

La fonction la plus complexe à implémenter est le roll, qui nécessite un soutient temporaire de l'information d'ordre n. Les valeurs (possiblement jusqu'à n) sont stockées dans un tableau en n opérations, puis relues en au maximum n autres opérations (puisqu'on fait un mod sur les décalages). On a donc un total de 2n+c opérations effectuées, où c représente une constante O(1) pour les opérations secondaires, telles la lecture des variables n et j, l'initialisation du tableau, le redressement de j, etc. On obtient donc que la fonction se déroule en O(n).

b) Le résultat de la suite d'opérations donne ce contenu de pile: |– 1 2 3 4 1 2 3 4 Pour s'en convaincre on peut le faire manuellement ou avec:

public class TestPSPile {

public static void main(String[] args) { PSPile pile = new PSPile();

pile.push(new Integer(1));

pile.push(new Integer(2));

pile.push(new Integer(3));

pile.push(new Integer(4));

pile.push(new Integer(1));

pile.push(new Integer(2));

pile.push(new Integer(3));

pile.push(new Integer(4));

pile.push(new Integer(1));

pile.push(new Integer(2));

pile.push(new Integer(3));

pile.push(new Integer(4));

pile.dup();

pile.push(new Integer(3));

pile.index();

pile.exch();

pile.pop();

pile.push(new Integer(-2));

pile.roll();

pile.pop();

pile.pop();

pile.index();

pile.index();

pile.roll();

while (pile.count() > 0) {

System.out.print(((Integer) pile.peek()).intValue() + ", ");

pile.pop();

}System.out.println();

} }

/* Exécution:

4, 3, 2, 1, 4, 3, 2, 1,

Appuyez sur une touche pour continuer...

*/

(7)

c) Voici l'implémentation de PSPile.java  PSPile.class

/* * IFT2010 - TP1 - Numéro 4 * * par: Nicola Grenon * GREN30077303 *

* Created on February 5, 2006, 1:00 AM */

import java.util.*;

public class PSPile{

private ListeChaine pile; // Contient les valeurs de la pile.

// Constructeur PSPile() {

pile = new ListeChaine();

}

// Ajouter un élément à la pile public void push(Object o) {

pile.insert(0, o);

}

// Lecture de l'élément au sommet de la pile public Object peek() {

if (count() > 0) return pile.get(0);

else

throw new PSPileUnderflowException("PSPile vide!");

}

// Efface l'élément au sommet de la pile public void pop() {

if (count() > 0) pile.remove(0);

else

throw new PSPileUnderflowException("PSPile vide!");

}

// Compte les éléments dans la pile public int count() {

return pile.size();

}

// Vide la pile public void clear() {

while (count() > 1) pop();

}

// Dupliquer l'élément au sommet de la pile public void dup() {

push(peek());

}

// Dupliquer un élément arbitraire de la pile public void index() {

int position = ((Integer) peek()).intValue(); pop();

push(pile.get(position));

}

// Échange les deux éléments du dessus de la pile public void exch() {

Object o1 = peek(); pop();

Object o2 = peek(); pop();

push(o1);

push(o2);

}

(8)

// Fait rouler n élément(s) j fois public void roll() {

int j = ((Integer) peek()).intValue(); pop();

int n = ((Integer) peek()).intValue(); pop();

Object[] cycle = new Object[n];

for (int i = 0; i < n; i++) { // On remplit un tableau des objets à rouler cycle[i] = peek(); pop();

}

// On ajuste j (cas plus grand que n ou négatif) if (j < 0) {

j=-j; j=j%n; j=n-j;

} else j=j%n;

for (int i = j-1; i >= 0; i--) // On sort la première partie des éléments push(cycle[i]);

for (int i = n-1; i >= j; i--) // On sort la deuxième partie des éléments push(cycle[i]);

}

// Exceptions

static class PSPileUnderflowException extends RuntimeException {

private PSPileUnderflowException(String message) { super(message); } } }

Références

Documents relatifs

On voit parcontre qu'on peut l'améliorer à 100% (dans notre test) avec des données triées. Ceci s'explique par le fait que l'on va systématiquement essayer de placer le cas le plus

La seconde partie effectue une fouille en profondeur en marquant chaque nouveau noeud rencontré d'une valeur alternant entre gauche et droite. Si en

Comme on applique au passage à chaque dessinateur les transformations que devra subir le dessinateur final, on obtient deux listes de

La première difficulté à laquelle nous sommes confrontés est la complexité du problème. En apparence simple, il se subdivise en une multitude de contraintes se

Chaque fois qu'on voudra ajouter une chaîne de caractère à notre base de données, on vérifiera donc si elle est déjà présente dans la liste de toutes celles déjà employées et

Donc: vote, électeur, carte d'identité, liste électorale, élection, liste des élections, liste d'émargement, option de vote....

Le logiciel affiche un message d'information, ferme la session et après quelques secondes réinitialise l'écran.. 

Le logiciel affiche un message d'information, ferme la session et après quelques secondes réinitialise l'écran.