参考:https://blog.csdn.net/panglinzhuo/article/details/79795172
BFPRT算法总体思想:
1.将所有n个数据分为n/5(的向下取整)组,每一组有5个元素, 用归并/快速排序求出每一组的中位数(时间复杂度为*5log5 * n/5, 即O(n)),并递归的调用BFPRT算法求出这n/5个中位数的中位数(T(n/5)), 也就是第n/10大的元素,记为m,找到m在原数组中的位置index(O(n))。
2.将原数组以m为分界点,将大于m的num2个元素放在m右边,小于等于m的num1个元素放在m左边,此时m的新位置为index_new
3.把k与num1比较,如果k=num1+1,则说明分界点m就是第k大的元素,如果k<=num1,说明第k大的元素在m左边,接下来去m左边寻找;否则在m右边,应去m右边寻找。这样就将原问题转化为规模更小的问题了。
代码2完全遵循思想,代码1练习
def median(arr): #返回划分值,即中位数数组的中位数
if len(arr)<5:
arr.sort()
return arr[len(arr)//2]
else:
splitnum=len(arr)//5
mid=[]
for i in range(splitnum):
s=sorted(arr[i*5:(i+1)*5])
mid.append(s[2])
mid.sort()
return mid[len(mid)//2]
def parttion(arr,value): #快排,小于大于等于分开
xiao=0-1 #小于区域
da=len(arr) #大于区域
i=0
while i<da: #条件容易写错
if arr[i]<value:
arr[i],arr[xiao+1]=arr[xiao+1],arr[i]
xiao+=1
i+=1
elif arr[i]>value:
arr[i],arr[da-1]=arr[da-1],arr[i]
da-=1
else:
i+=1
return xiao,da,arr
def bfprt(arr,k): #递归调用bfprt
pivot=median(arr)
xiao, da, arr=parttion(arr,pivot)
if da+1>k>xiao+1: #注意边界调整
return pivot
elif k<=xiao+1:
return bfprt(arr[0:xiao+1],k)
elif k>=da+1:
return bfprt(arr[da:len(arr)],k-da)
arr=[1,3,4,1,7,54,9,5,6,12,11,13,10]
print(bfprt(arr,3))
代码2
def parttion(arr,value): #快排,小于大于等于分开
xiao=0-1 #小于区域
da=len(arr) #大于区域
i=0
while i<da: #条件容易写错
if arr[i]<value:
arr[i],arr[xiao+1]=arr[xiao+1],arr[i]
xiao+=1
i+=1
elif arr[i]>value:
arr[i],arr[da-1]=arr[da-1],arr[i]
da-=1
else:
i+=1
return xiao,da,arr
def bfprt(arr,k):
if len(arr)<5: #小于5时,直接返回第k个
arr.sort()
return arr[k-1]
splitnum = len(arr) // 5
mid = [] #中位数数组
for i in range(splitnum):
s = sorted(arr[i * 5:(i + 1) * 5])
mid.append(s[2])
pivot=bfprt(mid,len(arr)//10) #递归,求中位数数组的中位数
xiao, da, arr=parttion(arr,pivot)
if da+1>k>xiao+1: #注意边界调整
return pivot
elif k<=xiao+1:
return bfprt(arr[0:xiao+1],k)
elif k>=da+1:
return bfprt(arr[da:len(arr)],k-da)
arr=[1,3,4,1,7,54,9,5,6,12,11,13,10]
print(sorted(arr))
print(bfprt(arr,6))