目录
1、二步掌握快速排序算法quicksort
昨天(注:实际上这是去年写的)准备开始看《编写高质量代码 改善python程序的91个建议》,才翻几页,就看到一个用递归实现的排序算法,顿时让我眼前一亮。
def quicksort(arr): #快速排序,目标是非递减序列
less=[];greater=[] #左子表、右子表
if(len(arr)<=1): #某个子表长度小于等于1时,即要么空,要么一个数据元素,返回子表本身
return arr
pivot=arr.pop() #定义pivot
for x in arr:
if(x<=pivot): #比pivot小的元素都加入左子表
less.append(x)
else:
greater.append(x) #比pivot大的元素都加入右子表
return quicksort(less)+[pivot]+quicksort(greater) #确定pivot位置并对两子表快速排序
1.1 步骤一:算法速览
阅读程序或读懂算法其实和学习语文、英语类似,先一条语句一条语句地理解,然后从整体上理解:每调用一次quicksort,只确定一个数据元素pivot的位置,并分割子表;对子表快速排序,直到子表为空或只有一个数据元素;每返回一次,即意味着一个子表排序的完成。
1.2 步骤二:算例分析
不妨以arr=[1,4,6,3,8]为例来分析其排序过程,看[1,3,4,6,8]是如何形成的。
根据步骤一的算法速览,可以对quicksort的调用与数据处理过程绘制出上图。
这里以第一次调用quicksort来稍作解释:要处理的子表是[1,4,6,3,8],确定了数字“8”所在位置,并分割成左子表[1,4,6,3]和右子表[](即空子表),对这两个子表进一步作快速排序处理。后面的图形示意依此类推。
分析上图可知(这里关注从下一层返回的子表中的数据,非每次调用quicksort时确定的数据,且已省略返回层节点):
第1次返回数据:1
第2次返回数据:4
第3次返回数据:(空)
第4次返回数据:4,6
第5次返回数据:1,3,4,6
第6次返回数据:(空)
第7次返回数据:1,3,4,6,8
除分析外,还可以直接跟踪数据处理过程:
def quicksort(arr):
global seq
less=[];greater=[]
if(len(arr)<=1):
seq+=1
print("第%d次返回数据:"%seq,end="")
if(len(arr)==0):print("(空)")
else: print(arr)
return arr
pivot=arr.pop()
for x in arr:
if(x<=pivot):
less.append(x)
else:
greater.append(x)
tr=quicksort(less)+[pivot]+quicksort(greater)
seq+=1
print("第%d次返回数据:"%seq,end="")
print(tr)
return tr
if(__name__=="__main__"):
seq=0
arr1=arr2=[1,4,6,3,8]
arr1=quicksort(arr1)
print(arr1)
2、quicksort算法的非递归实现:循环+队列
递归是一种特殊的子程序调用方式,即在子程序的实现代码中出现对自己的调用,可视为一种程序结构。
一句话概括,递归其实就是借助系统对子程序的调用机制来迭代处理问题规模不断缩小的数据集而解决问题。
递归是一种非常有意思的运行结构,和顺序结构、选择结构、循环结构一样,只是没有那么必须。
那么,如何把递归这种程序结构转化成非递归的程序结构呢?答案是:循环+队列。
def quicksort_nonR(L):
IO=[];IO.append([0,len(L)-1]) #IO为逻辑队列,每个元素为一个逻辑子表,初始时为整个L
while(len(IO)!=0):
l=[];g=[]
i,j=IO.pop(0) #出队,处理一个子表
if(i>=j):continue #无效子表,忽略
p=L[j] #p即quicksort中的pivot
for n in range(i,j):
if(L[n]<=p): #构造左子表
l.append(L[n])
else: #构造右子表
g.append(L[n])
L[i:j+1]=l+[p]+g #每次for循环将确定某个子表中数据p的位置
IO.append([i,i+len(l)-1]) #左子表入队
IO.append([i+len(l)+1,i+len(l)+len(g)]) #右子表入队
return L
系统的函数调用借助栈完成,因而可通过循环加与栈工作机制一定相似的队列来实现递归向非递归的转化。
if(__name__=="__main__"):
arr1=[1,4,6,3,8]
arr1=quicksort(arr1)
arr2=[1,4,6,3,8,0,1,-23]
arr2=quicksort_nonR(arr2)
print(arr1)
print(arr2)
递归转化成非递归的一般方法与原理,大家get到了吗?