• Aucun résultat trouvé

Un problème fondamental

N/A
N/A
Protected

Academic year: 2022

Partager "Un problème fondamental"

Copied!
105
0
0

Texte intégral

(1)

Algorithmes de tris

Judicaël Courant 2017-W42-4 (19 octobre)

(2)

1 Introduction Généralités Trier Remarques 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(3)

Un problème fondamental

Letri est un problème fondamental de l’algorithmique. En général, son but est de préparer des données pour permettre d’y rechercher rapidement une information.

(4)

Motivations

Dans des données triées, il est facile de :

chercher rapidement si un élément est présent ou non ; trouver les doublons ;

trouver une information associée à une donnée (exemple d’utilisation : index d’un livre) ;

chercher le k-ième plus grand élément d’un ensemble.

(5)

Notion de clé

Les données qu’on veut trier ne sont pas nécessairement munies d’un ordre total (canonique).

En général, pour trier des données, on leur appliquera une fonction, appelée clé de tri oucritère de trià valeurs dans un ensemble totalement ordonné

On dira que les données d’un tableaut sont triées (par ordre croissant) si elles sont rangées par ordre croissant des clés.

(6)

Exemples

Tri de données représentant des personnes par nom de famille croissant pour l’ordre lexicographique.

Tri de données représentant des personnes par date de naissance croissante.

Remarque

Dans la suite de ce document :

on triera des données déjà munies d’un ordre en Python et on les triera avec cet ordre

on supposera que la complexité en temps et en espace de la comparaison de deux éléments est constante.

(7)

1 Introduction Généralités Trier Remarques 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(8)

Cadre

Considérons un algorithme de tri qui prend en entrée un tableau contenant des donnéesu0, . . . ,up−1 et :

soit retourne un nouveau tableau (appelons t0, . . . ,tq−1 son contenu) ;

soit modifie ce tableau (appelons t0, . . . ,tq−1 son contenu après l’exécution de l’algorithme).

(9)

Ce que trier veut dire

Définition (Tri d’un tableau)

On dit que l’algorithme a trié le tableau si lesdeux propriétés suivantes sont vérifiées :

1 t est trié par ordre croissant1 de la clé choisie.

2 t etu contiennent les mêmes éléments avec les mêmes multiplicités.

1. ou décroissant suivant le contexte.

(10)

Une caractérisation

Proposition

Deux listes de donnéesu0, . . . ,up−1 et t0, . . . ,tq−1 contiennent les mêmes éléments avec les mêmes multiplicités si et seulement si p=q et il existe une permutationσ :J0,pJtel queti =uσ(i) pour touti ∈J0,pJ.

Conséquence

Pour montrer qu’un algorithme trie un tableau, il suffit donc de montrer les deux points suivants :

1 Le tableau obtenu est rangé par ordre croissant.

2 Le tableau obtenu est une permutation du tableau initial.

(11)

1 Introduction Généralités Trier Remarques 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(12)

Stabilité

Définition (Stabilité d’un tri)

Un tri est dit stable s’il ne modifie jamais l’ordre relatif de deux éléments de même clé.

Utilité des tris stables

Permettre de trier par ordre lexicographique de deux clés en triant pour la deuxième puis la première clé.

(13)

Question

On trie la liste suivante par ordre lexicographique de nom : Dupont, Pierre,

Martin, Jacques, Durand, Jacques, Martin, Claude, Dupont, Jean.

On obtient :

Dupont, Pierre, Dupont, Jean, Durand, Jacques, Martin, Claude, Martin, Jacques.

L’algorithme de tri utilisé était-il stable ?

A. Oui.

B. Non (cas des Dupont).

C. Non (cas des Martin).

D. On ne peut pas savoir.

(14)

Tri en place

Définition (Algorithme en place)

On dit qu’un algorithme s’effectueen places’il travaille en utilisant au plus un espace mémoire constant (en plus de ses données d’entrée).

Note

Par abus de langage, on considère parfois qu’un tri s’effectue en place s’il utilise un faible espace mémoire supplémentaire. En particulier, s’il utilise au plus un espace mémoireO(logn) car en pratiquelog2n ne dépasse pas quelques dizaines .

(15)

1 Introduction 2 Tri par sélection

Algorithme

Implantation en Python Correction de l’algorithme Complexité

Conclusion 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(16)

Principe

