Skip to content
Snippets Groups Projects
Commit ac0f90ae authored by Robin VAN DE MERGHEL's avatar Robin VAN DE MERGHEL :computer:
Browse files

Adding algo TDs

parent ddbad886
No related branches found
No related tags found
No related merge requests found
---
title: TD0
author: VAN DE MERGHEL Robin
date: 2023
lang: fr
geometry: margin=2cm
---
# Exercice 0.2
## 1.
......
No preview for this file type
---
title: TD1
author: VAN DE MERGHEL Robin
date: 2023
lang: fr
geometry: margin=2cm
---
# 1.3
## 1.
......
No preview for this file type
......@@ -389,4 +389,171 @@ Liste concatener(Liste l1, Liste l2) {
}
```
Le temps est bien en $O(1)$ car on ne fait que modifier les pointeurs.
\ No newline at end of file
Le temps est bien en $O(1)$ car on ne fait que modifier les pointeurs.
## Question 2
> **Expliquez comment utiliser les listes pour implémenter le TDA ensemble disjoint. Vous pourrez utiliser la réponse à la question précédente.**
**Rappel du cours :**
- `creerPartition(int n)` crée une partition où chaque partie est un singleton de $[n]$
- `trouver(partie p, int x)` doit donner le représentant de la partie contenant $x$
- `union(partie p, int x, int y)` doit faire l'union de sparties contenant $x$ et $y$
### Ma version
```ruby
enregistrement Liste {
Element[] tab
int taille
}
enregistrement Element {
int val
Partie p
}
enregistrement Partie {
int id
Element debutPartie
Element finPartie
}
```
```ruby
Partie vide = -1
Element vide = -1
# O(1)
# Car on a juste une allocation
Element creerElement(int x) { # x est un entier
Element e = allocation()
e.val = x
e.p = vide
return e
}
# O(n)
# Car on doit allouer n éléments
# Chaque allocation est en O(1)
Liste creerPartition(int n) {
Liste l = allocation()
l.tab = allocation(n)
l.taille = n
for (int i = 0; i < n; i++) {
l.tab[i] = creerElement(i)
}
return l
}
# O(1)
# Car on a un tableau, et on peut accéder à l'élément en O(1)
Partie trouver(Partie p, int x) {
return p.tab[x].p
}
# O(n)
# Car pour chaque élément de la liste, on doit changer le pointeur
# Changer le pointeur est en O(1)
void union(Partie p, int x, int y) {
Partie px = trouver(p, x)
Partie py = trouver(p, y)
Partie plusGrand
Partie plusPetit
Si taille(px) > taille(py) {
plusGrand = px
plusPetit = py
} Sinon {
plusGrand = py
plusPetit = px
}
Element e = plusPetit.debutPartie
Tant que e != vide, Faire {
e.p = plusGrand
e = e.suiv
plusPetit.finPartie.suiv = e
plusPetit.finPartie = e
}
plusGrand.finPartie.suiv = plusPetit.debutPartie
plusGrand.finPartie = plusPetit.finPartie
return p
}
```
### Correction
```ruby
enregistrement Partition {
Liste<Liste<int>> parties
}
Partition creerPartition(int n) {
Partition p;
p.l = creerLise();
Pour i <- 1 à n, Faire {
s = creerListe();
insererDebut(s, i);
insererDebut(p.l, s);
}
Retourner p;
}
int trouver(Partition p, int x) {
Cellule c = debutliste(p.l)
Tant que finListe(c) == Faux, Faire {
Cellule c2 = debutListe(val(c))
Tant que finListe(c2) == Faux {
Si x == valeur(c2) {
Retourner valeur(c)
}
c2 = suivant(c2)
}
c = suivant(c)
}
Retourner -1
}
```
Pour `trouver` : On suppose toujours que valeur suivant et debutListe sont en $O(1)$.
La boucle `Tant Que` est extérieure fait au plus $k$ itérations, $k$ le nombre de parties.
Pour chaque itération $i$, le nombre maximum d'itérations de la boucle est le nombre d'éléments de la partie parcourure à l'itération $i$, nommons cette taille $n_i$.
Complexité en temps :
$$\sum_{i=1}^k n_i$$
Comme les parties sont disjointes, et que l'union des parties c'est l'ensemble à partitionner, $\sum_{i=1}^k = n_i = n$, où $n$ est la taille de l'ensemble à partitionner.
Donc, la complexité est $\sum_{i=1}^k n_i = n$.
```ruby
Partition union(Partition p, int x, int y) {
l1 = trouver2(p,x) # O(n)
l2 = trouver2(p,y) # O(n)
concaténer(l1,l2) # O(n) ou O(1) selon l'implémentation
supprimer(p.l,l2) # O(nombre de parties) <= O(n)
retourner p
}
# On définit trouver 2 :
# Même chose que trouver, sauf que l'on retourne la liste contenant x
# n = la taille de l'ensemble partitionné par p
```
No preview for this file type
# Exercice 3.1
## Question 1
> **On implémente une arborescence avec le tableau `PERE`, i.e. dans chaque case on stocke l'index du père, et pour la racine on stocke la valeur $-1$. Proposer un algorithme (avec la meilleure complexité) pour chacune des opérations suivantes :**
> - La racine de l'arbre
> - La hauteur $h$ de l'arbre
> - La liste des fils d'un noeud $x$
> - Le sous-arbre issu d'un noeud $x$
> - Tester si $x$ et $y$ sont frères
```ruby
# Racine de l'arbre
# On cherche le premier élément du tableau qui vaut -1
int racine(int[] pere) {
int i = 0;
while (pere[i] != -1) {
i++;
}
return i;
}
```
La complexité en temps $O(l)$, où $l$ est le nombre d'itérations de `Tant que`. Comme $l$ peut être égal à $n-1$, la complexité en temps est $O(n)$.
```ruby
# Hauteur de l'arbre
int hauteurNoeud(int Pere[n], int x) {
int h = 0;
int y = x;
while (Pere[y] != -1) {
h = h + 1;
y = Pere[y];
}
return h + 1;
}
```
Si $h_x$ c'est la distance de la racine au noeud $x$, le nombre d'itérations c'est $h_x$. Donc la complexité en temps est $O(h_x)$.
```ruby
# Hauteur de l'arbre
int hauteur(int Pere[n]) {
int h = 0;
int i = 0;
for (i = 0; i < n; i++) {
int h_i = hauteurNoeud(Pere, i);
if (h_i > h) {
h = h_i;
}
}
return h;
}
```
Complexité : $n$ itérations, chaque itérations $O(h_i)$. Donc au total $\sum_{i=1}^n O(h_i) = O(\sum_{i=1}^n h_i) = O(n \cdot h)$.
```ruby
# Liste des fils d'un noeud x
Liste listeFils(int Pere[n], int x) {
Liste liste = ListeVide();
int i = 0;
for (i = 0; i < n; i++) {
if (Pere[i] == x) {
liste = insererDebut(liste, i);
}
}
return liste;
}
```
Si `insererDebut` est $O(1)$, la complexité en temps est $O(n)$.
```ruby
bool frere(int Pere[n], int x, int y) {
retourner Pere[x] == Pere[y];
}
```
La complexité en temps est $O(1)$ car on n'accède qu'à deux cases du tableau.
```ruby
# Ensemble des feuilles
Liste feuilles(int Pere[n]) {
bool[n] f;
# On met à vrai toutes les cases du tableau
for (i = 0; i < n; i++) {
f[i] = true;
}
for (i=0; i < n; i++) {
f[Pere[i]] = false;
}
Liste l = creerListe();
for (i = 0; i < n; i++) {
if (f[i]) {
l = insererDebut(l, i);
}
}
return l;
}
# Sous-arbre issu d'un noeud x
liste sousArbre(int Pere[n], int x) {
Liste l = feuilles(Pere);
for (Feuille feuille in l) {
if (*En remontant comme dans la fonction hauteurNoeud on rencontre x*) {
*ajouter tous les noeuds entre f et x dans r*
}
}
}
```
On peut vérifier que la complexité en temps est $O(n)$.
## Question 2
> **Comparer avec une implémentation où chaque noeud stocke une référence vers sont père, un premier fils vers sont frère de droite.**
```mermaid
graph TD
A(Noeud) --> C(Pere)
A --> B(Frere de droite)
A --> D(Premier fils)
```
```mermaid
graph TD
5 --> 1
1 --> 5
1 --> 1
5 --> 2
2 --> 4
4 --> 2
2 --> 5
2 --> 3
3 --> 5
3 --> 7
7 --> 5
```
Le graphe ci-dessus représente les relations de l'arbre suivant :
```mermaid
graph TD
5 --> 1
5 --> 2
5 --> 3
5 --> 7
2 --> 4
```
```ruby
enregistrement arbre {
noeud racine
}
enregistrement noeud {
noeud pere
noeud filsG
noeud frereD
T val
}
fils(noeud n) {
l = creerListe();
noeud d = n.filsG;
while (d != null) {
l = insererDebut(l, d);
d = d.frereD;
}
return l;
}
\ No newline at end of file
---
title: TD4 Listes
author: VAN DE MERGHEL Robin
date: 2023
lang: fr
geometry: margin=2cm
---
# Exercice 4.1
> **On a les codes suivants :**
......@@ -84,20 +92,20 @@ On a donc $c_k \leq 1$ quand $n \geq \log_5(n)$. Donc la complexité est au pire
On a :
$$\begin{align}
$$\begin{aligned}
(n+a)^b &= \sum_{k=0}^b \binom{b}{k} a^{b-k} n^k \\
&= n^k + \alpha_1 n^{k-1} + \alpha_2 n^{k-2} + \dots + \alpha_{k-1} n + \alpha_k \\
\end{align}$$
\end{aligned}$$
Avec $\alpha_i = \binom{b}{i}$.
On a donc :
$$\begin{align}
$$\begin{aligned}
O((n+a)^b) &= O(n^b + \alpha_1 n^{b-1} + \alpha_2 n^{b-2} + \dots + \alpha_{b-1} n + \alpha_b) \\
&= O(n^b) + O(\alpha_1 n^{b-1}) + O(\alpha_2 n^{b-2}) + \dots + O(\alpha_{b-1} n) + O(\alpha_b) \\
&= O(n^b) + O(n^{b-1}) + O(n^{b-2}) + \dots + O(n) + O(1) \\
\end{align}$$
\end{aligned}$$
On a $O(1)$ négligeable par rapport à $O(n)$, puis $O(n)$ négligeable par rapport à $O(n^2)$, etc. Jusqu'à $O(n^{b-1})$ qui est négligeable par rapport à $O(n^b)$. Donc $O((n+a)^b) = O(n^b)$.
......
File added
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment