AccueilđŸ‡«đŸ‡·Chercher

Quickselect

En algorithmique, quickselect est un algorithme de sélection qui retourne le ke plus petit élément dans une liste non ordonnée. Comme l'algorithme de tri quicksort, il a été créé par Tony Hoare et il est donc aussi connu comme l' algorithme de sélection de Hoare[1].

Quickselect
Visualisation animée de l'algorithme de sélection rapide. Sélection de la 22Úme plus petite valeur.
DĂ©couvreur ou inventeur
Date de découverte
ProblÚme lié
Structure des données
À l'origine de
Complexité en temps
Pire cas
Moyenne
Meilleur cas
Complexité en espace
Pire cas

Quickselect utilise la mĂȘme approche que quicksort, choisissant un Ă©lĂ©ment Ă  la fois, afin de partitionner les Ă©lĂ©ments selon le pivot. Cependant, au lieu de sĂ©parer l'ensemble en deux parties comme dans quicksort, l'algorithme quickselect n'utilise la rĂ©cursion que sur un cĂŽtĂ© - le cĂŽtĂ© contenant l'Ă©lĂ©ment qu'il cherche. Cela rĂ©duit la complexitĂ© en moyenne O(n log n) de quicksort Ă  la complexitĂ© en moyenne O(n) de quickselect.

Tout comme quicksort, l'algorithme quickselect est en général implémenté en place, et en plus de sélectionner le ke élément, il trie une partie des données. Comme quicksort, il est efficace en pratique avec un temps moyen de . Quickselect et ses variantes sont des algorithmes souvent utilisés dans le monde réel.

Algorithme

Quicksort utilise une fonction auxiliaire, appelĂ©e partition, qui rĂ©organise la liste allant de la position gauche Ă  la position droite en deux parties : les Ă©lĂ©ments qui sont plus petits qu'un certain Ă©lĂ©ment appelĂ© pivot, et ceux qui sont supĂ©rieurs ou Ă©gaux au mĂȘme Ă©lĂ©ment. Voici le pseudo-code qui crĂ©e cette partition:

fonction partition(list, gauche, droite, pivot)
    ValeurPivot := list[pivot]
    Ă©changer list[pivot] et list[droite]  // DĂ©place le pivot Ă  la fin
    IndiceStockage := gauche
    pour i de gauche Ă  droite-1
        si list[i] < ValeurPivot
            Ă©changer list[IndiceStockage] et list[i]
            incrémenter IndiceStockage
    échanger list[droite] et list[IndiceStockage]  // Met le pivot à sa place définitive.
    retourner IndiceStockage

Quicksort trie récursivement les deux branches, créant un pire cas en temps de Ω(n log n). Cependant la sélection choisit de quel cÎté de la partition se trouve l'élément, puisque le pivot est à sa place finale, avec les éléments plus petits à gauche et les plus grands à droite. Donc un seul appel récursif suffit à créer l'algorithme quickselect:

 // Retourne le n-iĂšme plus petit Ă©lĂ©ment de la liste entre gauche et droite incluse (i.e. gauche ≀ n ≀ droite).
 // La taille de la liste reste la mĂȘme Ă  chaque appel rĂ©cursif, donc n n'a pas besoin d'ĂȘtre changĂ©.
 fonction select(list, gauche, droite, n)
    si gauche = droite          // S'il n'y a qu'un élément
        retourner list[gauche]  // Retourne cet élément
    pivot := ...               // Choisit un pivot entre gauche et droite, par exemple  
                                // gauche + Math.floor(Math.random() * (droite - gauche + 1))
    pivot := partition(list, gauche, droite, pivot)
    // Si le pivot est Ă  sa position finale
    si n = pivot
        retourner list[n]
    sinon si n < pivot
        retourner select(list, gauche, pivot - 1, n)
    sinon
        retourner select(list, pivot + 1, droite, n)

Remarquons la ressemblance avec quicksort: tout comme l'algorithme basĂ© sur la sĂ©lection de l'Ă©lĂ©ment minimal est un algorithme de tri partiel, quickselect est un quicksort partiel, crĂ©ant et partitionnant uniquement O(log n) de ces O(n) partitions. Cette procĂ©dure a en moyenne un temps d'exĂ©cution linĂ©aire, et de bonnes performances en pratique. C'est en plus un algorithme en place, utilisant un espace constant supplĂ©mentaire puisque la rĂ©cursion terminale peut ĂȘtre Ă©liminĂ©e avec une boucle telle que:

fonction select(list, gauche, droite, n)
   boucle
        si gauche = droite
           retourner list[gauche]
        pivot := ...     // Choix du pivot entre gauche et droite
        pivot := partition(list, gauche, droite, pivot)
        si n = pivot
            retourner list[n]
        sinon si n < pivot
            droite := pivot - 1
        sinon
            gauche := pivot + 1

Complexité en temps

Tout comme quicksort, l'efficacitĂ© de l'algorithme quickselect dĂ©pend du choix du pivot. Si le choix de pivot permet de faire dĂ©croĂźtre la taille du tableau Ă  chaque Ă©tape d'une mĂȘme fraction, alors la dĂ©croissance est exponentielle, et la complexitĂ© en temps est linĂ©aire, comme une sĂ©rie gĂ©omĂ©trique. Si au contraire le pivot ne fait diminuer la taille que de 1, alors le pire cas a une complexitĂ© quadratique, O(n2). Cela arrive principalement si le pivot est l'Ă©lĂ©ment le plus Ă  droite et que le tableau est dĂ©jĂ  triĂ©.

Variantes

La solution la plus simple est de choisir un pivot alĂ©atoire, qui donne avec grande probabilitĂ© un temps d'exĂ©cution linĂ©aire. Comme algorithme dĂ©terministe, la stratĂ©gie de la mĂ©diane de 3 valeurs, comme dans quicksort, donne un temps d'exĂ©cution linĂ©aire sur les donnĂ©es partiellement triĂ©es, ce qui arrive souvent en vrai. Mais la complexitĂ© pire-cas peut toujours ĂȘtre atteinte, David Musser a montrĂ© comment atteindre ce pire cas, contre lequel il existe son algorithme introselect.

Une complexitĂ© linĂ©aire en pire-cas peut-ĂȘtre obtenue via la mĂ©thode de mĂ©diane des mĂ©dianes, avec un surcout pratique considĂ©rable, ce qui fait qu'il n'est pas utilisĂ© en pratique. Il est possible de le combiner avec le quickselect basique, et cet algorithme pour le pire cas, afin d'avoir de bons rĂ©sultats en pratiques et une bonne complexitĂ© dans le pire cas, c'est ce que fait introselect.

Plus prĂ©cisĂ©ment, la complexitĂ© moyenne en temps est pour un pivot alĂ©atoire (dans le cas de la recherche de la mĂ©diane, d'autres k sont plus rapides)[2]. La constante peut ĂȘtre descendue Ă  3/2 avec un pivot plus complexe, utilisant l'algorithme de Floyd–Rivest, dont la complexitĂ© moyenne en temps est de pour le calcul de la mĂ©diane, et plus rapide avec d'autres k.

Notes et références

  1. (en) C.A.R. Hoare, « Algorithm 65: find », Communications of the ACM, vol. 4, no 7,‎ , p. 321-322 (DOI 10.1145/366622.366647).
  2. Blum-style analysis of Quickselect, David Eppstein, October 9, 2007.
Cet article est issu de wikipedia. Text licence: CC BY-SA 4.0, Des conditions supplĂ©mentaires peuvent s’appliquer aux fichiers multimĂ©dias.