Étant donné un tableau de n valeursL[0], …, L[n−1], on cherche le minimum : L[i]. On échangeL[0] et L[i].

On cherche le minimum de L[1],…,L[n−1], et on l’échange avec L[1].

. . .

On cherche le minimun de L[k],…,L[n−1], et on l’échange avec L[k].

. . .

On cherche le minimum de L[n−2] etL[n−1] et on l’échange avecL[n−2].

(17)

Exemple

2 1 5 9 0 4

| {z }

min=0

:min(T[0 :]) = 0que l’on échange avec T[0] = 2 0 1 5 9 2 4

| {z }

min=1

:min(T[1 :]) = 1qu’on laisse en place 0 1 5 9 2 4

| {z }

min=2

:min(T[2 :]) = 2que l’on échange avec T[2] = 5 0 1 2 9 5 4

| {z }

min=4

:min(T[3 :]) = 4que l’on échange avec T[3] = 9 0 1 2 4 5 9

min=5|{z}

:min(T[4 :]) = 5qu’on laisse en place 0 1 2 4 5 9

min=9|{z}

:min(T[5 :]) = 9qu’on laisse en place.

(18)

Introduction Tri par sélection Tri par insertion Tri fusion Tri par pivot

Algorithme Implantation en Python Correction de l’algorithme Complexité

Conclusion

QCM

Stabilité

Le tri par sélection est-il stable ?

(19)

QCM

Stabilité

Le tri par sélection est-il stable ? En place

S’agit-il d’un tri en place ?

(20)

1 Introduction 2 Tri par sélection

Algorithme

Implantation en Python Correction de l’algorithme Complexité

Conclusion 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(21)

Échange d’éléments

def swap(t, i, j):

"""Échange les éléments d'indice i et j dans t, tableau.

Précondition : t tableau et i et j entiers dans l'intervalle range(len(t)).

"""

t[i], t[j] = t[j], t[i]

return

(22)

Indice de l’élément minimum d’un sous-tableau

def imin(t, i):

"""Retourne j tel que t[j] == min(t[i], ..., t[n-1]) où n est la longueur de t

Précondition : t tableau de taille n et i entier avec 0 <= i < n"""

j = i

for k in range(i+1, n):

# t[j] == min(t[i], ..., t[k-1]) if t[k] < t[j]:

j = k return j

(23)

QCM

L’exécution deimin(t, i), oùt est un tableau de taille n prend un temps

A. O(1); B. O(n−i); C. O(n); D. O(n2).

(24)

Fonction principale

def tri_selection(t):

"""Trie le tableau t par ordre croissant"""

n = len(t)

for i in range(n-1):

# les i premiers éléments de t sont triés

# et inférieurs ou égaux aux autres éléments de t.

j = imin(t, i) swap(t, i, j) return

(25)

QCM

L’exécution detri_selection(t), oùt est un tableau de taille n prend un temps

A. O(n);

B. O(n(n−1)/2); C. O(n(n+ 1)/2); D. O(n2).

(26)

1 Introduction 2 Tri par sélection

Algorithme

Implantation en Python Correction de l’algorithme Complexité

Conclusion 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(27)

Correction

Proposition

Ce programme est correct : il trie par ordre croissant le tableaut qui lui est passé en argument

Il y a deux points à montrer :

1 Le contenu det après l’exécution du programme est obtenu par application d’une permutation à son contenu avant l’exécution.

2 Après l’exécution de la procédure, t est trié.

(28)

Démonstration

1 Les seules modifications qu’on effectue sur le tableau sont des échanges de deux éléments. À la fin du programme on a donc appliqué au tableau la composée d’un nombre fini de

transpositions. On a donc simplement permuté les éléments du tableau.

2 On va :

Montrer que l’invariant de boucle est bien vérifié.

En déduire que le tableaut est trié à la fin de l’exécution.

(29)

Justification de l’invariant de boucle

1 Au début du premier tour de boucle (pouri = 0), l’invariant de boucle est vérifié : les0 premiers éléments det sont triés, inférieurs ou égaux aux n suivants.

2 Si au début du touri, l’invariant est vérifié, notons t00, . . . ,tn0−1 les éléments du tableau au début du tour de boucle ett000, . . . ,tn−100 ceux à la fin. Alors :

(t000, . . . ,ti−100 ) = (t00, . . . ,ti−10 )donc lesi premiers éléments de t00 sont triés par ordre croissant.

ti00 est le plus petit des élémentsti0, . . . ,tn−10 qui sont tous plus grands quet00, . . . ,ti−10 , donct000, . . . ,ti00est trié par ordre croissant.

Les éléments det000, . . . ,ti−100 sont plus petits que ceux de ti+100 , . . . ,tn−100 etti00est plus petit queti+100 , . . . ,tn−100 donc les i+ 1 premiers éléments det00 sont tous plus petits que les ni1 autres.

L’invariant est donc vérifié au début du tour suivant.

(30)

Conclusion

D’après l’invariant de boucle, à la fin de l’exécution : les n−1 premiers éléments det sont triés

ils sont plus petits que t[n−1](qui est le n ième) Donct est trié.

(31)

1 Introduction 2 Tri par sélection

Algorithme

Implantation en Python Correction de l’algorithme Complexité

Conclusion 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(32)

Complexité de imin

On supposera que les comparaisons d’éléments de t sont des opérations élémentaires.

Le nombre de d’opérations élémentaires effectuées par

imin(t, i) estdominé par le nombre de comparaisons entre éléments det.

Un appel à imin(t, i)effectuelen(t)-(i+1) comparaisons.

Donc le temps d’exécution deimin(t, i) est un O(len(t)-i).

(33)

Complexité de tri_selection

Le temps d’exécution de tri_selection(t) est dominé par le temps des appels à imin(t, i), car l’appel àswap s’effectue en temps constant.

Pour un tableau de taille n, il est donc dominé par

n−2

X

i=0

(n−i−1) =

n−1

X

k=1

k = n(n−1) 2

Complexité temporelle du tri par sélection

La complexité en temps detri_selection(t)pour un tableau t de taillen est donc unO(n2), dans le cas le pire comme dans le cas le meilleur.

(34)

Complexité spatiale

Pas d’appels récursifs : espace de pile utilisé O(1).

Aucune structure de données auxiliaire : espace mémoire utilisé autre que la pile O(1)

Complexité spatiale du tri par sélection

La complexité spatiale du tri par sélection est constante.

(35)

1 Introduction 2 Tri par sélection

Algorithme

Implantation en Python Correction de l’algorithme Complexité

Conclusion 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

(36)

Conclusion sur le tri par sélection

Le tri par sélection est assez facile à écrire.

Sa complexité spatiale est constante.

Il a une complexité temporelleO(n2) dans le cas le pire comme dans le cas le meilleur, il ne permet donc pas de trier de grands tableaux.

Il ne sait pas tirer parti du fait que les données à trier sont déjà triées, ou presque triées.

(37)

1 Introduction 2 Tri par sélection 3 Tri par insertion

Algorithme

Implantation en Python Correction

Complexité Conclusion 4 Tri fusion 5 Tri par pivot

(38)

Principe

On procède élément par élément. Si lesi premiers éléments sont triés, on prend le(i+ 1)ième et on l’insère dans le paquet des éléments déjà triés en le faisant glisser vers la gauche et en s’arrêtant dès que :

on est en première position

ou l’élément à sa gauche lui est inférieur ou égal

(39)

Exemple

D F A G B

D F A G B

D F A G B

A D F G B

A D F G B

A B D F G

(40)

Stabilité

Le tri par insertion est-il stable ? A. Oui.

B. Non.

(41)

1 Introduction 2 Tri par sélection 3 Tri par insertion

Algorithme

Implantation en Python Correction

Complexité Conclusion 4 Tri fusion 5 Tri par pivot

(42)

Position

def position(t, n):

"""t[:n] étant supposé trié, retourne la position à laquelle insérer t[n] dans t[:n].

Précondition: n < len(t)."""

for k in range(n, 0, -1):

# les éléments de t[k:n] sont str. supérieurs à t[n]

if t[k-1] <= t[n]:

return k

# les éléments de t[:n] sont str. supérieurs à t[n]

return 0

(43)

Décalage

def decale(t, k, n):

"""Décale les éléments de t[k:n] d'un cran vers la droite. t[k] est remplacé par la valeur de t[n].

Précondition: 0 <= k <= n < len(t)."""

v = t[n]

for i in range(n, k, -1):

t[i] = t[i-1]

t[k] = v

(44)

Insertion

def insere(t, n):

"""Précondition: t[:n] trié et len(t) >= n+1.

Postcondition: t[:n+1] trié. Les n+1 premiers éléments de t sont préservés mais pas nécessairement leur ordre.

Les autres éléments de t sont inchangés."""

k = position(t, n) decale(t, k, n)

(45)

QCM

insere(t, x), oùt est un tableau de taille n prend un temps A. O(1);

B. O(n); C. O(nlogn); D. O(n2).

(46)

Fonction principale

def tri_insertion(u):

"""Trie le tableau u par insertion."""

for k in range(1, len(u)):

# invariant : u[:k] est trié.

insere(u, k)

# u est trié.

(47)

QCM

tri_insertion(t), oùt est un tableau de taillen prend un temps

A. O(1); B. O(n); C. O(nlogn); D. O(n2).

(48)

1 Introduction 2 Tri par sélection 3 Tri par insertion

Algorithme

Implantation en Python Correction

Complexité Conclusion 4 Tri fusion 5 Tri par pivot

(49)

Correction du tri par insertion

Le tableau est trié à la fin

C’est une conséquence directe de l’invariant de boucle.

Cet invariant est vrai avant l’entrée dans la boucle.

Il est préservé par chaque tour de boucle.

Le tableau final est une permutation du tableau initial En effet, le tableau n’est modifié que dans la fonction

decalage(t, k, n), qui applique une permutation circulaire à t[k :n+ 1].

(50)

1 Introduction 2 Tri par sélection 3 Tri par insertion

Algorithme

Implantation en Python Correction

Complexité Conclusion 4 Tri fusion 5 Tri par pivot

(51)

Calcul de la position

La boucle dansposition(t, n) ne comporte que des opérations élémentaires

Donc le temps d’exécution de cette fonction est dominé par le nombre de tours de boucle effectués.

Ce dernier est égal au nombre de comparaisons entre éléments det, qui est compris entre 1 etn.

Il est aussi égal ànkk est la valeur retournée.

(52)

Décalage

Le temps d’exécution de decalage(t, k, n) est dominé par le nombre de tours de boucle.

Ce nombre vaut nk.

(53)

Insertion

Dans insere(t, n), on affecte àk la valeur retournée par l’appel à position(t, n).

Le temps de calcul de position(t, n)est dominé parnk.

Celui de decale(t, k, n)aussi.

Donc le temps de calcul de insere(t, n)est dominé par le nombre de comparaisons effectuées dans position(t, n).

(54)

Complexité du tri

Le temps d’exécution de tri_insertion(t) sur un tableaut de taille n est donc dominé par le nombre de comparaisons effectuées.

NotonsC(t) ce nombre de comparaisons.

(55)

Cas le pire

C(t)≤

n−1

X

k=1

= n(n−1) 2

Cette inégalité est une égalité pour tout tableaut initialement trié par ordre décroissant.

Conclusion

La complexité temporelle du tri par insertion dans le cas le pire sur un tableau de taillen est O(n).

(56)

Cas le meilleur

C(t)≥

n−1

X

k=1

=n−1

Cette inégalité est une égalité pour tout tableaut initialement trié par ordre croissant.

Conclusion

La complexité temporelle du tri par insertion dans le cas le meilleur sur un tableau de taillen est O(n).

Remarque

Cela se produit lorsque le tableau est trié mais aussi lorqu’il est presque trié, à l’exception dek valeurs, avec k borné

indépendamment den.

(57)

Complexité spatiale

Pas d’appels récursifs : espace de pile utilisé O(1).

Aucune structure de données auxiliaire : espace mémoire utilisé (autre que la pile) :O(1)

Complexité spatiale du tri par insertion

La complexité spatiale du tri par insertion est constante.

(58)

1 Introduction 2 Tri par sélection 3 Tri par insertion

Algorithme

Implantation en Python Correction

Complexité Conclusion 4 Tri fusion 5 Tri par pivot

(59)

Conclusion sur le tri par insertion

Simple à écrire et à justifier.

Sans doute le tri naïf le plus efficace : travaille en temps linéaire lorsque le tableau est trié ou presque trié (nombre fini d’éléments mal placés).

Complexité temporelle quadratique et spatiale constante dans le cas le pire.

Tri recommandé pour trier quelques dizaines d’éléments.

(60)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion

Algorithme

Implantation en Python Correction

Complexité Conclusion 5 Tri par pivot

(61)

Principe

Le principe est de partager le tableau en deux moitiés, de les trier récursivement, puis de fusionner ces deux moitiés triées de façon à obtenir un tableau trié.

(62)

QCM

Stabilité

Est-ce un tri stable ? En place

Est-ce un tri en place ?

(63)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion

Algorithme

Implantation en Python Correction

Complexité Conclusion 5 Tri par pivot

(64)

Fusion de deux tableaux triés

def fusion(t1, t2):

"""Retourne un tableau t trié de mêmes élts que t1+t2.

Précondition : t1 et t2 triés par ordre croissant."""

n1, n2 = len(t1), len(t2) n = n1 + n2; t = n * [None]

i1, i2 = 0, 0 for k in range(n):

# t[:k] trié, d'éléments ceux de t1[:i1] + t2[:i2]

# tous inf. ou égaux à ceux de t1[i1:] et t2[i2:]

if i2 >= n2 or (i1 < n1 and t1[i1] <= t2[i2]):

t[k] = t1[i1]; i1 += 1 else:

t[k] = t2[i2]; i2 += 1 return t

(65)

Fonction principale

def tri_fusion(t):

"""Retourne une copie de t triée par ordre croissant."""

n = len(t) if n <= 1:

return t.copy() k = n // 2

return fusion(tri_fusion(t[:k]), tri_fusion(t[k:]))

(66)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion

Algorithme

Implantation en Python Correction

Complexité Conclusion 5 Tri par pivot

(67)

Correction de la fusion

C’est une conséquence immédiate de l’invariant de boucle.

Cet invariant est vrai à l’entrée dans la boucle Il est préservé par chaque tour de boucle.

(68)

Correction de la fonction principale

On montre, par récurrence forte, que pour tout entiern, elle trie tous les tableaux de taillen :

C’est évident sur les tableaux de taille0 et1.

Soit n≥2,t un tableau de taillen. Supposons qu’elle est correcte sur tous les tableaux strictement plus petits. Alors en posantk =bn/2c, on ak <n etnk =dn/2e<n.

Lorsqu’on exécute tri_fusion(t), les deux appels récursifs se font sur des tableaux strictement plus petits que t. Par hypothèse de récurrence, ils retournent donc des tableaux triés contenant les mêmes éléments que t[:k]et t[k :]. La fusion de ces deux tableaux est donc triée et contient les mêmes

éléments que t[:k] +t[k:], donc quet.

(69)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion

Algorithme

Implantation en Python Correction

Complexité Conclusion 5 Tri par pivot

(70)

Complexité

L’opération de fusion de deux tableaux de longueursn1 et n2

demande un tempsO(n1+n2) dans le cas le pire comme dans le cas le meilleur.

NotonsP(n)(resp.M(n)) le temps d’exécution du tri fusion sur un tableau de taillen dans le cas le pire (resp. le meilleur).

Inégalité de complexité P(n)≤ O

n→+∞(n) +P(bn/2c) +P(dn/2e)

(71)

Croissance de la complexité

Rappel de l’inégalité : P(n)≤ O

n→+∞(n) +P(bn/2c) +P(dn/2e)

Pour résoudre l’inéquation surP, le mieux est de voir ce qu’il se passe pourn= 2k, puis de dire qu’on a P(n)≤P(2dlog2ne)… sauf que rien ne dit queP est croissante !

Pour s’en sortir, deux possibilités :

Faire l’hypothèseexplicitement que P est croissante (c’est mieux que ne rien dire)

NoterP0(n)le temps d’exécution du tri fusion sur un tableau de taille inférieure ou égaleàn dans le cas le pire. P0 est alors croissante (pourquoi ?)

(72)

Croissance de la complexité (bis)

Si nous prenons la deuxième solution.

Pour un entiern fixé,P0(n)est le temps d’exécution d’un tableau tn de taille kn avecknn.

Alors on a

P0(n)≤ O

n→+∞(kn) +P0(bkn/2c) +P0(dkn/2e) Inégalité de complexité

P0(n)≤n→+∞O (n) +P0(bn/2c) +P0(dn/2e)

Autrement dit,P0 est croissante et vérifie la même inégalité queP.

(73)

Résolution : cas simples

Pour résoudre

P0(n)≤ O

n→+∞(n) +P0(bn/2c) +P0(dn/2e)

On constate que le cas des puissances de2doit être plus simple, donc on poseuk =P0(2k).

Inégalité pour les puissances de2

On en déduit, pourk au voisinage de+∞ : uk ≤ O

