Académique Documents
Professionnel Documents
Culture Documents
www.hichamhatimi.com
I. Méthodes de tri
1- Définition
Principe
Comparaison 2 à 2 des éléments adjacents et
échange s'ils ne sont pas ordonnés. Le
programme s'arrête lorsqu'on parcours la
liste sans faire d'échange Comme les bulles,
les plus grands éléments remontent en fin de
liste
3
I. Méthodes de tri
2- Tri à bulles
Exercice
4
I. Méthodes de tri
2- Tri à bulles
Implémentation
T = [25,15,56,4,89,23,6]
print("Avant le tri : ",T)
triBulles(T)
print("Apres le tri :",T)
6
I. Méthodes de tri
3- Tri par sélection
Principe :
Recherche du plus petit élément du tableau et
échange avec le premier élément
Recherche du plus petit élément du tableau entre
les positions 1 et n-1 et échange avec le second
élément
...
Recherche du plus petit élément entre les positions
n-2 et n-1 et échange avec l' élément en position n-
2
7
Exemple :
T =[ 28, 14, 16, 5, 11, 3, 22]
Etape 0 : [3, 14, 16, 5, 11, 28, 22]
Etape 1 : [3, 5, 16, 14, 11, 28, 22]
Etape 2: [3, 5, 11, 14, 16, 28, 22]
Etape 3: [3, 5, 11, 14, 16, 28, 22]
Etape 4: [3, 5, 11, 14, 16, 28, 22]
Etape 5: [3, 5, 11, 14, 16, 22, 28]
8
I. Méthodes de tri
3- Tri par sélection
Exercice
9
I. Méthodes de tri
3- Tri par sélection
Implementation
10
I. Méthodes de tri
3- Tri par sélection
Exemple d'utilisation
T = [25,15,56,4,89,23,6]
print("Avant le tri : ",T)
triSelection(T)
print("Apres le tri :",T)
11
I. Méthodes de tri
4- Tri par insertion
13
I. Méthodes de tri
4- Tri par insertion
Implementation
def tri_insertion(T) :
n=len(T)
for i in range(1,n):
x=T[i]
j=i
while j>0 and T[j-1]>x :
T[j]=T[j-1]
j=j-1
T[j]=x
14
I. Méthodes de tri
4- Tri par insertion
Exemple d'utilisation
T = [25,15,56,4,89,23,6]
print("Avant le tri : ",T)
tri_insertion(T)
print("Apres le tri :",T)
15
I. Méthodes de tri
5- Tri rapide(QuickSort)
Exemple :
Soit la liste :
L = [ 4, 23, 3, 42, 2, 14, 45, 18, 38, 16 ]
Prenons comme pivot la dernière valeur
pivot = 16
Nous obtenons donc :
L1 = [4, 14, 3, 2]
L2 = [23, 45, 18, 38, 42]
A cette étape voici l'arrangement de L :
L =17L1 + pivot + L2 = [4, 14, 3, 2, 16, 23, 45, 18, 38, 42]
I. Méthodes de tri
5- Tri rapide(QuickSort)
def triRapide(T,premier,dernier) :
if premier < dernier :
indPivot=partitionner(T,premier,dernier)
triRapide(T,premier, indPivot-1)
triRapide(T, indPivot+1,dernier)
19
I. Méthodes de tri
5- Tri rapide(QuickSort)
Fonction partitionner
def partitionner(T,premier,dernier) :
j=premier
for i in range(premier,dernier) :
if T[i]<=T[dernier] :
T[i],T[j]=T[j],T[i]
j=j+1
T[dernier],T[j]=T[j],T[dernier]
return j
20
I. Méthodes de tri
5- Tri rapide(QuickSort)
Exemple d'utilisation
T = [25,15,56,4,89,23,13]
print("Avant le tri : ",T)
triRapide(T,0,6)
print("Apres le tri :",T)
21
I. Méthodes de tri
6- Tri par fusion
22
I. Méthodes de tri
6- Tri par fusion
23
I. Méthodes de tri
6- Tri par fusion
Exemple
24
I. Méthodes de tri
6- Tri par fusion
Implémentation
25
I. Méthodes de tri
6- Tri par fusion
Fonction fusion
def fusion(L1, L2):
res = []
ind1, ind2 = 0, 0
while ind1 < len(L1) and ind2 < len(L2):
if L1[ind1] <= L2[ind2]:
res = res + [L1[ind1]]
ind1 = ind1+1
else:
res = res + [L2[ind2]]
ind2 = ind2+1
if ind1!=len(L1):
res=res+L1[ind1:]
if ind2!=len(L2):
res=res+L2[ind2:]
26
return res
I. Méthodes de tri
6- Tri par fusion
Fonction triFusion
def triFusion(ls):
if len(ls) <= 1:
return ls
moitie = len(ls) // 2
L1= triFusion(ls[:moitie])
L2 = triFusion(ls[moitie:])
return fusion(L1,L2)
27
I. Méthodes de tri
6- Tri par fusion
Exemple d'utilisation
T = [25,15,56,4,89,23,6]
print("Avant le tri : ",T)
T=triFusion(T)
print("Apres le tri :",T)
28
II. Les arbres
1) Introduction
left right
Nœud : Nœud :
Value Value
29
II. Les arbres
2) Terminologie
Tout d'abord, chaque élément d'un arbre se nomme un
nœud. Les nœuds sont reliés les uns aux autres par des
relations d'ordre ou de hiérarchie. Ainsi on dira qu'un
nœud possède un père, c'est à dire un nœud qui lui est
supérieur dans cette hiérarchie. Il possède
éventuellement un ou plusieurs fils.
31
32
II. Les arbres
3) Types d'arbres
Il 'existe deux types d'arbres
Les arbres binaires
Les arbres n-aires
33
II. Les arbres
4) Parcourir un arbre en profondeur
Le parcours en profondeur permet d'explorer l'arbre en explorant
jusqu'au bout une branche pour passer à la suivante.
Les types de parcours en profondeur sont :
• Postfixe
tout Nœud est suivi des nœuds de son sous-arbre Gauche puis des
nœuds de son sous-arbre Droit
• Infixe
tout Nœud est précédé des nœuds de son sous-arbre Gauche et suivi
des nœuds de son sous-arbre Droit
• Suffixe
tout Nœud est précédé des nœuds de son sous-arbre Gauche et des
nœuds de son sous-arbre Droit
34
II. Les arbres
4) Parcourir un arbre en profondeur
• Postfixe : 1-2-3-4-5-6-7-8-9-
10
• Infixe : 4 – 3 -5 – 2-6-7-1-9-
8-10
• Suffixe :4-5-3-7-6-2-9-10-8-1
35
II. Les arbres
4) Parcourir un arbre en largeur
Parcourir un arbre en largeur consiste à visiter les nœuds
niveau par niveau depuis la racine.
Par exemple, le résultat pour cet arbre sera :
12 - 1 - 7- 91- 67- 61- 82- 32 - 45 - 50 - 40
36
II. Les arbres
5) Application sous Python
Pour construire un arbre binaire sous Python on
peut utiliser les listes ou autre structures de
données. Dans cette partie nous allons utilisé les
listes pour construire et gérer un arbre binaire. La
liste sera sous la forme suivante:
[donnée, sous_arbre_gauche, sous_arbre_droite]
38
II. Les arbres
5) Application sous Python
Parcours en profondeur
Exemple :
def prefixe(arbre): def infixe(arbre):
if arbre!=[None]: if arbre!=[None]:
print(arbre[0]) infixe (arbre[1])
prefixe(arbre[1]) print(arbre[0])
prefixe(arbre[2]) infixe(arbre[2])
def suffixe(arbre):
if arbre!=[None]:
suffixe(arbre[1])
suffixe (arbre[2])
39
print(arbre[0])
II. Les arbres
5) Application sous Python
Parcours en profondeur
Exemple d'exécution :
Arb=[15, [7, [6, [None], [None]],[9, [None], [None]]],
[20, [None], [25, [None], [None]]]]
print("Affichage prefixe:")
prefixe(Arb)
40
II. Les arbres
5) Application sous Python
Parcourir un arbre en largeur
Pour programmer une telle opération, on peut utiliser les Files.
L'algorithme de la fonction sera :
affichageLargeur(a):
F : File #File FIFO
Enfiler(a,F) #enfiler la racine a dans la file F
tantque non vide(F):
n=Défiler(F)
Afficher(val(n))
si non vide(filsGauche(n)):
Enfiler(filsGauche(n),F)
si non vide(filsGauche(n)):
Enfiler(filsDroit(n),F)
41
II. Les arbres
5) Application sous Python
Parcourir un arbre en largeur
En python :
def parcoursLargeur(a):
F=[]
F.append(a)
while F!=[]:
n=F.pop(0) #Equiv : n=F[0] et del F[0]
print(n[0])
if n[1]!=[]:
F.append(n[1])
if n[2]!=[]:
F.append(n[2])
Arb=[15, [7, [6, [], []],[9, [], []]], [20, [], [25, [], []]]]
print("Affichage en largeur:")
parcoursLargeur(Arb)
42
II. Les arbres
6) Tri Maximier(tri par tas)
L'idée qui sous-tend cet algorithme consiste à voir le tableau comme un arbre
binaire. Le premier élément est la racine, le deuxième et le troisième sont les
deux descendants du premier élément, etc. Ainsi le ne élément a pour enfants
les éléments 2n et 2n+1. Si le tableau n'est pas de taille 2 1, les branches ne
se finissent pas toutes à la même profondeur. Dans l'algorithme, on cherche à
obtenir un tas, c'est-à-dire un arbre binaire vérifiant les propriétés suivantes
(les deux premières propriétés découlent de la manière dont on considère les
éléments du tableau) :
la différence maximale de profondeur entre deux feuilles est de 1 (toutes les
feuilles se trouvent sur la dernière ou sur l'avant-dernière ligne) ;
les feuilles de profondeur maximale sont « tassées » sur la gauche.
chaque nœud est de valeur supérieure (resp. inférieure) à celles de ses deux
fils, pour un tri ascendant (resp. descendant).
Il en découle que la racine du tas (le premier élément) contient la valeur
maximale (resp. minimale) de l'arbre. Le tri est fondé sur cette propriété
43
II. Les arbres
6) Tri Maximier(tri par tas)
def Tri_Maximier_par_tas(tab):
n = len(tab)
for debut in range(n- 1,-1,-1):
faire_tas(tab, debut)
for fin in range(n- 1,-1,-1):
tab[fin], tab[0] = tab[0], tab[fin]
faire_tas(tab[0:fin], 0)
44
II. Les arbres
6) Tri Maximier(tri par tas)
def faire_tas(tab, debut):
fin=len(tab)
pere = debut
while 2*pere + 1 < fin:
fils1 = 2*pere + 1
fils2 = 2*pere + 2
GF=fils1
if fils2 < fin and tab[fils1] < tab[fils2]:
GF=fils2
if tab[pere] < tab[GF]:
tab[pere], tab[GF] = tab[GF], tab[pere]
pere = GF
else:
return
45
III. Les graphes
1. Définitions
Graphe : Un graphe G est défini par G=(V,U), ou V est un
ensemble de sommets et U l’ensemble d'arcs(ou arêtes) ;
Un arc (ou arête) est un couple de sommets, donc, un
élément du produit cartésien VxV
46
III. Les graphes
1. Définitions
47
III. Les graphes
1. Définitions
48
III. Les graphes
1. Définitions
A B
49
III. Les graphes
2. Terminologies
Graphe d'ordre 6
50
2. Terminologies
51
III. Les graphes
2. Terminologies
Adjacences:
Deux sommets sont adjacents lorsqu'ils sont joints par une
arête.
Deux arcs sont dits adjacents s'ils ont une extrémité en
commun.
52
III. Les graphes
2. Terminologies
53
III. Les graphes
2. Terminologies
54
III. Les graphes
2. Terminologies
Cycle : Un cycle est une chaine qui permet de partir
d’un sommet et revenir a ce sommet en parcourant
une et une seule fois les autres sommets.
55
III. Les graphes
2. Terminologies
Distance entre deux sommets i et j est la longueur
de la chaine la plus courte qui les relie
56
III. Les graphes
2. Terminologies
Chemin : c’est une chaine bien orientée
Un circuit ou cycle orienté : est un chemin dont l’origine et
l’extrémité sont confondus.
58
2. Terminologies
Cycle eulérien : si le sommet de départ d’une chaine eulérienne
est celui d’arrivé on parle de cycle eulérienne
Par exemple : Dans le graphe suivant, la chaîne A – B – C – D –
E – F – A est un cycle eulérien.
59
2. Terminologies
60
III. Les graphes
3. Manipulation des graphes sous python
Un graphe peut être implémenté de différentes manières selon le
langage utilisé. En Python, on peut représenter un graphe à l’aide
d’un dictionnaire ou à l’aide d’une matrice d’adjacence:
Matrice d’adjacence
2 1 2 3 4 5
1 2
1 0 0 0 0 3
4
3 8 2 2 0 4 3 0
3 3
5 6 3 0 0 0 6 0
4
1 4 0 0 1 0 0
4
5 0 8 0 4 0
61
III. Les graphes
3. Manipulation des graphes sous python
Exemple 2:
dictionnaire
62
Matrice d’adjacence
III. Les graphes
4. Algorithme de dijkstra
Il existe de nombreux algorithmes déterminant
un ou le plus court chemin dans un graphe
connexe pondéré. Par exemple: Warshall,
Floyd, Dijkstra, Branch and Bound, Bellman-
Ford
On se limitera à la recherche d'un plus court
chemin entre deux sommets du graphe pondéré
avec des poids positifs en utilisant la matrice
d’adjacence pour représenter le graphe.
63
III. Les graphes
4. Algorithme de dijkstra
On construit de proche en proche le chemin cherché en
choisissant à chaque itération de l'algorithme, un sommet si
du graphe parmi ceux qui n'ont pas encore été traités, tel que
la longueur connue provisoirement du plus court chemin
allant de E à si soit la plus court possible.
64
III. Les graphes
4. Algorithme de dijkstra
Algorithme :
Étape 1 : On affecte le poids 0 au sommet origine (E) et
on attribue provisoirement un poids ∞ aux autres
sommets.
Répéter les opérations suivantes tant que le sommet
de sortie (s) n'est pas affecté d'un poids définitif
Étape 2 : Parmi les sommets dont le poids n'est pas
définitivement fixé, choisir le sommet X de poids
minimal. Marquer définitivement ce sommet X
65
III. Les graphes
4. Algorithme de dijkstra
Étape 3 : Pour tous les sommets Y qui ne sont pas définitivement
marqués, adjacents au dernier sommet fixé X:
Calculer la somme s du poids de X et du poids de l'arête reliant
X à Y.
Si la somme s est inférieure au poids provisoirement affecté au
sommet Y, affecter provisoirement à Y le nouveau poids s et
indiquer le sommet X comme prédécesseur de Y pour se
souvenir de sa provenance.
Quand le sommet s est définitivement marqué Le plus court
chemin de E à S s'obtient en écrivant de gauche à droite le
parcours en partant de la fin S.
66
III. Les graphes
4. Algorithme de dijkstra
1 0
0 1 4
10
2
2
6 0
2
1
5
1 3
4
3
67
III. Les graphes
4. Algorithme de dijkstra
Matrice d'adjacence:
Sommet de depart : 0
d=[0, infini,infini, infini,infini,infini] # Liste des poids
p=[0,-1,-1,-1,-1,-1] # Liste des prédécesseurs
c=[0,1,2,3,4,5] # Sommet à marquer
68
III. Les graphes
4. Algorithme de dijkstra
x=0 (Sommet) x appartient c telque d[x] =min{d[j] telque j appartient c}
Pour tout sommet y de c:
d[y] = min(d[y],d[x]+G[x][y])
d[1]=min(d[1],d[x]+G[x][1]) = min(Infini,0+10) = 10
p[1] = x=0
d[2] = min(d[2],d[x]+G[x][2]) = min(Infini,0+3) = 3
p[2] = 0
d[3] = min(d[3],d[x]+G[x][3]) = min(Infini,0+Infini) = Infini
p[3] =-1(Aucune modification)
d[4] = min(d[4],d[x]+G[x][4]) = min(Infini,0+6) = 6
p[4] = 0
d[5] = min(d[5],d[x]+G[x][5]) = min(Infini,0+Infini) = Infini
p[5] = -1 (Aucune modification)
d=[0, 10, 3, infini, 6, Infini] # Liste des poids
p=[0,0,0,-1,0,-1] # Liste des prédécesseurs
c=[1,2,3,4,5] # Sommet à marquer
69
III. Les graphes
4. Algorithme de dijkstra
x=2 (Sommet)
d[1]=min(d[1],d[2]+G[2][1]) = min(10, 3+4) = 7
p[1] = 2
d[3] = min(d[3],d[2]+G[2][3]) = min(Infini,3+Infini) = Infini
p[3] = -1 (Aucune modification)
d[4] = min(d[4],d[2]+G[2][4]) = min(6,3+2) = 5
p[4] = 2
d[5] = min(d[5],d[2]+G[2][5]) = min(Infini,3+Infini) = Infini
p[5] = -1 (Aucune modification)
d=[0, 7, 3, infini, 5, Infini] # Liste des poids
p=[0,2,0,-1,2,-1] # Liste des prédécesseurs
c=[1,3,4,5] # Sommet à marquer
70
III. Les graphes
4. Algorithme de dijkstra
x=4 (Sommet)
d[1]=min(d[1],d[4]+G[4][1]) = min(7, 5+0) = 5
p[1] = 4
d[3] = min(d[3],d[4]+G[4][3]) = min(Infini,5+Infini) = Infini
p[3] = -1 (Aucune modification)
d[5] = min(d[5],d[4]+G[4][5]) = min(Infini,5+1) = 6
p[5] = 4
d=[0, 5, 3, infini, 5, 6] # Liste des poids
p=[0,4,0,-1,2,4] # Liste des prédécesseurs
c=[1,3,5] # Sommet à marquer
71
4. Algorithme de dijkstra
x=1
d[5] = min(d[5],d[1]+ G[1][5])=min(6,6)=6
d[3] = min(d[3],d[1]+ G[1][3])=min(infini,infini)=infini
d = [ 0, 5, 3, Infini, 5, 6 ]
p=[0, 4, 0, -1, 2, 4 ]
c = [ 3, 5 ]
72
4. Algorithme de dijkstra
x=5
d[3] = min(d[3],d[5]+ G[5][3])=min(infini,infini)=infini
d = [ 0, 5, 3, Infini, 5, 6 ]
p=[0, 4, 0, -1, 2, 4 ]
c=[3]
73
4. Algorithme de dijkstra
def dijkstra(G,s):
infini=G[0][0]
n=len(G)
D=[infini for i in range(n)]
D[s]=0
P=[-1 for i in range(n)]
P[s]=s
C=[i for i in range(n)]
while len(C)>0:
x=minD(D,C)
for k in C:
if D[x]+G[x][k]<D[k]:
D[k]=D[x]+G[x][k]
P[k]=x
C=supp(C,x)
return
74 P,D
III. Les graphes
4. Algorithme de dijkstra
def minD(LD,LC):
iminD=LC[0]
for i in LC:
if LD[i]<LD[iminD]:
iminD=i
return iminD
def supp(LC,v):
for i in range(len(LC)):
if LC[i] == v:
del LC[i]
return LC
75
III. Les graphes
G=[[1000,…..]
L=dijkstra(G,0)
Print(L)
Question : Ecrire une fonction chemin(G,s1,s2)
permettant d’afficher le chemin optimal entre
les sommets s1 et s2.Vous devez afficher aussi
le cout du chemin. Si le chemin n’existe pas
vous afficher « Le chemin n’existe pas »
76
III. Les graphes
5. Parcourir un graphe
a)Parcours en profondeur(DFS :Depht First Search)
L'algorithme sera :
1. Initialement tous les nœuds sont marqués " non visités".
2. Choisir un nœud v de départ et le marquer " visité".
3. Chaque nœud adjacent à v, non visité, est à son tour visité en
utilisant un traitement récursive.
4. Une fois tous les nœuds accessibles à partir de v ont été
visités, la recherche de v ( DFS(v) ) est complète.
5. Si certains nœuds du graphe restent "non visités",
sélectionner un comme nouveau nœud de départ et
répéter le processus jusqu'à ce que tous les nœuds soient
visités.
77
III. Les graphes
5. Parcourir un graphe
a)Parcours en profondeur
Code Python :
def DFSRecursif(G,s,etats):
etats[s]=1
print(s)
for x in voisinNonVisite(G,s,etats):
DFSRecursif(G,x,etats)
def voisinNonVisite(G,s,etats):
n=len(G[s])
infini = G[0][0]
L=[]
for i in range(n):
if G[s][i]!=infini and etats[i]==0:
L.append(i)
return L
78
III. Les graphes
5. Parcourir un graphe
a)Parcours en profondeur
def parcours(G):
etats=[0]*len(G)
for i in range(len(G)):
if etats[i]==0:
DFSRecursif(G,i,etats)
#Testes
G=[
[99,10,3,99, 6,99],
[ 0,99,99,99,99,1],
[99, 4,99,99, 2,99],
[ 99, 99,1,99,3,99],
[99, 0,99,99,99, 1],
[ 2, 99,99,99, 99,99]
]
print("Résultat du parcours en profondeur :")
parcours(G)
79
III. Les graphes
5. Parcourir un graphe
a)Parcours en profondeur
On peut aussi réaliser le parcours en profondeur en utilisant les Piles. Pour ce
faire on remplace la fonction DFSRecursif par la fonction suivante :
def parcoursDFSpile(G,s,etats):
pile=[s]
while pile!=[]:
noeud=pile.pop()
print(noeud)
etats[noeud]=1
voisin=voisinNonVisite(G,noeud,etats)
if voisin!=[]:
for x in voisin:
pile.append(x)
80
III. Les graphes
5. Parcourir un graphe
a)Parcours en profondeur
def parcours(G):
etats=[0]*len(G)
for i in range(len(G)):
if etats[i]==0:
parcoursDFSpile (G,i,etats)
#Testes
G=[
[99,10,3,99, 6,99],
[ 0,99,99,99,99,1],
[99, 4,99,99, 2,99],
[ 99, 99,1,99,3,99],
[99, 0,99,99,99, 1],
[ 2, 99,99,99, 99,99]
]
print("Résultat du parcours en profondeur :")
parcours(G)
81
III. Les graphes
5. Parcourir un graphe
b)Parcours en largeur(BFS Breadh First Search )
L'algorithme sera :
1) Dans le parcours en largeur, on utilise une file. On
enfile le sommet de départ
2) On visite les voisins de la tète de file. On les enfile.
3) On défile (c'est à dire : on supprime la tête de la file).
4) On recommence au point 2 (tant que la file n'est pas
vide)
82
III. Les graphes
5. Parcourir un graphe
b)Parcours en largeur
Code python :
def BFSFile(G,s,etats):
file=[s]
while file!=[]:
noeud=file.pop(0)
print(noeud,end=' ')
etats[noeud]=1
voisin=voisinNonVisite(G,noeud,etats)
if voisin!=[]:
for x in voisin:
file.append(x)
83
III. Les graphes
5. Parcourir un graphe
b)Parcours en largeur
def parcours(G):
etats=[0]*len(G)
for i in range(len(G)):
if etats[i]==0:
BFSFile (G,i,etats)
#Testes
G=[
[99,10,3,99, 6,99],
[ 0,99,99,99,99,1],
[99, 4,99,99, 2,99],
[ 99, 99,1,99,3,99],
[99, 0,99,99,99, 1],
[ 2, 99,99,99, 99,99]
]
print("Résultat du parcours en largeur:")
parcours(G)
84