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)
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
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)
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
choisissez le premier élément du tableau _arr[0]
_ comme pivot
_[arr[0]]
_
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]])
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]])
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
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]])
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:
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.
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.
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.
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]
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
.
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)
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]])
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)
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
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: -
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))
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.
L'algorithme comporte 4 étapes simples:
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.
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])
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)
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)
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])
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 ?
Voici un exemple avec visuel pour aller avec elle ... (Pivot) 9,11,2,0
moyenne: n log de n
pire cas: n ^ 2
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))
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)
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 []
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)
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()
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]))
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]
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))
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
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()
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
# 编程珠玑实现
# 双向排序: 提高非随机输入的性能
# 不需要额外的空间,在待排序数组本身内部进行排序
# 基准值通过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))