k→+∞(2k) + 2uk−1

(74)

Équation homogène

C’est une inégalité du type :

uk−2uk−1 ≤ O

k→+∞(2k)

Équation homogène associée

k ∈N uk = 2uk−1

dont une solution est 2k

kN.

(75)

Variation de la constante

Inégalité :

uk−2uk−1 ≤ O

k→+∞(2k) Une solution de l’équation homogène associée : 2k

k∈N. Méthode de variation de la constante

On pose pour toutk ∈N,λk =uk/2k (méthode de variation de la constante) et on divise l’inégalité précédente par2k. On obtient :

λk−λk−1 ≤ O

k→+∞(1)

(76)

Variation de la constante (fin)

λk−λ0

k

X

i=1

i −λi−1)

≤ O

k→+∞(k)(k) (cours sur les séries) etλk ≥0, donc λk =O(k). D’où ukk2k =O(k2k).

(77)

Solution du cas général

P0(n)≤P0(2dlog2ne) =udlog2ne=O(dlog2ne2dlog2ne) =O(nlogn) CommeP est à valeurs positives, on en déduit :

Complexité temporelle du tri fusion dans le cas le pire P(n) =O(nlogn)

(78)

Cas le meilleur

Dans le cas le meilleur, on peut de la même façon montrer que le temps d’exécution estM(n) = Ω(nlogn).

Remarque

M(n) = Ω(nlogn) et P(n)≤M(n) et P(n) =O(nlogn)

D’où M(n) = Θ(nlogn) etP(n) = Θ(nlogn)

(79)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion

Algorithme

Implantation en Python Correction

Complexité Conclusion 5 Tri par pivot

(80)

Conclusion sur le tri fusion

Complexité temporelle

Dans le cas le meilleur comme dans le cas dans le pire, le tri fusion demande un temps d’exécutionO(nlogn), oùn est la longueur du tableau à trier.

Complexité spatiale (admise)

La complexité spatiale du tri fusion sur un tableau de taillen est O(n) : car on a besoin d’espace mémoire pour stocker les morceaux de tableau et pour effectuer la fusion.

Note

Le tri fusion estletri à implanter si vous cherchez un algorithme plus efficace que les tris naïfs et que vous ne voulez pas y passer trop de temps.

(81)

Remarque 1 : Timsort

La fonctionsortedde Python utilise une version améliorée du tri fusion appeléeTimsort.

(82)

Remarque 2 : tri fusion itératif

Celui-ci consiste à fusionner

les éléments d’indices 2k et2k+ 1, le tableau se trouve ainsi composé de sous-tableaux de taille 2commençant à l’indice 2k, pour toutk, et tous triés.

les tableaux d’indices 4k,4k+ 1avec ceux d’indices 4k+ 2,4k+ 3, pour obtenir des sous-tableaux de taille4 commençant à chaque indice de la forme 4k

etc.

Facile à écrire si le tableau est de taille2p, sinon il convient de faire attention pour les derniers éléments.

(83)

Remarque 3 : tri fusion externe

Le tri fusion est très utile pour un tableau tellement gros qu’il ne peut tenir en mémoire vive :

on stocke le tableau dans un fichier ;

on découpe le fichier en morceaux qui tiennent en RAM ; on trie chaque morceau (et on le stocke dans un fichier) ; on fusionne deux-à-deux les morceaux (on lit les premiers octets des fichiers à trier et on écrit dans un fichier résultat) pour obtenir des fichiers de taille double ;

on fusionne deux à deux ces fichiers de taille double pour obtenir des fichiers de taille quadruple ;

etc.

(84)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

Algorithme

Implantation en Python Correction

Complexité Conclusion

(85)

Introduction

Aussi appelétri rapide ouquicksort.

Inventé par Tony Hoare en 19602.

Toujours un des tris les plus rapides en pratique aujourd’hui.

2. Hoare a aussi inventé les notions de pré-condition, post-condition et d’invariant de boucle.

(86)

Principe

Étant donné un tableautetget ddeux indices avec

0≤g≤d<len(t),tri_rapide(t, g, d) va trier la portion du tableau d’indices appartenant àJg,dJ.

Sid−g≤1, il n’y a rien à faire. Sinon :

On choisit une valeurv du tableau appeléepivotet on réordonne la portion du tableau à trier de façon à ce que :

1 Le pivot arrive à une positioniJg,dJ.

