Algorithmes de Tri

In [1]:
# Juste pour l'affichage ; pas à connaître

from IPython.display import display, HTML

def table(t, vert=(), rouge=(), bleu=()):
    # Couleurs : <https://clrs.cc/>
    s = ["<table style='font-size:130%'>", "<tr>"]
    for i, x in enumerate(t):
        couleur = "#2ECC40" if i in vert else ""
        if i in rouge: couleur = "#FF4136"
        if i in bleu: couleur = "#0074D9"
        s.extend(['<td bgcolor="{}">'.format(couleur), str(x), '</td>'])
    s.extend(["</tr>", "</table>"])
    return s

def affiche(*args, **kwargs):
    display(HTML(''.join(table(*args, **kwargs))))

Tri par insertion

  • Complexité : $O(n^2)$
  • en place, adaptatif, stable
In [2]:
def tri_insertion(t):
    for i in range(len(t)):
        j = i
        while j > 0 and t[j]<t[j-1]:
            t[j], t[j-1] = t[j-1], t[j]
            j = j-1
            
def tri_insertion_affiche(t):
    """
    Vert/Bleu : zone déjà triée (invariant)
    Bleu : éléments comparés/échangés
    Rouge : prochain élément à insérer
    """
    affiche(t, [], [0])
    for i in range(len(t)):
        j = i
        while j > 0 and t[j]<t[j-1]:
            t[j], t[j-1] = t[j-1], t[j]
            j = j-1
        affiche(t, range(i+1), [i+1], range(j, i+1))
In [3]:
u = [2, 7, 3, 1, 4, 6, 5]
tri_insertion_affiche(u)
2731465
2731465
2731465
2371465
1237465
1234765
1234675
1234567
In [4]:
import random
v = [random.randrange(0, 100) for i in range(10)]
tri_insertion_affiche(v)
1343641753893990224
1343641753893990224
1343641753893990224
1343641753893990224
1317436453893990224
1317435364893990224
1317435364893990224
1317394353648990224
1317394353648990224
1317223943536489904
4131722394353648990

Tri sélection

In [5]:
def pos_maxi(t, n):
    pos = 0
    for i in range(n):
        if t[i] > t[pos]:
            pos = i
    return pos

def tri_selection(t):
    for j in range(len(t), 0, -1):
        p = pos_maxi(t, j)
        t[j-1], t[p] = t[p], t[j-1]
        
def tri_selection_affiche(t):
    """
    Vert/Bleu : zone déjà triée (invariant)
    Bleu : éléments comparés/échangés
    Rouge : prochain élément à insérer
    """
    affiche(t, rouge=[len(t)-1])
    for j in range(len(t), 0, -1):
        p = pos_maxi(t, j)
        t[j-1], t[p] = t[p], t[j-1]
        affiche(t, range(j, len(t)), [j-2], [j-1, p])
In [6]:
v = [random.randrange(0, 100) for i in range(10)]
tri_selection_affiche(v)
6495904497946958231
6431904497946958295
6431904497946829595
6431824497946909595
6431464497982909595
6431464497982909595
9314644647982909595
9314446647982909595
9314446647982909595
9314446647982909595
9314446647982909595

Tri fusion

In [12]:
# Juste pour l'affichage ! Pas à connaître

def trace(f):   
    from IPython.display import display, SVG
    import graphviz
    def show_trace():
        s = ['digraph Trace {', 'node [shape=rectangle]', 'None [style=invis]']
        nodes = []
        for caller, current, label in trace.graph:
            s.append('{}  [label="{}"]'.format(current, label))
            s.append('{}->{}'.format(caller, current))
        s.extend('}')
        trace.graph[:]=[]
        display(SVG(graphviz.Source('\n'.join(s), engine='dot')._repr_svg_()))
    def g(*args):
        caller = None if trace.stack==[] else trace.stack[-1]
        trace.compteur += 1
        callee = trace.compteur
        trace.stack.append(callee)
        res = f(*args)
        trace.graph.append((caller, callee, "{}{} = {}".format(f.__name__, args, res)))
        trace.stack.pop()
        if trace.stack==[]:
            show_trace()
        return res
    trace.stack = []
    trace.graph = []
    trace.compteur = 0
    return g
In [22]:
#@trace
def fusion(u, v):
    res, i, j = [], 0, 0
    while i < len(u) and j < len(v):
        if u[i] < v[j]:
            res.append(u[i])
            i += 1
        else:
            res.append(v[j])
            j += 1
    return res+u[i:]+v[j:]

@trace
def tri_fusion(t):
    n = len(t)
    if n < 2:
        return t
    return fusion(tri_fusion(t[:n//2]), tri_fusion(t[n//2:]))
In [23]:
import random
v = [random.randrange(0, 100) for _ in range(6)]
print(v)
tri_fusion(v)
[9, 37, 36, 13, 68, 13]
Trace 1 tri_fusion([9, 37, 36, 13, 68, 13],) = [9, 13, 13, 36, 37, 68] None->1 3 tri_fusion([9],) = [9] 2 tri_fusion([9, 37, 36],) = [9, 36, 37] 2->3 4 tri_fusion([37, 36],) = [36, 37] 2->4 5 tri_fusion([37],) = [37] 4->5 6 tri_fusion([36],) = [36] 4->6 1->2 7 tri_fusion([13, 68, 13],) = [13, 13, 68] 1->7 8 tri_fusion([13],) = [13] 7->8 9 tri_fusion([68, 13],) = [13, 68] 7->9 10 tri_fusion([68],) = [68] 9->10 11 tri_fusion([13],) = [13] 9->11
Out[23]:
[9, 13, 13, 36, 37, 68]

Tri rapide

In [26]:
import random

@trace
def tri_rapide(t):
    if len(t) < 2:
        return t
    valeur_pivot = t[0] # au hasard : t[random.randrange(len(t))]
    petits, egaux, grands = [], [], []
    for x in t:
        if x < valeur_pivot:
            petits.append(x)
        elif x == valeur_pivot:
            egaux.append(x)
        else:
            grands.append(x)
    return tri_rapide(petits)+egaux+tri_rapide(grands)
In [29]:
import random
v = [random.randrange(0, 100) for _ in range(6)]
print(v)
tri_rapide(v)
[7, 82, 7, 84, 72, 66]
Trace 23 tri_rapide([7, 82, 7, 84, 72, 66],) = [7, 7, 66, 72, 82, 84] None->23 24 tri_rapide([],) = [] 23->24 25 tri_rapide([82, 84, 72, 66],) = [66, 72, 82, 84] 23->25 27 tri_rapide([66],) = [66] 26 tri_rapide([72, 66],) = [66, 72] 26->27 28 tri_rapide([],) = [] 26->28 25->26 29 tri_rapide([84],) = [84] 25->29
Out[29]:
[7, 7, 66, 72, 82, 84]
In [ ]: