web-dev-qa-db-fra.com

Quicksort avec Python

Je suis totalement novice en python et j'essaie d'y intégrer quicksort ... Quelqu'un pourrait-il m'aider à compléter mon code?

Je ne sais pas comment concaténer les trois tableaux et les imprimer. 

def sort(array=[12,4,5,6,7,3,1,15]):
    less = []
    equal = []
    greater = []

    if len(array) > 1:
        pivot = array[0]
        for x in array:
            if x < pivot:
                less.append(x)
            if x == pivot:
                equal.append(x)
            if x > pivot:
                greater.append(x)
            sort(less)
            sort(pivot)
            sort(greater)
73
user2687481
def sort(array=[12,4,5,6,7,3,1,15]):
    less = []
    equal = []
    greater = []

    if len(array) > 1:
        pivot = array[0]
        for x in array:
            if x < pivot:
                less.append(x)
            Elif x == pivot:
                equal.append(x)
            else x > pivot:
                greater.append(x)
        # Don't forget to return something!
        return sort(less)+equal+sort(greater)  # Just use the + operator to join lists
    # Note that you want equal ^^^^^ not pivot
    else:  # You need to hande the part at the end of the recursion - when you only have one element in your array, just return the array.
        return array
187
Brionius

Tri rapide sans mémoire supplémentaire (en place)

Usage:

array = [97, 200, 100, 101, 211, 107]
quicksort(array)
# array -> [97, 100, 101, 107, 200, 211]
def partition(array, begin, end):
    pivot = begin
    for i in xrange(begin+1, end+1):
        if array[i] <= array[begin]:
            pivot += 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot



def quicksort(array, begin=0, end=None):
    if end is None:
        end = len(array) - 1
    def _quicksort(array, begin, end):
        if begin >= end:
            return
        pivot = partition(array, begin, end)
        _quicksort(array, begin, pivot-1)
        _quicksort(array, pivot+1, end)
    return _quicksort(array, begin, end)
118
suquant

Il y a une autre version concise et belle

_def qsort(arr): 
    if len(arr) <= 1:
        return arr
    else:
        return qsort([x for x in arr[1:] if x < arr[0]]) + \
               [arr[0]] + \
               qsort([x for x in arr[1:] if x >= arr[0]])

# this comment is just to improve readability due to horizontal scroll!!!
_

Laissez-moi vous expliquer les codes ci-dessus pour plus de détails

  1. choisissez le premier élément du tableau _arr[0]_ comme pivot

    _[arr[0]]_

  2. qsort ces éléments de tableau qui sont inférieurs à pivot avec List Comprehension

    qsort([x for x in arr[1:] if x < arr[0]])

  3. qsort ces éléments de tableau qui sont plus grands que pivot avec _List Comprehension_

    qsort([x for x in arr[1:] if x >= arr[0]])

67
zangw

Si je recherche "implémentation de python quicksort" dans Google, cette question est le premier résultat à apparaître. Je comprends que la question initiale était «d’aider à corriger le code», mais de nombreuses réponses ignorent déjà cette demande: le le plus voté en second lieu , l’horrible un interligne avec le commentaire hilarant "Vous êtes renvoyé" et, en général, de nombreuses implémentations qui ne sont pas en place (c'est-à-dire utiliser de la mémoire supplémentaire proportionnelle à la taille de la liste d'entrée). Cette réponse fournit une solution sur place mais c'est pour python 2.x. Voici donc mon interprétation de la solution sur place de Rosetta Code qui fonctionnera parfaitement pour python 3 également:

import random

def qsort(l, fst, lst):
    if fst >= lst: return

    i, j = fst, lst
    pivot = l[random.randint(fst, lst)]

    while i <= j:
        while l[i] < pivot: i += 1
        while l[j] > pivot: j -= 1
        if i <= j:
            l[i], l[j] = l[j], l[i]
            i, j = i + 1, j - 1
    qsort(l, fst, j)
    qsort(l, i, lst)

Et si vous êtes prêt à renoncer à la propriété in-situ, vous trouverez ci-dessous une autre version qui illustre mieux les idées de base du quicksort. Outre la lisibilité, son autre avantage est qu'il s'agit de stable (des éléments identiques apparaissent dans la liste triée dans le même ordre que dans la liste non triée). Cette propriété de stabilité ne tient pas à l'implémentation en place moins gourmande en mémoire présentée ci-dessus.

def qsort(l):
    if not l: return l # empty sequence case
    pivot = l[random.choice(range(0, len(l)))]

    head = qsort([elem for elem in l if elem < pivot])
    tail = qsort([elem for elem in l if elem > pivot])
    return head + [elem for elem in l if elem == pivot] + tail
28
alisianoi

