Post on 13-Jul-2020
Tris rapides
Émeric Tourniaire
26 janvier 2020
Trier des nombres
‚ Liste de nombres‚ Mettre dans le bon ordre‚ l.sort() et sorted(l)
‚ Piège classique
21 14 32 17
14 17 21 32
Trier des nombres
‚ Liste de nombres‚ Mettre dans le bon ordre‚ l.sort() et sorted(l)
‚ Piège classique
21 14 32 17
14 17 21 32
Trier des nombres
‚ Liste de nombres‚ Mettre dans le bon ordre‚ l.sort() et sorted(l)
‚ Piège classique
IN : li = [21, 14, 32, 17]IN : li.sort()IN : liOUT: [14, 17, 21, 32]
Trier des nombres
‚ Liste de nombres‚ Mettre dans le bon ordre‚ l.sort() et sorted(l)
‚ Piège classique
IN : li = [21, 14, 32, 17]IN : sorted(li)OUT: [14, 17, 21, 32]IN : liOUT: [21, 14, 32, 17]
Trier des nombres
‚ Liste de nombres‚ Mettre dans le bon ordre‚ l.sort() et sorted(l)‚ Piège classique
IN : li = [21, 14, 32, 17]IN : li = li.sort()IN : liOUT:
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def tri_a_bulle(li):n = l en (li)for i in range(n):
for j in range(n´1):if li[j] >= li[j+1]:
aux = li[j]li[j] = li[j+1]li[j+1] = aux
Une
pass
e
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def tri_a_bulle(li):n = l en (li)for i in range(n):
for j in range(n´1):if li[j] >= li[j+1]:
aux = li[j]li[j] = li[j+1]li[j+1] = auxUn
epa
sse
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def tri_a_bulle(li):n = l en (li)for i in range(n´1):
for j in range(n´i´1):if li[j] > li[j+1]:
li[j], li[j+1] = li[j+1], li[j]
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
Nombre de comparaisons
pn ´ 1q ` ¨ ¨ ¨ ` 1 “npn ´ 1q
2
Nombre d’échanges
: npn ´ 1q
2
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
Nombre de comparaisons
pn ´ 1q ` ¨ ¨ ¨ ` 1 “npn ´ 1q
2
Nombre d’échanges : npn ´ 1q
2
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def maximum(li, j):m = 0for i in range(1, j):
if li[i] >= li[m]:m = i
return mdef tri_selection(li):
n = l en (li)for j in range(n,0,´1):
m = maximum(li, j)li[m], li[j´1] = li[j´1], li[m]
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def maximum(li, j):m = 0for i in range(1, j):
if li[i] >= li[m]:m = i
return mInvariant de boucle : m “ max
kPJ0,iKl[k]
Nombre de comparaisons : j ´ 1
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def tri_selection(li):n = l en (li)for j in range(n,0,´1):
m = maximum(li, j)li[m], li[j´1] = li[j´1], li[m]
Invariant de boucle : l[j-1:n-1] est trié
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def tri_selection(li):n = l en (li)for j in range(n,0,´1):
m = maximum(li, j)li[m], li[j´1] = li[j´1], li[m]
Nombre de comparaisons :n
ÿ
j“1j ´ 1 “
npn ´ 1q
2 „n2
2Nombre d’échanges : ď n ´ 1.
Vieux tris
Créd
it:
Han
sPe
terS
chae
fer,
CC-B
Y-SA
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
def tri_insertion(li):n = l en (li)for j in range(n):
p = jwhile p > 0 and li[p] < li[p´1]:
li[p], li[p´1] = li[p´1], li[p]p = p´1
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
5
86431
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
8
5
6431
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
86
5
431
Vieux tris
‚ Tri à bulles‚ Tri par sélection‚ Tri par insertion
Invariant : l[0:j] est trié.
Nombre de comparaisons au pire : „n2
2Nombre de comparaisons au mieux : n ´ 1Nombre d’échanges : autant que decomparaisons.
Vieux tris
ThéorèmeLe tri par insertion effectue en moyenne un nombre de
comparaisons équivalent à n2
4
Proof.Nombre d’inversions…
Vieux tris
ThéorèmeLe tri par insertion effectue en moyenne un nombre de
comparaisons équivalent à n2
4Proof.Nombre d’inversions…
timsort
‚ En Python ? timsort‚ Tim Peters‚ CPython, Jython, Pypy,
java, octave
‚ Bug ?‚ Analyse automatique
timsort
This describes an adaptive, stable, natural mergesort, modestlycalled timsort (hey, I earned it <wink>). It has supernaturalperformance on many kinds of partially ordered arrays (less thanlg(N!) comparisons needed, and as few as N-1), yet as fast asPython’s previous highly tuned samplesort hybrid on randomarrays.
timsort
‚ En Python ? timsort‚ Tim Peters‚ CPython, Jython, Pypy,
java, octave
‚ Bug ?‚ Analyse automatique
PypyAdapted from CPython, originalcode and algorithms by Tim Peters
Javatimsort depuis 2014 (937 lignes).This implementation was adaptedfrom Tim Peters’s list sort forPython
timsort
‚ En Python ? timsort‚ Tim Peters‚ CPython, Jython, Pypy,
java, octave
‚ Bug ?‚ Analyse automatique
PypyAdapted from CPython, originalcode and algorithms by Tim Peters
Javatimsort depuis 2014 (937 lignes).This implementation was adaptedfrom Tim Peters’s list sort forPython
timsort
‚ En Python ? timsort‚ Tim Peters‚ CPython, Jython, Pypy,
java, octave‚ Bug ?
‚ Analyse automatique
« Proving that Android’s, Java’s andPython’s sorting algorithm is broken(and showing how to fix it) » (24février 2015)
timsort
‚ En Python ? timsort‚ Tim Peters‚ CPython, Jython, Pypy,
java, octave‚ Bug ?‚ Analyse automatique
KeY is a deductive verificationplatform for sequential Java andJavaCard applications. It allows toprove the correctness of programswith respect to a given specification.
timsort
‚ En Python ? timsort‚ Tim Peters‚ CPython, Jython, Pypy,
java, octave‚ Bug ?‚ Analyse automatique
[timsort] was intended to work forarrays with up to 264 elements.However, on current machines [thisversion] suffices [...] for arrays withless than 249 elements. Forcomparison, the current mostpowerful supercomputer [...] hasabout 250 bytes of memory in total.
timsort
« This affects all current versions of Python. However, I markedthe priority ”low” because, as the article also notes, there’scurrently no machine in existence with enough memory to hold anarray large enough for a contrived input to trigger an overflow ofthe pending-runs stack.It should be fixed anyway, and their suggested fix looks good tome. »(Tim Peters, 24 février)
timsort
« A logical error is an error, and will bite us eventually, regardlessof whether it does so today. I’m very glad the researchers went toall the trouble to analyze this one :-) »(Tim Peters, 25 février, après correction)
Clé de tri
‚ Trier des entiers ?‚ Trier des objets‚ Fonction cmp‚ Fonction key‚ Préordre total‚ Stabilité
14 12 3 21 32 42
Clé de tri
‚ Trier des entiers ?‚ Trier des objets‚ Fonction cmp‚ Fonction key‚ Préordre total‚ Stabilité
Clé de tri
Clé de triMungo Park (1771 – 1806) et James Rennell (1742 – 1830)
Clé de tri
Clé de tri
Carte de Rennell, 1802A Map, shewing the Progress of Discovery & Improvement, in the Geography of North Africa
Clé de tri
Carte de Rennell, 1802A Map, shewing the Progress of Discovery & Improvement, in the Geography of North Africa
Clé de tri
Map of Africa from the Latest Authorities, 1852
Clé de tri
Synthèse
Clé de tri
Clé de tri
‚ Trier des entiers ?‚ Trier des objets‚ Fonction cmp‚ Fonction key‚ Préordre total‚ Stabilité
def compa(ch1 , ch2):return l en (ch1)´ l en (ch2)
IN : li = ["ab", "b", "adc", "ddda"]IN : sorted(li)OUT: ['ab', 'adc', 'b', 'ddda']IN : sorted(li, cmp=compa)OUT: ['b', 'ab', 'adc', 'ddda']
Clé de tri
‚ Trier des entiers ?‚ Trier des objets‚ Fonction cmp‚ Fonction key‚ Préordre total‚ Stabilité
def compa(ch1 , ch2):return l en (ch1)´ l en (ch2)
IN : li = ["ab", "b", "adc", "ddda"]IN : sorted(li)OUT: ['ab', 'adc', 'b', 'ddda']IN : sorted(li, cmp=compa)OUT: ['b', 'ab', 'adc', 'ddda']
Clé de tri
‚ Trier des entiers ?‚ Trier des objets‚ Fonction cmp‚ Fonction key‚ Préordre total‚ Stabilité
def cle(ch):return l en (ch)
IN : li = ["ab", "b", "adc", "ddda"]IN : sorted(li)OUT: ['ab', 'adc', 'b', 'ddda']IN : sorted(li, key=cle)OUT: ['b', 'ab', 'adc', 'ddda']
Clé de tri
‚ Trier des entiers ?‚ Trier des objets‚ Fonction cmp‚ Fonction key‚ Préordre total‚ Stabilité
IN : li = ["ab", "b", "adc", "ddda"]IN : sorted(li, key=lambda x: l en (x))['b', 'ab', 'adc', 'ddda']
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
def occurrences(li , max):res = [0] * maxfor i in li:
res[i] += 1return res
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
occ : 2 1 0 2res :
0 0 1 3 3
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
occ : 2 1 0 2res : 0 0
1 3 3
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
occ : 2 1 0 2res : 0 0 1
3 3
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
occ : 2 1 0 2res : 0 0 1 3 3
Principe général
‚ Entiers dans J0; max ´ 1K‚ Compter les occurrences.‚ Réécrire le tableau
def tri_lineaire(li , max):occ = occurrences(li, max)res = [0] * l en (li)k=0for i in range(max):
for j in range(occ[i]):res[k] = ik = k+1
return res
Trier n’importe quoi
‚ Objets et clé‚ Occurrences‚ Positions‚ Résultat
li = [(3, "Afrique␣du␣Sud"),(2, "Bolivie"),(1, "France"),...
]
def cle(i):return i[0]
Trier n’importe quoi
‚ Objets et clé‚ Occurrences‚ Positions‚ Résultat
max = 8
res = [0] * maxfor i in li:
res[cle(i)] += 1
Trier n’importe quoi
‚ Objets et clé‚ Occurrences‚ Positions‚ Résultat
pos = [0] * maxfor i in range(1, max):
pos[i] = pos[i´1] + res[i´1]
Trier n’importe quoi
‚ Objets et clé‚ Occurrences‚ Positions‚ Résultat
res = [0]* l en (li)for i in li:
res[pos[cle(i)]] = ipos[cle(i)] += 1
Trier n’importe quoi
BilanL’algorithme fonctionne en temps Opn ` maxq.Il s’agit d’un tri stable.
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines
‚ etc.‚ Complexité :
Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines
‚ etc.‚ Complexité :
Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines
‚ etc.‚ Complexité :
Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines
‚ etc.‚ Complexité :
Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines
‚ etc.‚ Complexité :
Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines‚ etc.
‚ Complexité :Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines‚ etc.
‚ Complexité :Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Tri par radix
‚ Trier des entiers‚ Trier par unités‚ Trier par dizaines‚ etc.‚ Complexité :
Opn ˆ kq
1 0 1 21 0 1 11 0 0 12 0 1 12 0 0 20 2 1 11 0 1 2
1 0 1 11 0 0 12 0 1 10 2 1 11 0 1 22 0 0 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 10 2 1 11 0 1 21 0 1 2
1 0 0 12 0 0 21 0 1 12 0 1 11 0 1 21 0 1 20 2 1 1
0 2 1 11 0 0 11 0 1 11 0 1 21 0 1 22 0 0 22 0 1 1
Arbre de décision
‚ Comparaisons‚ Structure d’arbre‚ Profondeur
minimale
[a,b,c]a ă b
b ă c a ă c
a ă c b ă ca,b,c b,a,c
a,c,b c,a,b b,c,a c,b,a
Arbre de décision
‚ Comparaisons‚ Structure d’arbre‚ Profondeur
minimale
[a,b,c]a ă b
b ă c a ă c
a ă c b ă ca,b,c b,a,c
a,c,b c,a,b b,c,a c,b,a
Arbre de décision
‚ Comparaisons‚ Structure d’arbre‚ Profondeur
minimale
[a,b,c]a ă b
b ă c a ă c
a ă c b ă c
a,b,c b,a,c
a,c,b c,a,b b,c,a c,b,a
Arbre de décision
[a,b,c]a ă b
b ă c a ă c
a ă c b ă c
a,b,c b,a,ca,c,b c,a,b b,c,a c,b,a
Hau
teur
:h
“3
Nombre maximal de feuilles : 2h “ 8 ą 3!
Arbre de décision
[a,b,c]a ă b
b ă c a ă c
a ă c b ă c
a,b,c b,a,ca,c,b c,a,b b,c,a c,b,a
Hau
teur
:h
“3
Nombre maximal de feuilles : 2h “ 8 ą 3!
Arbre de décision
[a,b,c]a ă b
b ă c a ă c
a ă c b ă c
a,b,c b,a,ca,c,b c,a,b b,c,a c,b,a
Hau
teur
:h
“3
Nombre maximal de feuilles : 2h “ 8 ą 3!
Arbre de décision
Conclusion 1Soit un algorithme de tri par comparaisons qui réalise au plus hcomparaisons et trie un tableau de taille n. On a alors 2h ą n!.
Conclusion 2On ne peut pas avoir h “ opn lg nq.
Conclusion 3On ne peut pas avoir une profondeur moyenne qui serait enopn lg nq non plus.
Arbre de décision
Sous-théorèmeDans un arbre binaire strict à f feuilles, la profondeur moyenne estsupérieure ou égale à lg f .
Arbre de décision
CorollaireUn algorithme de tri par comparaisons est au mieux en complexitéen moyenne (ou dans le pire des cas) en Opn lg nq.
Tri par fusion
‚ Diviser pour régner‚ Couper le tableau en deux‚ Trier (récursivement)‚ Fusionner
‚ Recopier
Division
Tri Tri
Fusion
Recopie
Tri par fusion
‚ Diviser pour régner‚ Couper le tableau en deux‚ Trier (récursivement)‚ Fusionner‚ Recopier
Division
Tri Tri
Fusion
Recopie
Tri par fusion
def fusion(t,a,c,b):# Les sous tableaux t[a:c] et# t[c:b] sont triéstemp = t[a:b]c1 = ac2 = cfor k in range(b´a):
if c2==b or (c1<c and t[c1]<=t[c2]):temp[c1+c2´a´c] = t[c1]c1 += 1
else:temp[c1+c2´a´c] = t[c2]c2 += 1
return temp
Tri par fusion
def tri_fusion(t, a, b):# Trie entre les indices a et b´1# Donc b a éléments.if b´a < 2:
return Noneif b´a == 2:
if t[a]>t[a+1]:t[a], t[a+1] = t[a+1], t[a]
return Nonec = (a+b)//2tri_fusion(t, a, c)tri_fusion(t, c, b)temp = fusion(t, a, c, b)for i in range(b´a):
t[a+i] = temp[i]
Tri par fusion
ThéorèmeLe tri fusion a une complexité temporelle en Opn lg nq et unecomplexité spatiale en Opnq.
Quicksort
‚ Choisir un pivot‚ Segmenter (placer le pivot)‚ Récursiver
tableau
pď p ě p
Tri Tri
Quicksort
‚ Choisir un pivot‚ Segmenter (placer le pivot)‚ Récursiver
tableau p
pď p ě p
Tri Tri
Quicksort
‚ Choisir un pivot‚ Segmenter (placer le pivot)‚ Récursiver
tableau p
pď p ě p
Tri Tri
Quicksort
‚ Choisir un pivot‚ Segmenter (placer le pivot)‚ Récursiver
tableau p
pď p ě p
Tri Tri
Quicksort
def segmenter(t,i,j):# on traite t[i:j]# pivot en position j´1p = t[j´1]lim = ifor k in range(i, j´1):
if t[k] < p:t[k], t[lim] = t[lim], t[k]lim += 1
t[lim], t[j´1] = t[j´1], t[lim]return lim
Quicksort
def segmenter(t,i,j):# on traite t[i:j]# pivot en position j´1p = t[j´1]lim = ifor k in range(i, j´1):
if t[k] < p:t[k], t[lim] = t[lim], t[k]lim += 1
t[lim], t[j´1] = t[j´1], t[lim]return lim
p
limlimlim k
ď p ě p ?
Quicksort
def quicksort(t, i, j):if j´i > 1:
a = segmenter(t, i, j)quicksort(t, i, a)quicksort(t, a + 1, j)
Quicksort
ThéorèmeLe Quicksort a une complexité spatiale Opnq et une complexitétemporelle Opn2q.
Timsort, illustration
Timsort, illustration
Timsort, illustration
Timsort, illustration
Bibliographie
https://github.com/python/cpython/blob/master/Objects/list-sort.txthttp://envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/http://corte.si/posts/code/timsort/index.html