快速排序算法,总体来说就是选一个基准值,把小于基准值的分一拨,把大于基准值的分到另一拨,然后递归。
有区别的是,分区算法有差异,最直接的是,选个基准值,定义两个列表(小值分区less和大值分区great),然后挨个比较,小的追加到less,大的追加到great
再有就是,选个基准值,先从右边开始比,比基准值大的不管,比基准值小就和基准值换位置,换一次后,就去和左边比,比基准值小的不管,比基准值大的又去换位置,略有些绕。
最后,还可以不递归,通过把分区节点保存在栈里来实现。
1 # -*- coding: utf-8 -*- 2 3 import numpy as np 4 #1)依次对比arr[0]和其他元素,比arr[0]小的话,就原地删除,然后插入到arr[0]前面,基准值后移。大于等于,则不处理。然后递归 5 #原地排序 6 def quick_sort1(arr,left,right): 7 8 if left>=right: 9 return 10 flag=left 11 for i in range(left+1,right+1): 12 if arr[flag]>arr[i]: 13 temp=arr[i] 14 del arr[i] 15 arr.insert(flag,temp) 16 flag+=1 17 quick_sort1(arr,left,flag-1) 18 quick_sort1(arr,flag+1,right) 19 #2)基准值arr[0],对比所有元素,比它小就追加到less后面,比它大就追加到great后面,相等就追加到pivot后面,然后递归 20 #返回排序后的列表 21 def quick_sort2(arr): 22 less=[] 23 great=[] 24 pivot=[] 25 if len(arr)<=1: 26 return arr 27 else: 28 p=arr[0] 29 for i in arr: 30 if i<p: 31 less.append(i) 32 elif i>p: 33 great.append(i) 34 else: 35 pivot.append(i) 36 less=quick_sort2(less) 37 great=quick_sort2(great) 38 return less+pivot+great 39 #2-2)基本思想同上,代码更简化 40 def quick_sort22(arr): 41 if len(arr)<=1: 42 return arr 43 else: 44 return quick_sort22([i for i in arr[1:] if i<arr[0]])+[arr[0]]+quick_sort22([i for i in arr[1:] if i>=arr[0]]) 46 #2-3)思路同上,更简化的版本 47 quick_sort23=lambda xs:((len(xs)<=1 and [xs]) or [quick_sort23([x for x in xs[1:] if x<xs[0]])+[xs[0]]+quick_sort23([x for x in xs[1:] if x>=xs[0]])])[0] 49 quick_sort24=lambda arr:arr if len(arr)<=1 else quick_sort24([x for x in arr[1:] if x<arr[0]])+[arr[0]]+quick_sort24([x for x in arr[1:] if x>=arr[0]])
#lambda 参数:取值1,如果满足条件1,否则,取值2 51 52 53 #3)定义两个函数:分区和排序。分区是要把列表元素移动位置,直到基准值arr[0]移到中间(左边都比它小,右边都比它大)。排序则调用分区并递归 54 #原地排序 55 def partition(arr,i,j): 56 p=arr[i] 57 while i!=j: 58 while i<j and p<=arr[j]:#此处添加=,解决了之前遇到的序列中有重复值时死循环的问题 59 j-=1 60 arr[i]=arr[j] 61 while i<j and p>arr[i]: 62 i+=1 63 arr[j]=arr[i] 64 arr[i]=p 65 return i 66 def quick_sort3(arr,i,j): 67 if i<j: 68 mid=partition(arr,i,j) 69 quick_sort3(arr,i,mid-1) 70 quick_sort3(arr,mid+1,j) 71 #3-2)上述思路的变体,分区函数变动,每次都比右边是否比基准值大,大的话,j前移,否则,把arr[j]给到arr[i],然后i后移,arr[i]再给到arr[j],继续上述循环 72 def partition2(arr,i,j): 73 p=arr[i] 74 while i!=j: 75 while i<j and p<=arr[j]: 76 j-=1 77 78 while i<j and p>arr[j]: 79 arr[i]=arr[j] 80 i+=1 81 arr[j]=arr[i] 82 arr[i]=p 83 return i 84 def quick_sort32(arr,i,j): 85 if i<j: 86 mid=partition2(arr,i,j) 87 quick_sort32(arr,i,mid-1) 88 quick_sort32(arr,mid+1,j) 89 #3-3)分区函数变动,基准值为最后一个值,依次比较,如果比基准值小,就换到前面去,最后再把基准值换到中间。 90 def partition3(arr,i,j): 91 p=arr[j] 92 x=i-1 93 for y in range(i,j): 94 if arr[y]<=p: 95 x+=1 96 arr[x],arr[y]=arr[y],arr[x] 97 arr[x+1],arr[j]=arr[j],arr[x+1] 98 return x+1 99 def quick_sort33(arr,i,j): 100 if i<j: 101 mid=partition3(arr,i,j) 102 quick_sort33(arr,i,mid-1) 103 quick_sort33(arr,mid+1,j) 104 #4)非递归方式,使用栈,思路类似previous,只是把切分边界保存在栈(用list实现)里, 105 #当只剩一个元素时,跳出本次循环,进入下次循环,看下一个区间里元素值是否多于1个,直到栈空 106 def quick_sort4(arr,i,j): 107 if j<=i: 108 return 109 stack=[] 110 stack.extend([i,j]) 111 while stack: 112 left=stack.pop(0) 113 right=stack.pop(0) 114 if right<=left: 115 continue 116 x=left-1 117 p=arr[right] 118 for y in range(left,right):#此处循环不包括最后一个元素,循环结束后,最后一个元素换到中间 119 if arr[y]<=p: 120 x+=1 121 arr[x],arr[y]=arr[y],arr[x] 122 arr[x+1],arr[right]=arr[right],arr[x+1] 123 stack.extend([left,x,x+2,right]) 124 125 126 if __name__=="__main__": 127 s=np.random.randint(1,30,20).tolist() 128 print(s) 129 #print(quick_sort24(s)) 130 quick_sort4(s,0,len(s)-1) 131 print(s)