Il y a déjà beaucoup de réponses à cela, mais je pense que cette approche est la mise en œuvre la plus propre:

def quicksort(arr):
    """ Quicksort a list

    :type arr: list
    :param arr: List to sort
    :returns: list -- Sorted list
    """
    if not arr:
        return []

    pivots = [x for x in arr if x == arr[0]]
    lesser = quicksort([x for x in arr if x < arr[0]])
    greater = quicksort([x for x in arr if x > arr[0]])

    return lesser + pivots + greater

Vous pouvez bien sûr ignorer tout stocker dans les variables et les renvoyer immédiatement comme ceci:

def quicksort(arr):
    """ Quicksort a list

    :type arr: list
    :param arr: List to sort
    :returns: list -- Sorted list
    """
    if not arr:
        return []

    return quicksort([x for x in arr if x < arr[0]]) \
        + [x for x in arr if x == arr[0]] \
        + quicksort([x for x in arr if x > arr[0]])
22
Sebastian Dahlgren

Quicksort avec Python

Dans la vie réelle, nous devrions toujours utiliser le type intégré fourni par Python. Cependant, comprendre l'algorithme quicksort est instructif. 

Mon objectif ici est de décomposer le sujet de sorte qu'il soit facilement compris et reproductible par le lecteur sans qu'il soit nécessaire de revenir à des documents de référence.

L'algorithme quicksort est essentiellement le suivant:

  1. Sélectionnez un point de données pivot.
  2. Déplacez tous les points de données inférieurs au pivot en dessous du pivot - déplacez ceux qui sont supérieurs ou égaux au pivot au dessus.
  3. Appliquer l'algorithme aux zones situées au-dessus et au-dessous du pivot

Si les données sont distribuées de manière aléatoire, la sélection du premier point de données en tant que pivot équivaut à une sélection aléatoire.

Exemple lisible:

Tout d'abord, examinons un exemple lisible qui utilise des commentaires et des noms de variables pour pointer vers des valeurs intermédiaires:

def quicksort(xs):
    """Given indexable and slicable iterable, return a sorted list"""
    if xs: # if given list (or Tuple) with one ordered item or more: 
        pivot = xs[0]
        # below will be less than:
        below = [i for i in xs[1:] if i < pivot] 
        # above will be greater than or equal to:
        above = [i for i in xs[1:] if i >= pivot]
        return quicksort(below) + [pivot] + quicksort(above)
    else: 
        return xs # empty list

Pour reformuler l'algorithme et le code démontrés ici - nous déplaçons les valeurs au-dessus du pivot vers la droite et les valeurs sous le pivot vers la gauche, puis passons ces partitions à la même fonction pour qu'elles soient encore triées.

Golfé:

Cela peut être joué à 88 personnages:

q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])

Pour voir comment nous en arrivons là, prenons d’abord notre exemple lisible, supprimons les commentaires et les docstrings, et trouvons le pivot sur place:

def quicksort(xs):
    if xs: 
        below = [i for i in xs[1:] if i < xs[0]] 
        above = [i for i in xs[1:] if i >= xs[0]]
        return quicksort(below) + [xs[0]] + quicksort(above)
    else: 
        return xs

Maintenant, trouvez ci-dessous et ci-dessus, en place:

def quicksort(xs):
    if xs: 
        return (quicksort([i for i in xs[1:] if i < xs[0]] )
                + [xs[0]] 
                + quicksort([i for i in xs[1:] if i >= xs[0]]))
    else: 
        return xs

Maintenant, sachant que and renvoie l'élément précédent si false, sinon s'il vaut true, il évalue et renvoie l'élément suivant:

def quicksort(xs):
    return xs and (quicksort([i for i in xs[1:] if i < xs[0]] )
                   + [xs[0]] 
                   + quicksort([i for i in xs[1:] if i >= xs[0]]))

Puisque lambdas retourne une seule expression et que nous avons simplifié en une seule expression (même si cela devient de plus en plus illisible), nous pouvons maintenant utiliser un lambda:

quicksort = lambda xs: (quicksort([i for i in xs[1:] if i < xs[0]] )
                        + [xs[0]] 
                        + quicksort([i for i in xs[1:] if i >= xs[0]]))

Et pour résumer à notre exemple, réduisez les noms de fonction et de variable à une lettre et supprimez les espaces inutiles.

q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])

Notez que ce lambda, comme la plupart des codes de golf, est plutôt mauvais style.

Quicksort sur place, à l'aide du schéma de partitionnement Hoare

La mise en œuvre précédente crée beaucoup de listes supplémentaires inutiles. Si nous pouvons le faire sur place, nous éviterons de gaspiller de l'espace.

