Aller au contenu

Insertion

On programme ici la partie insertion: comment insérer une nouvelle carte dans un tableau déjà trié.

Exercice

On rappelle que l'opérateur + entre deux listes a pour effet de créer une liste concaténation de la première liste et de la seconde.

>>> a = [42, 666]
>>> b = [1789, 1968]
>>> c = a + b
>>> c
[42, 666, 1789, 1968]

On considère le code suivant:

def insertion(tab, valeur):
    """
    tab -- liste d'entiers
    préconditions: 
        - liste est triée en ordre croissant
        - les éléments de liste sont tous distincts
    valeur -- entier

    renvoie .....
    """
    return [x for x in tab if x < valeur] + [valeur] + [x for x in tab if x >= valeur]    
  • Quelle est la valeur de insertion([2, 3, 5, 6, 8], 3)?
  • Quelle est la valeur de insertion([2, 3, 5, 6, 8], 1)?
  • Quelle est la valeur de insertion([2, 3, 5, 6, 8], 9)?
  • Compléter la ligne "renvoie ..." du docstring.
Valeur renvoyée

La fonction renvoie une liste triée en ordre croissant contenant tous les éléments de tab et l'élément valeur.

Les valeurs demandées

On a indiqué les réponses en les ajoutant au docstring de la fonction.

def insertion(tab, valeur):
    """
    tab -- liste d'entiers, précondition: liste est triée en ordre croissant
    valeur -- entier

    renvoie une liste
        - les éléments de liste sont les éléments de tab et valeur, 
        - liste est triée en ordre croissant. 
    >>> insertion([2, 3, 5, 6, 8], 3)
    [2, 3, 3, 5, 6, 8]
    >>> insertion([2, 3, 5, 6, 8], 1)
    [1, 2, 3, 5, 6, 8]
    >>> insertion([2, 3, 5, 6, 8], 9)
    [2, 3, 5, 6, 8, 9]
    """
    return [x for x in tab if x < valeur] + [valeur] + [x for x in tab if x >= valeur]    
  • Quel est le nombre de comparaisons effectuées lors d'une exécution de la fonction insertion? (ce nombre est fonction de la longueur n de la liste tab passée en paramètre).
Comparaisons?

On rappelle qu'une comparaison est l'utilisation de <, ou ==, ou >=, ou <=, ou >.

Nombre de comparaisons

Notons n la longueur de liste passée en argument.

  • Dans [x for x in tab if x < valeur], n comparaisons.
  • Dans [x for x in tab if x >= valeur], n comparaisons.

Au total, 2n comparaisons.

Exercice

Écrire un code possible pour la fonction suivante:

def rechercheIndicePivot(tab, valeur):
    """
    tab -- liste d'entiers
    précondition: tab triée en ordre croissant
    valeur -- entier

    renvoie le plus petit indice i tel que tab[i] >= valeur
    et renvoie len(tab) si un tel indice n'existe pas.
    """
Un principe

Comme les éléments sont triés en ordre croissant, on les parcourt de gauche à droite et on s'arrête dès qu'on en a un qui est supérieur ou égal à la valeur pivot donnée en paramètre.

Solution

Un code possible:

def rechercheIndicePivot(tab, valeur):
    """
    tab -- liste d'entiers, précondition: tab triée en ordre croissant
    valeur -- entier

    renvoie le plus petit indice i tel que tab[i] >= valeur
    et renvoie len(tab) si un tel indice n'existe pas.
    """
    for indice, element in enumerate(tab):
        if element >= valeur: return indice
    return len(tab)

Exercice

On va ici réécrire la fonction d'insertion de l'exercice 1 mais en réduisant le nombre de comparaisons effectuées. Pour réduire ce nombre de comparaisons, nous utiliserons la précondition (qui n'a pas été utilisée dans la version de l'exercice 1): la liste donnée en paramètre est ordonnée. Cette précondition nous permet en effet de ne parcourir qu'une seule fois la liste (au lieu de deux dans la version précédente de l'insertion).

Insertion