2 Toutes les valeurs strictement plus petite quev sont avant l’indicei, les autres après.

On dit qu’on a partitionné la partie à trier.

On trie récursivement les portions du tableau d’indices appartenant à Jg,iJet Ji+ 1,dJ.

(87)

Algorithme de partition

On parcourt le sous-tableau à partitionner de la gauche vers la droite de façon à avoir, à chaque itération :

le pivotvà l’indice g;

des valeurs strictement plus petites quevpour les indices de Jg+ 1,mJ;

des valeurs supérieures ou égales àvpour les indices de Jm,iJ; des valeurs qui restent à répartir pour les indices de Ji,dJ.

(cf dessin et exercice du drapeau hollandais)

(88)

QCM

Stabilité

Est-ce un tri stable ? En place

Est-ce un tri en place ?

(89)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

Algorithme

Implantation en Python Correction

Complexité Conclusion

(90)

Implantation de la fonction partition

def partition(t, g, d):

assert g < d v = t[g]

m = g+1

for i in range(g+1, d):

# en g on a v, en range(g+1,m), des valeurs < v

# en range(m, i), des valeurs >= v if t[i] < v:

swap(t, i, m) m += 1

# replacer v si au moins une valeur est < v : swap(t, g, m-1) # ne fait rien si m == g+1.

# on retourne la position finale du pivot return m-1

(91)

Programme principal

Le tri rapide s’écrit alors :

def tri_rapide_rec(t, g, d):

if d - g <= 1: return i = partition(t, g, d) tri_rapide_rec(t, g, i) tri_rapide_rec(t, i+1, d) def tri_rapide(t):

tri_rapide_rec(t, 0, len(t))

(92)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

Algorithme

Implantation en Python Correction

Complexité Conclusion

(93)

Correction de la fonction de partition

C’est une conséquence immédiate de l’invariant de boucle.

Cet invariant est vrai à l’entrée dans la boucle Il est préservé par chaque tour de boucle.

(94)

Correction de tri_rapide_rec

Évidente pour les sous-tableaux de taille 0ou1.

Soit n≥2, etg et d délimitant un sous-tableau de taille n.

Supposons tri_rapide_rec sur tous les sous-tableaux strictement plus petits. Alors après l’exécution de i = partition(t, g, d), on agi <d et :

1 tous les éléments det[g :i]sont inférieurs ou égaux àt[i]

2 tous ceux det[i+ 1 :d]sont supérieurs ou égaux.

De plus, ig <dg =n et

d −(i+ 1)<didg =n. Donc, par hypothèse de récurrence, les appels récursifs trient respectivement les sous-tableaux de t d’indices dans Jg,iJetJi+ 1,dJ. À l’issue de ces appels récursifs, les propriétés 1. et 2. sont encore vérifiées par ces sous-tableaux et comme ils sont de plus triés, t[g :d]est trié et possède les mêmes éléments qu’initialement.

(95)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

Algorithme

Implantation en Python Correction

Complexité Conclusion

(96)

Domination par le nombre de comparaisons

Comme pour les tris par insertion et par sélection, la complexité temporelle est dominée par le nombre de comparaisons effectuées.

L’appel à partition(t, g, d)effectue toujoursdg−1 comparaisons et partitionne le sous-tableau à trier en deux sous-tableaux de taille p etq avecp+q=dg −1.

(97)

Cas le pire

On peut montrer que, pour un sous tableau de longueur n, le cas où un des sous-tableaux construit par la partition est vide et l’autre de longueur n−1est un pire cas.

C’est notamment le cas si le tableau de départ ne contient que des éléments égaux. Remarquons que le nombre de comparaisons effectuées partri_rapide_rec pour un tableau trié de taille n ne dépend pas du contenu du tableau mais juste de n et notonsC(n)ce nombre.

n∈N C(n) =n−1 +C(n−1) D’où∀n∈N C(n)−C(0) =

n

X

k=1

(k−1) =n(n−1)/2 =O(n2)

(98)

Cas le pire (bis)

Le cas où le tableau initial est trié par ordre décroissant constitue également un cas où la complexité estO(n2).

Exercice

Le démontrer (il faudra s’intéresser à deux appels récursifs successifs pour comprendre).

(99)

Cas le meilleur

À l’inverse, lorsque le sous-tableau est coupé en deux moitiés de tailles à peu près égales est un cas le meilleur.