L’implémentation ci-dessous utilise le schéma de partitionnement de Hoare, sur lequel vous pouvez en savoir plus sur wikipedia (mais nous avons apparemment supprimé jusqu’à 4 calculs redondants par appel partition() en utilisant une sémantique de boucle while au lieu de do-while et en déplaçant la restriction pas à la fin de la boucle while externe.).

def quicksort(a_list):
    """Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort"""
    def _quicksort(a_list, low, high):
        # must run partition on sections with 2 elements or more
        if low < high: 
            p = partition(a_list, low, high)
            _quicksort(a_list, low, p)
            _quicksort(a_list, p+1, high)
    def partition(a_list, low, high):
        pivot = a_list[low]
        while True:
            while a_list[low] < pivot:
                low += 1
            while a_list[high] > pivot:
                high -= 1
            if low >= high:
                return high
            a_list[low], a_list[high] = a_list[high], a_list[low]
            low += 1
            high -= 1
    _quicksort(a_list, 0, len(a_list)-1)
    return a_list

Pas sûr si je l'ai testé suffisamment à fond:

def main():
    assert quicksort([1]) == [1]
    assert quicksort([1,2]) == [1,2]
    assert quicksort([1,2,3]) == [1,2,3]
    assert quicksort([1,2,3,4]) == [1,2,3,4]
    assert quicksort([2,1,3,4]) == [1,2,3,4]
    assert quicksort([1,3,2,4]) == [1,2,3,4]
    assert quicksort([1,2,4,3]) == [1,2,3,4]
    assert quicksort([2,1,1,1]) == [1,1,1,2]
    assert quicksort([1,2,1,1]) == [1,1,1,2]
    assert quicksort([1,1,2,1]) == [1,1,1,2]
    assert quicksort([1,1,1,2]) == [1,1,1,2]

Conclusion

Cet algorithme est fréquemment enseigné dans les cours d'informatique et sollicité lors d'entretiens d'embauche. Cela nous aide à penser à la récursivité et à la division. 

Quicksort n’est pas très pratique en Python car notre algorithme incorporé timsort est assez efficace et nous avons des limites de récursivité. Nous nous attendons probablement à trier les listes sur place avec list.sort ou à créer de nouvelles listes triées avec sorted -, qui prennent tous deux un argument key et reverse

16
Aaron Hall

approche fonctionnelle:

def qsort(list):
    if len(list) < 2:
        return list

    pivot = list.pop()
    left = filter(lambda x: x <= pivot, list)
    right = filter(lambda x: x > pivot, list)

    return qsort(left) + [pivot] + qsort(right)
6
akarca

approche de programmation fonctionnelle

smaller = lambda xs, y: filter(lambda x: x <= y, xs)
larger = lambda xs, y: filter(lambda x: x > y, xs)
qsort = lambda xs: qsort(smaller(xs[1:],xs[0])) + [xs[0]] + qsort(larger(xs[1:],xs[0])) if xs != [] else []

print qsort([3,1,4,2,5]) == [1,2,3,4,5]

Je pense que les deux réponses ici fonctionnent bien pour la liste fournie (qui répondent à la question initiale), mais se briseraient si un tableau contenant des valeurs non uniques était passé. Donc, pour être complet, je voudrais simplement signaler la petite erreur dans chacune et expliquer comment les réparer.

Par exemple, essayer de trier le tableau suivant [12,4,5,6,7,3,1,15,1] (notez que 1 apparaît deux fois) avec Brionius algorithm .. à un moment donné se retrouvera avec le tableau less est vide et le tableau equal avec une paire de valeurs (1,1) qui ne peuvent pas être séparées lors de la prochaine itération et le len ()> 1 ... d'où vous allez vous retrouver avec une boucle infinie

Vous pouvez résoudre ce problème en retournant un tableau si moins _ est vide ou mieux en pas en appelant sort dans votre tableau égal, comme dans zangw answer 

def sort(array=[12,4,5,6,7,3,1,15]):
    less = []
    equal = []
    greater = []

    if len(array) > 1:
        pivot = array[0]
        for x in array:
            if x < pivot:
                less.append(x)
            if x == pivot:
                equal.append(x)
            if x > pivot:
                greater.append(x)

        # Don't forget to return something!
        return sort(less)+ equal +sort(greater)  # Just use the + operator to join lists
    # Note that you want equal ^^^^^ not pivot
    else:  # You need to hande the part at the end of the recursion - when you only have one element in your array, just return the array.
        return array

La solution la plus sophistiquée se casse également, mais pour une autre cause, il manque la clause return dans la ligne de récursivité, ce qui entraînera à un moment donné le renvoi de None et la tentative de l'ajouter à une liste ....

Pour résoudre ce problème, ajoutez simplement un retour à cette ligne.

def qsort(arr): 
   if len(arr) <= 1:
      return arr
   else:
      return qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
3
FedeN

Cloison - Découpez un tableau en faisant pivoter les éléments les plus petits vers la gauche et les plus grands vers la droite ou inversement. Un pivot peut être un élément aléatoire d'un tableau. Pour faire cet algorithme, nous avons besoin de savoir quel est le début et la fin d'un tableau et où se trouve un pivot. Puis définissez deux pointeurs auxiliaires L, R.

Nous avons donc un utilisateur de tableau [..., begin, ..., end, ...]

La position de départ des pointeurs L et R
[..., commence, ensuite, ..., fin, ...]
R L

tandis que L <fin
1. Si un utilisateur [pivot]> utilisateur [L] déplace alors R de un à l'autre et remplace l'utilisateur [R] par l'utilisateur [L]
2. déplacer L par un

Après échange de l'utilisateur [R] avec l'utilisateur [pivot]

Tri rapide - Utilisez l'algorithme de partition jusqu'à ce que chaque partie suivante de la division par un pivot ait un index de début supérieur ou égal à un index de fin.

def qsort(user, begin, end):

    if begin >= end:
        return

    # partition
    # pivot = begin
    L = begin+1
    R = begin
    while L < end:
        if user[begin] > user[L]:
            R+=1
            user[R], user[L] = user[L], user[R]
        L+= 1
    user[R], user[begin] = user[begin], user[R]

    qsort(user, 0, R)
    qsort(user, R+1, end)

tests = [
    {'sample':[1],'answer':[1]},
    {'sample':[3,9],'answer':[3,9]},
    {'sample':[1,8,1],'answer':[1,1,8]},
    {'sample':[7,5,5,1],'answer':[1,5,5,7]},
    {'sample':[4,10,5,9,3],'answer':[3,4,5,9,10]},
    {'sample':[6,6,3,8,7,7],'answer':[3,6,6,7,7,8]},
    {'sample':[3,6,7,2,4,5,4],'answer':[2,3,4,4,5,6,7]},
    {'sample':[1,5,6,1,9,0,7,4],'answer':[0,1,1,4,5,6,7,9]},
    {'sample':[0,9,5,2,2,5,8,3,8],'answer':[0,2,2,3,5,5,8,8,9]},
    {'sample':[2,5,3,3,2,0,9,0,0,7],'answer':[0,0,0,2,2,3,3,5,7,9]}
]

for test in tests:

    sample = test['sample'][:]
    answer = test['answer']

    qsort(sample,0,len(sample))

    print(sample == answer)
2
Grzegorz Eleryk
def Partition(A,p,q):
    i=p
    x=A[i]
    for j in range(p+1,q+1):
        if A[j]<=x:
            i=i+1
            tmp=A[j]
            A[j]=A[i]
            A[i]=tmp
    l=A[p]
    A[p]=A[i]
    A[i]=l
    return i

def quickSort(A,p,q):
    if p<q:
        r=Partition(A,p,q)
        quickSort(A,p,r-1)
        quickSort(A,r+1,q)
    return A
1
Amy