Écrire une version de la fonction insertion de l'exercice 1 utilisant la fonction de l'exercice 2, cette fonction insertion n'utilisera aucune comparaison (ou plus exactement: toutes les comparaisons seront faites uniquement par la fonction rechercheIndicePivot).

def rechercheIndicePivot(tab, valeur):
    """
    tab -- liste d'entiers, 
    précondition: tab triée en ordre croissant
    valeur -- entier

    renvoie le plus petit indice i tel que tab[i] >= valeur
    et renvoie len(tab) si un tel indice n'existe pas.
    """
    for indice, element in enumerate(tab):
        if element >= valeur: return indice
    return len(tab)


def insertion(tab, valeur):
    """
    tab -- liste d'entiers, 
    précondition: liste est triée en ordre croissant
    valeur -- entier

    renvoie une liste
        - les éléments de liste sont les éléments de tab et valeur, 
        - liste est triée en ordre croissant. 
    >>> insertion([2, 3, 5, 6, 8], 3)
    [2, 3, 3, 5, 6, 8]
    >>> insertion([2, 3, 5, 6, 8], 1)
    [1, 2, 3, 5, 6, 8]
    >>> insertion([2, 3, 5, 6, 8], 9)
    [2, 3, 5, 6, 8, 9]
    """
    indicePivot = rechercheIndicePivot(tab, valeur)
    # PARTIE A COMPLETER

Principe

La fonction rechercheIndicePivot() donne l'indice indicePivot auquel placer notre valeur.

On construit donc une liste en y plaçant:

  • en premier lieu, tous les éléments de tab ayant un indice < indicePivot (dans l'ordre de leurs indices puisqu'ils sont déjà en ordre croissant),
  • puis la valeur donnée en paramètre,
  • et enfin tous les éléments de tab ayant un indice ≥ indicePivot (dans l'ordre de leurs indices).
Solution

Un code possible:

def rechercheIndicePivot(tab, valeur):
    """
    tab -- liste d'entiers, précondition: tab triée en ordre croissant
    valeur -- entier

    renvoie le plus petit indice i tel que tab[i] >= valeur
    et renvoie len(atb) si un tel indice n'existe pas.
    """
    for indice, element in enumerate(tab):
        if element >= valeur: return indice
    return len(tab)



def insertion(tab, valeur):
    """
    tab -- liste d'entiers, précondition: liste est triée en ordre croissant
    valeur -- entier

    renvoie une liste dont les éléments sont les éléments de tab et valeur, la liste
    renvoyée est triée en ordre croissant. 
    >>> insertion([2, 3, 5, 6, 8], 3)
    [2, 3, 3, 5, 6, 8]
    >>> insertion([2, 3, 5, 6, 8], 1)
    [1, 2, 3, 5, 6, 8]
    """
    indice_pivot = rechercheIndicePivot(tab, valeur)
    return [tab[k] for k in range(indice_pivot)] + [valeur] + [tab[k] for k in range(indice_pivot, len(tab))]

Le nombre de comparaisons

Quel est maintenant le nombre de comparaisons effectuées lors d'un appel à la fonction insertion?

Réponse

Les comparaisons sont toutes effectuées dans l'appel à la fonction rechercheIndicePivot.

Notons n la longueur de la liste tab passée en argument.

  • Il peut y avoir 0 comparaison (cas de la liste vide).
  • Il peut y avoir une unique comparaison (cas tab[0] ≥ valeur).
  • Il peut y avoir deux comparaisons (cas tab[0] < valeur et tab[1] ≥ valeur).
  • Il peut y avoir trois comparaisons (cas tab[0] < valeur, tab[1] < valeur et tab[2] ≥ valeur).
  • ...
  • Il peut y avoir n comparaisons (cas tab[0], tab[1], ..., tab[n-2] tous < valeur et tab[n-1] ≥ valeur ou encore cas où tous les éléments sont < valeur).

Le nombre de comparaisons est donc compris entre 0 et n suivant la liste tab donnée en entrée. Nous avons donc réduit au moins de moitié le nombre de comparaisons par rapport à la version 1 de notre fonction d'insertion.