En notant C0(n)le nombre de comparaisons effectuées dans le meilleur des cas pour un tableau de taille n, on peut montrer

n∈N C0(n) =n−1 + 2C0n−1 2

On peut en déduireC0(n) =O(nlogn)(commencer par s’intéresser aux tableaux de taille 2k−1).

(100)

Conclusion (provisoire)

Dans le cas le pire : O(n2). Ce cas se produit notamment lorsque tous les éléments sont égaux ou lorsqu’ils sont triés par ordre croissant ou décroissant.

Dans le cas le meilleur : O(nlogn)(en pratique souvent plus rapide que le tri fusion).

En moyenne3 :O(nlogn) (en pratique souvent plus rapide que le tri fusion) ; écart-typeO(n).

3. Espérance du temps de calcul pour des donnéesdistinctes, mélangées aléatoirement de façon équiprobable (résultat hors-programme).

(101)

Réparer les défauts

1 Mieux choisir le pivot. Deux méthodes classiques :

1 La médiane du premier élément, du dernier élément et de l’élément du milieu du tableau (idéal si le tableau est déjà trié, pas mauvais en général sinon).

2 En prendre un au hasard dans le tableau (théoriquement efficace mais très coûteux en pratique).

2 Partitionnement trois voies : les éléments strictement plus petits que le pivot, les strictement plus grands et les égaux.

(102)

Complexité avec ces améliorations

Avec le partitionnement trois voies :

O(nlogn) en moyenne pour une permutation aléatoire de données, non nécessairement distinctes.

Avec le pivot aléatoire :

O(nlogn) en moyenne pour des données fixées toutes distinctes.

Avec pivot aléatoire et partitionnement trois voies : O(nlogn) en moyenne pour des données fixées non nécessairement distinctes.

Dans tous les cas :

O(nlogn) dans le cas le meilleur ; O(n2) dans le cas le pire.

(103)

Complexité en espace

C’est la profondeur maximale des appels récursifs.

O(logn) dans le cas le meilleur.

O(n) dans le cas le pire. Peut être ramenée àO(logn)avec une idée due à Sedgewick4.

4. Pour cela, après avoir partitionné, on commence par trier (récursivement) la partition la plus petite avant de trier l’autre, sans appel récursif. Voir le livre Informatique pour tous en CPGE pour plus de détails.

(104)

1 Introduction 2 Tri par sélection 3 Tri par insertion 4 Tri fusion 5 Tri par pivot

Algorithme

Implantation en Python Correction

Complexité Conclusion

(105)

Conclusion sur le tri par pivot

Souvent préféré au tri par fusion pour son efficacité pratique.

L’implanter correctement est très délicat (cas enn2).

À éviter sur des données d’origine mal intentionnée.

Complexité temporelle du tri par pivot

O(nlogn) dans le cas le meilleur et en moyenne.

O(n2) dans le cas le pire.

Complexité spatiale du tri par pivot Dans le cas le meilleur : O(logn)

Dans le cas le pire : O(n) pour la version naïve, O(logn) avec optimisation.

Références

Documents relatifs

Il ne le supporte pas. Il décide de dévorer toutes les histoires qui parlent de grand méchant loup.!. Mais il ne dévore pas que

La qualification juridique du texte numérique est le préalable indispensable à l ’étude des modalités d’application des droits d’auteur au document numérique par exemple,

Dans la série « collège autour d'un thème », cet article présente la réalisation de quelques expériences simples (et peu coûteuses) à réaliser sur 2 séances d'une heure,

Il peut s’agir de stratégies de passation de test : dans le cas de l’épreuve de français, l’étudiant pourra réaliser un texte en reproduisant un modèle générique, limiter

Constatant la difficulté à appliquer les résultats des enquêtes du type Baro- mètre santé dans le champ social, de plus en plus d’auteurs s’attachent aujourd’hui à définir

Chez vous ou en visio s’entraîner à mettre en place la démarche pédagogique d’apprentissage en partant de l’observation du pratiquant dans un domaine sportif ou non de

Dans une phrase déclarative, le pronom est devant le verbe conjugué, ou devant l’auxiliaire, ou devant l’infinitif ; le « ne » se place devant les pronoms. Quand il y a

Pour les limiter, cer- tains acteurs du marché se sont enga- gés à mettre en place des conditions de productionplusvertueuses.C’estlecas de la marque premium Café Royal (DELICA,