分治法:BFPTR算法找第k小
生活随笔
收集整理的這篇文章主要介紹了
分治法:BFPTR算法找第k小
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
BFPTR算法
來自于Blum、Floyd、Pratt、Rivest、Tarjan這5個(gè)人,一起發(fā)布了一篇名為 “Time bounds for selection” 的論文,有興趣可以看一下:https://pan.baidu.com/s/1QEWjZBrjEJ7zTIrI99sFYA。
下面是一種實(shí)現(xiàn)方式,這種有一個(gè)問題,只是找到中位數(shù)了,標(biāo)號(hào)還要搜索然后此時(shí)的數(shù)組是有結(jié)構(gòu)規(guī)律的,劃分?jǐn)?shù)組的時(shí)候使用的是快排的劃分,沒有用到這里insert_sort排序產(chǎn)生的局部有序的特征,改進(jìn)優(yōu)化方法:在找中位數(shù)組中位數(shù)的過程中想辦法記錄下來,哪些數(shù)據(jù)必定小于中位數(shù)的在左上方,那些數(shù)據(jù)必定大于中位數(shù)在右下方, 以及不確定的那一塊。
# -*- coding: utf-8 -*-# 簡(jiǎn)單的插入排序 def insert_sort(arr,low,high):# 指針i,代表第幾次插入,第0次,就默認(rèn)首元素放入有序列表# 從第1次開始,拿一個(gè)元素放入有序列表,或者理解為拿原數(shù)組里面# 第i個(gè)元素放入有序數(shù)組,在這里是原地操作的,要么使用交換,要么# 先拿出一個(gè)元素在空中,數(shù)組里面就流出了一個(gè)空位for i in range(low+1,high+1):# 把第i個(gè)元素拿起,暫時(shí)放在空中temp = arr[i]# 指針j是從尾部掃描已排列的有序數(shù)組,注意有序列表是從小到大排列的# j一直都是指在空閑的位置的j = i# 遇到比空中的元素大的元素,大的元素后移一位,移到空出來的那個(gè)位置# 此時(shí)就又空出來一個(gè)位置,更新空閑的位置j,...直到碰到比空中的元素小的元素# 空中元素的位置就找到了,就是現(xiàn)在j指的空閑位置while arr[j-1] > temp and j >low:arr[j] = arr[j-1]j -=1# 把空中元素放入空閑位置arr[j] = temp# 這個(gè)一個(gè)可以準(zhǔn)確找到中位數(shù)的算法?顯然不是的這個(gè)只是大概找中位數(shù)的方法,而且還有一個(gè) # 致命的問題,只是找到中位數(shù)了,標(biāo)號(hào)還要搜索 # 然后此時(shí)的數(shù)組是有結(jié)構(gòu)規(guī)律的,劃分?jǐn)?shù)組的時(shí)候使用的是快排的劃分,沒有用到這里面 # insert_sort排序產(chǎn)生的局部有序的特征,改進(jìn)優(yōu)化方法:在找中位數(shù)組中位數(shù)的過程中 # 想辦法記錄下來,哪些數(shù)據(jù)必定小于中位數(shù)的在左上方,那些數(shù)據(jù)必定大于中位數(shù)在右下方, # 以及不確定的那一塊 def findMid(arr,low,high): ############################################################################### # Divide ############################################################################### # 這里的兩個(gè)指針為每個(gè)小分組的頭和尾,也可以只用一個(gè)指針left = lowright = low+4# count指的是中位數(shù)數(shù)組的指針count = 0# 當(dāng)小數(shù)組的尾指針小于等于右邊界限時(shí),對(duì)每個(gè)小組排序,得到每個(gè)小組的中位數(shù)while right <= high:insert_sort(arr,left,right)# 因?yàn)橹形粩?shù)是分散的步長(zhǎng)為5,對(duì)于我來說不好處理,所以此時(shí)處理時(shí)把中位都放在數(shù)組的# 前面,這樣下一輪時(shí)就比較好處理了,但是這樣處理,就破壞了數(shù)組有序的規(guī)律,讓最后# 無法利用數(shù)組的有序規(guī)律來劃分?jǐn)?shù)據(jù),這里可以優(yōu)化arr[low + count],arr[left +2] = arr[left +2],arr[low + count]# 處理下一組left +=5right +=5# 記得更新中位數(shù)數(shù)組的指針count +=1# 當(dāng)跳出循壞時(shí),就需要處理余數(shù),或者沒有進(jìn)入循環(huán),也要處理余數(shù)# 把余數(shù)排序,獲取中位數(shù),加入到中位數(shù)列表if left <=high:insert_sort(arr,left,high)arr[low + count],arr[left+(high-left)//2] = arr[left+(high-left)//2],arr[low + count]count +=1# 以上過程是這個(gè)問題劃分子問題的過程,也就是partion的過程,也就是把問題規(guī)模n變成# n//5的過程。 ############################################################################### # Conquer ################################################################################獲取到中位數(shù)數(shù)組,得到了子問題,下面就考慮治conquer了# 第一種情況,數(shù)組沒有經(jīng)過5分組,排序后直接到這里,直接返回在首位的中位數(shù),這種情況下count=1# 當(dāng)進(jìn)入了5分組沒有進(jìn)入余數(shù)處理,這時(shí)count=1,也應(yīng)該是返回首元素# 其他情況count>=0時(shí),這兩個(gè)元素還沒有排序,所以要進(jìn)入下一輪排序一下,變成count=1輸出首元素# count就是low>high的情況,直接返回空if count ==0:returnif count ==1:return arr[low]else:# 注意count是指中位數(shù)元素的數(shù)量,對(duì)應(yīng)數(shù)組上的指針需要-1return findMid(arr,low,low+count-1)#標(biāo)號(hào)需要通過檢索得到 def findIndex(arr,mid):for i in range(len(arr)):if arr[i] == mid:return idef partion_with_index(arr,low,high,index):def partition(arr,low,high):# 這時(shí)另外一種考慮方式,而且他是不需要額外空間的,他只使用一個(gè)指針來區(qū)分小于基準(zhǔn)和大于基準(zhǔn)的# pointer_less_than代表這個(gè)指針的左邊全部都是小于基準(zhǔn)的(包括自己,不包括首元素)# 然后從左往右掃描,遇到小于基準(zhǔn)的元素,就把小于基準(zhǔn)元素區(qū)域的后面緊接著的一個(gè)元素和他交換# 那么小于基準(zhǔn)元素區(qū)域就多了一個(gè)元素,。。。就這樣小于基準(zhǔn)的元素就連在了一起# 首元素是基準(zhǔn)元素,小于基準(zhǔn)元素區(qū)域塊,大于基準(zhǔn)元素區(qū)域塊,現(xiàn)在分成了三個(gè)部分# 把首元素和小于基準(zhǔn)元素區(qū)域塊最后一個(gè)元素交換,那三部分就變成,小于的,基準(zhǔn),大于的# 剛開始小于基準(zhǔn)的元素為0,暫且指向首位值pointer_less_than = low# 然后一次掃描后面所有元素for i in range(pointer_less_than +1,high+1):# 遇到小于基準(zhǔn)的,就把小于基準(zhǔn)元素區(qū)域的后面緊接著的一個(gè)元素和他交換,小于的塊相當(dāng)于也更新了if arr[i] < arr[low] :pointer_less_than +=1arr[pointer_less_than],arr[i]=arr[i],arr[pointer_less_than]# 把首元素和小于基準(zhǔn)元素區(qū)域塊最后一個(gè)元素交換,那三部分就變成,小于的,基準(zhǔn),大于的 arr[low],arr[pointer_less_than] = arr[pointer_less_than],arr[low]return pointer_less_thanarr[low],arr[index] = arr[index],arr[low]return partition(arr,low,high)def BFPTR(arr,low,high,k): ######################################################################### divide ######################################################################### 首先獲取midmid = findMid(arr,low,high)# 獲取此時(shí)mid的indexmid_index = findIndex(arr,mid)# 根據(jù)mid來劃分?jǐn)?shù)據(jù),返回的是中間的index(就是排序后最終的位置)index =partion_with_index(arr,low,high,mid_index) ######################################################################## Conquer ######################################################################## #根據(jù)index做出子問題的處理if index == k:return arr[index]elif index > k:return BFPTR(arr,low,index-1,k)else:return BFPTR(arr,index+1,high,k)arr3 = [7,3,66,33,22,66,9,0,1,11,14,17,9,10,13,99,44,33,77,88,99,101,404,87,44,22,11,99,43,22] print(sorted(arr3)) print(BFPTR(arr3,0,len(arr3)-1,(len(arr3)-1)//2-1)) runfile('D:/share/test/BFPTR.py', wdir='D:/share/test') [0, 1, 3, 7, 9, 9, 10, 11, 11, 13, 14, 17, 22, 22, 22, 33, 33, 43, 44, 44, 66, 66, 77, 87, 88, 99, 99, 99, 101, 404] 22 與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的分治法:BFPTR算法找第k小的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 找中位数,找第k小,还存在问题
- 下一篇: 算法优化:最大字段和,双指针遍历(n^2