L'algorithme contient deux limites, l'une ayant des éléments inférieurs au pivot (suivi de l'indice "j") et l'autre aux éléments supérieurs au pivot (suivie de l'indice "i"). 

A chaque itération, un nouvel élément est traité en incrémentant j.

Invariant: - 

  1. tous les éléments entre pivot et i sont inférieurs au pivot, et 
  2. tous les éléments entre i et j sont supérieurs au pivot.

Si l'invariant est violé, les ième et jième éléments sont échangés et i .__ est incrémenté. 

Une fois que tous les éléments ont été traités et que tout après le pivot A été partitionné, l'élément pivot est échangé avec le dernier élément Plus petit que celui-ci.

L'élément pivot sera maintenant à la bonne place dans la séquence. Les éléments Avant seront inférieurs à lui et ceux qui suivront seront plus grands, et ils ne seront pas triés.

def quicksort(sequence, low, high):
    if low < high:    
        pivot = partition(sequence, low, high)
        quicksort(sequence, low, pivot - 1)
        quicksort(sequence, pivot + 1, high)

def partition(sequence, low, high):
    pivot = sequence[low]
    i = low + 1
    for j in range(low + 1, high + 1):
        if sequence[j] < pivot:
            sequence[j], sequence[i] = sequence[i], sequence[j]
            i += 1
    sequence[i-1], sequence[low] = sequence[low], sequence[i-1]
    return i - 1

def main(sequence):
    quicksort(sequence, 0, len(sequence) - 1)
    return sequence

if __== '__main__':
    sequence = [-2, 0, 32, 1, 56, 99, -4]
    print(main(sequence))

Sélection d'un pivot

Un "bon" pivot donnera deux sous-séquences de taille à peu près identique De manière déterministe, un élément pivot peut être sélectionné d’une manière naïve ou en calculant la médiane de la séquence.

Une implémentation naïve de la sélection d'un pivot constituera le premier ou le dernier élément Dans le cas le plus défavorable, l'exécution sera alors lorsque la séquence En entrée est déjà triée ou triée en sens inverse, car l'une des sous-séquences Sera vide, ce qui entraînera la suppression d'un seul élément par appel récursif .

Une scission parfaitement équilibrée est obtenue lorsque le pivot est l’élément médian De la séquence. Il y a un nombre égal d'éléments plus grands que. Et moins que. Cette approche garantit un meilleur temps de fonctionnement global, mais prend beaucoup plus de temps.

Une manière non déterministe/aléatoire de sélectionner le pivot serait de choisir un élément uniformément aléatoire. Il s’agit d’une approche simple et légère qui minimisera le pire des scénarios et conduira à une division approximativement équilibrée. Cela fournira également un équilibre entre l'approche naïve et l'approche médiane du choix du pivot.

1
SR8H

L'algorithme comporte 4 étapes simples:

  1. Divisez le tableau en 3 parties différentes: gauche, pivot et droite, où pivot n'aura qu'un seul élément. Choisissons cet élément pivot comme premier élément du tableau
  2. Ajoutez des éléments à la partie respective en les comparant à l’élément pivot. (explication dans les commentaires)
  3. Recurse cet algorithme jusqu'à ce que tous les éléments du tableau aient été triés
  4. Enfin, rejoignez les parties gauche + pivot + droite

Code pour l'algorithme en python:

def my_sort(A):

      p=A[0]                                       #determine pivot element. 
      left=[]                                      #create left array
      right=[]                                     #create right array
      for i in range(1,len(A)):
        #if cur elem is less than pivot, add elem in left array
        if A[i]< p:
          left.append(A[i])         
          #the recurssion will occur only if the left array is atleast half the size of original array
          if len(left)>1 and len(left)>=len(A)//2:          
              left=my_sort(left)                            #recursive call
        Elif A[i]>p: 
          right.append(A[i])                                #if elem is greater than pivot, append it to right array
          if len(right)>1 and len(right)>=len(A)//2:        # recurssion will occur only if length of right array is atleast the size of original array
              right=my_sort(right)
     A=left+[p]+right                                        #append all three part of the array into one and return it
     return A

my_sort([12,4,5,6,7,3,1,15])

Continuez avec cet algorithme récursivement avec les parties gauche et droite.

1
Mamta Kanvinde

Pour la version Python 3.x : un style fonctionnel utilisant le module operator, principalement pour améliorer la lisibilité. 

from operator import ge as greater, lt as lesser

def qsort(L): 
    if len(L) <= 1: return L
    pivot   = L[0]
    sublist = lambda op: [*filter(lambda num: op(num, pivot), L[1:])]

    return qsort(sublist(lesser))+ [pivot] + qsort(sublist(greater))

et est testé comme 

print (qsort([3,1,4,2,5]) == [1,2,3,4,5])
1
lifebalance

Une autre implémentation de tri rapide:

# A = Array 
# s = start index
# e = end index
# p = pivot index
# g = greater than pivot boundary index

def swap(A,i1,i2):
  A[i1], A[i2] = A[i2], A[i1]

def partition(A,g,p):
    # O(n) - just one for loop that visits each element once
    for j in range(g,p):
      if A[j] <= A[p]:
        swap(A,j,g)
        g += 1

    swap(A,p,g)
    return g

def _quicksort(A,s,e):
    # Base case - we are sorting an array of size 1
    if s >= e:
      return

    # Partition current array
    p = partition(A,s,e)
    _quicksort(A,s,p-1) # Left side of pivot
    _quicksort(A,p+1,e) # Right side of pivot

# Wrapper function for the recursive one
def quicksort(A):
    _quicksort(A,0,len(A)-1)

A = [3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,-1]

print(A)
quicksort(A)
print(A)
1
Gillespie

Implémentation facile des algorithmes de grokking

def quicksort(arr):
    if len(arr) < 2:
        return arr #base case
    else:
        pivot = arr[0]
        less = [i for i in arr[1:] if i <= pivot] 
        more = [i for i in arr[1:] if i > pivot]
        return quicksort(less) + [pivot] + quicksort(more)
1
Alice

Ou si vous préférez une ligne qui illustre également l'équivalent Python des varags C/C++, des expressions lambda et des expressions if:

qsort = lambda x=None, *xs: [] if x is None else qsort(*[a for a in xs if a<x]) + [x] + qsort(*[a for a in xs if a>=x])
1
Bruce Lucas

Je sais que beaucoup de gens ont répondu correctement à cette question et j'ai bien aimé les lire. Ma réponse est presque identique à celle de zangw mais je pense que les contributeurs précédents n’ont pas bien expliqué visuellement le fonctionnement de la situation. solution simple pour la mise en œuvre quicksort.

Comment ça marche ?

  1. Nous sélectionnons essentiellement le premier élément en tant que pivot de notre liste, puis nous créons deux sous-listes.
  2. Notre première sous-liste contient les éléments qui sont moins que pivot 
  3. Notre deuxième sous-liste contient nos articles qui sont grands ou égaux à pivot
  4. Nous trions ensuite rapidement chacun de ceux-ci et nous les combinons le premier groupe + pivot + le deuxième groupe pour obtenir le résultat final.

Voici un exemple avec visuel pour aller avec elle ... (Pivot) 9,11,2,0

moyenne: n log de n 

pire cas: n ^ 2 

 enter image description here

Le code:

def quicksort(data):
if (len(data) < 2):
    return data
else:
    pivot = data[0]  # pivot
    #starting from element 1 to the end
    rest = data[1:]
    low = [each for each in rest if each < pivot]
    high = [each for each in rest if each >= pivot]
    return quicksort(low) + [pivot] + quicksort(high)

items = [9,11,2,0] print (tri rapide (items))

1
grepit

Ceci est une version du tri rapide utilisant le schéma de partition Hoare et avec moins de swaps et de variables locales

def quicksort(array):
    qsort(array, 0, len(array)-1)

def qsort(A, lo, hi):
    if lo < hi:
        p = partition(A, lo, hi)
        qsort(A, lo, p)
        qsort(A, p + 1, hi)

def partition(A, lo, hi):
    pivot = A[lo]
    i, j = lo-1, hi+1
    while True:
      i += 1
      j -= 1
      while(A[i] < pivot): i+= 1
      while(A[j] > pivot ): j-= 1

      if i >= j: 
          return j

      A[i], A[j] = A[j], A[i]


test = [21, 4, 1, 3, 9, 20, 25, 6, 21, 14]
print quicksort(test)
1
Madu Alikor
def quick_sort(array):
    return quick_sort([x for x in array[1:] if x < array[0]]) + [array[0]] \
        + quick_sort([x for x in array[1:] if x >= array[0]]) if array else []
1
dapangmao
def quick_sort(self, nums):
    def helper(arr):
        if len(arr) <= 1: return arr
        #lwall is the index of the first element euqal to pivot
        #rwall is the index of the first element greater than pivot
        #so arr[lwall:rwall] is exactly the middle part equal to pivot after one round
        lwall, rwall, pivot = 0, 0, 0
        #choose rightmost as pivot
        pivot = arr[-1]
        for i, e in enumerate(arr):
            if e < pivot:
                #when element is less than pivot, shift the whole middle part to the right by 1
                arr[i], arr[lwall] = arr[lwall], arr[i]
                lwall += 1
                arr[i], arr[rwall] = arr[rwall], arr[i]
                rwall += 1
            Elif e == pivot:
                #when element equals to pivot, middle part should increase by 1
                arr[i], arr[rwall] = arr[rwall], arr[i]
                rwall += 1
            Elif e > pivot: continue
        return helper(arr[:lwall]) + arr[lwall:rwall] + helper(arr[rwall:])
    return helper(nums)
1
MoeChen

Une "vraie" implémentation sur place [Algorithmes 8.9, 8.11 du Livre de conception et applications d'algorithmes de Michael T. Goodrich et Roberto Tamassia]:

from random import randint

def partition (A, a, b):
    p = randint(a,b)
    # or mid point
    # p = (a + b) / 2

    piv = A[p]

    # swap the pivot with the end of the array
    A[p] = A[b]
    A[b] = piv

    i = a     # left index (right movement ->)
    j = b - 1 # right index (left movement <-)

    while i <= j:
        # move right if smaller/eq than/to piv
        while A[i] <= piv and i <= j:
            i += 1
        # move left if greater/eq than/to piv
        while A[j] >= piv and j >= i:
            j -= 1

        # indices stopped moving:
        if i < j:
            # swap
            t = A[i]
            A[i] = A[j]
            A[j] = t
    # place pivot back in the right place
    # all values < pivot are to its left and 
    # all values > pivot are to its right
    A[b] = A[i]
    A[i] = piv

    return i

def IpQuickSort (A, a, b):

    while a < b:
        p = partition(A, a, b) # p is pivot's location

        #sort the smaller partition
        if p - a < b - p:
            IpQuickSort(A,a,p-1)
            a = p + 1 # partition less than p is sorted
        else:
            IpQuickSort(A,p+1,b)
            b = p - 1 # partition greater than p is sorted


def main():
    A =  [12,3,5,4,7,3,1,3]
    print A
    IpQuickSort(A,0,len(A)-1)
    print A

if __== "__main__": main()
1
anask

Voici une implémentation facile: -

def quicksort(array):
            if len(array) < 2:
                  return array
            else:
                  pivot= array[0]
                  less = [i for i in array[1:] if i <= pivot]

                  greater = [i for i in array[1:] if i > pivot]

                  return quicksort(less) + [pivot] + quicksort(greater)

print(quicksort([10, 5, 2, 3]))
0
abhishek4996

Cet algorithme n'utilise pas de fonctions récursives.

Soit N toute liste de nombres avec len(N) > 0. Définissez K = [N] et exécutez le programme suivant.

Remarque: il s’agit d’un algorithme de tri stable .

def BinaryRip2Singletons(K, S):
    K_L = []
    K_P = [ [K[0][0]] ] 
    K_R = []
    for i in range(1, len(K[0])):
        if   K[0][i] < K[0][0]:
            K_L.append(K[0][i])
        Elif K[0][i] > K[0][0]:
            K_R.append(K[0][i])
        else:
            K_P.append( [K[0][i]] )
    K_new = [K_L]*bool(len(K_L)) + K_P + [K_R]*bool(len(K_R)) + K[1:]
    while len(K_new) > 0:
        if len(K_new[0]) == 1:
            S.append(K_new[0][0])
            K_new = K_new[1:]
        else: 
            break
    return K_new, S

N = [16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]
K = [ N ]
S = []

print('K =', K, 'S =', S)
while len(K) > 0:
    K, S = BinaryRip2Singletons(K, S)
    print('K =', K, 'S =', S)

SORTIE DU PROGRAMME:

K = [[16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]] S = []
K = [[11, 15, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1], [16], [16], [19]] S = []
K = [[10, 4, 10, 5, 2, 3, 4, 7, 1], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[4, 5, 2, 3, 4, 7, 1], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[2, 3, 1], [4], [4], [5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4]
K = [[15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11]
K = [[12, 14], [15], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11]
K = [] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11, 12, 14, 15, 16, 16, 19]
0
CopyPasteIt

Exemple complet avec des variables imprimées à l'étape de la partition:

def partition(data, p, right):
    print("\n==> Enter partition: p={}, right={}".format(p, right))
    pivot = data[right]
    print("pivot = data[{}] = {}".format(right, pivot))

    i = p - 1  # this is a dangerous line

    for j in range(p, right):
        print("j: {}".format(j))
        if data[j] <= pivot:
            i = i + 1
            print("new i: {}".format(i))
            print("swap: {} <-> {}".format(data[i], data[j]))
            data[i], data[j] = data[j], data[i]

    print("swap2: {} <-> {}".format(data[i + 1], data[right]))
    data[i + 1], data[right] = data[right], data[i + 1]
    return i + 1


def quick_sort(data, left, right):
    if left < right:
        pivot = partition(data, left, right)
        quick_sort(data, left, pivot - 1)
        quick_sort(data, pivot + 1, right)

data = [2, 8, 7, 1, 3, 5, 6, 4]

print("Input array: {}".format(data))
quick_sort(data, 0, len(data) - 1)
print("Output array: {}".format(data))
0
Andrei Sura
def quick_sort(l):
    if len(l) == 0:
        return l
    pivot = l[0]
    pivots = [x for x in l if x == pivot]
    smaller = quick_sort([x for x in l if x < pivot])
    larger = quick_sort([x for x in l if x > pivot])
    return smaller + pivots + larger
0
feroz
def is_sorted(arr): #check if array is sorted
    for i in range(len(arr) - 2):
        if arr[i] > arr[i + 1]:
            return False
    return True

def qsort_in_place(arr, left, right): #arr - given array, #left - first element index, #right - last element index
    if right - left < 1: #if we have empty or one element array - nothing to do
        return
    else:
        left_point = left #set left pointer that points on element that is candidate to swap with element under right pointer or pivot element
        right_point = right - 1 #set right pointer that is candidate to swap with element under left pointer

        while left_point <= right_point: #while we have not checked all elements in the given array
            swap_left = arr[left_point] >= arr[right] #True if we have to move that element after pivot
            swap_right = arr[right_point] < arr[right] #True if we have to move that element before pivot

            if swap_left and swap_right: #if both True we can swap elements under left and right pointers
                arr[right_point], arr[left_point] = arr[left_point], arr[right_point]
                left_point += 1
                right_point -= 1
            else: #if only one True we don`t have place for to swap it
                if not swap_left: #if we dont need to swap it we move to next element
                    left_point += 1
                if not swap_right: #if we dont need to swap it we move to prev element
                    right_point -= 1

        arr[left_point], arr[right] = arr[right], arr[left_point] #swap left element with pivot

        qsort_in_place(arr, left, left_point - 1) #execute qsort for left part of array (elements less than pivot)
        qsort_in_place(arr, left_point + 1, right) #execute qsort for right part of array (elements most than pivot)

def main():
    import random
    arr = random.sample(range(1, 4000), 10) #generate random array
    print(arr)
    print(is_sorted(arr))
    qsort_in_place(arr, 0, len(arr) - 1)
    print(arr)
    print(is_sorted(arr))

if __== "__main__":
    main()
0
Igor Mansurov
  1. Tout d'abord, nous déclarons la première valeur du tableau comme étant la valeur Pivot_value et définissons également les marques gauche et droite.
  2. Nous créons la première boucle while, cette boucle while est là pour indiquer à Le processus de partition à réexécuter s'il ne remplit pas la condition Nécessaire
  3. alors nous appliquons le processus de partition
  4. une fois que les deux processus de partition ont été exécutés, nous vérifions si satisfait la condition appropriée. Si c'est le cas, nous le marquons comme terminé, Sinon, nous basculons entre les valeurs gauche et droite et l'appliquons à nouveau
  5. Une fois cela fait, changez les valeurs left et right et renvoyez le Split_point

Je joins le code ci-dessous! Ce tri rapide est un excellent outil d’apprentissage en raison de la position Emplacement de la valeur de pivot. Comme il se trouve dans un lieu constant, vous pouvez le parcourir plusieurs fois et comprendre comment cela fonctionne. En pratique, il est préférable de randomiser le pivot pour éviter l'exécution de O (N ^ 2).

def quicksort10(alist):
    quicksort_helper10(alist, 0, len(alist)-1)

def quicksort_helper10(alist, first, last):
    """  """
    if first < last:
        split_point = partition10(alist, first, last)
        quicksort_helper10(alist, first, split_point - 1)
        quicksort_helper10(alist, split_point + 1, last)

def partition10(alist, first, last):
    done = False
    pivot_value = alist[first]
    leftmark = first + 1
    rightmark = last
    while not done:
        while leftmark <= rightmark and alist[leftmark] <= pivot_value:
            leftmark = leftmark + 1
        while leftmark <= rightmark and alist[rightmark] >= pivot_value:
            rightmark = rightmark - 1

        if leftmark > rightmark:
            done = True
        else:
            temp = alist[leftmark]
            alist[leftmark] = alist[rightmark]
            alist[rightmark] = temp
    temp = alist[first]
    alist[first] = alist[rightmark]
    alist[rightmark] = temp
    return rightmark
0
DanHabib
# 编程珠玑实现
# 双向排序: 提高非随机输入的性能
# 不需要额外的空间,在待排序数组本身内部进行排序
# 基准值通过random随机选取
# 入参: 待排序数组, 数组开始索引 0, 数组结束索引 len(array)-1
import random

def swap(arr, l, u):
    arr[l],arr[u] = arr[u],arr[l]
    return arr

def QuickSort_Perl(arr, l, u):
    # 小数组排序i可以用插入或选择排序 
    # if u-l < 50 : return arr
    # 基线条件: low index = upper index; 也就是只有一个值的区间
    if l >= u:
        return arr
    # 随机选取基准值, 并将基准值替换到数组第一个元素        
    swap(arr, l, int(random.uniform(l, u)))
    temp = arr[l]
    # 缓存边界值, 从上下边界同时排序
    i, j = l, u
    while True:
        # 第一个元素是基准值,所以要跳过
        i+=1
        # 在小区间中, 进行排序
        # 从下边界开始寻找大于基准值的索引
        while i <= u and arr[i] <= temp:
            i += 1
        # 从上边界开始寻找小于基准值的索引
        # 因为j肯定大于i, 所以索引值肯定在小区间中
        while arr[j] > temp:
            j -= 1
        # 如果小索引仍小于大索引, 调换二者位置
        if i >= j:
            break
        arr[i], arr[j] = arr[j], arr[i]
    # 将基准值的索引从下边界调换到索引分割点
    swap(arr, l, j)
    QuickSort_Perl(arr, l, j-1)
    QuickSort_Perl(arr, j+1, u)
    return arr

print('QuickSort_Perl([-22, -21, 0, 1, 2, 22])',
    QuickSort_Perl([-22, -21, 0, 1, 2, 22], 0, 5))
0
Song