python分治算法_分治法及其python实现例子
在前面的排序算法學(xué)習(xí)中,歸并排序和快速排序就是用的分治法,分治法作為三大算法之一的,有非常多的應(yīng)用例子。
分治法概念
將一個(gè)復(fù)雜的問(wèn)題分成兩個(gè)或更多的相同或相似的子問(wèn)題,再把子問(wèn)題分成更小的子問(wèn)題----“分”
將最后子問(wèn)題可以簡(jiǎn)單的直接求解----“治”
將所有子問(wèn)題的解合并起來(lái)就是原問(wèn)題打得解----“合”
分治法特征
該問(wèn)題的規(guī)模縮小到一定的程度就可以容易地解決
該問(wèn)題可以分解為若干個(gè)規(guī)模較小的相同問(wèn)題,即該問(wèn)題具有最優(yōu)子結(jié)構(gòu)性質(zhì)。
利用該問(wèn)題分解出的子問(wèn)題的解可以合并為該問(wèn)題的解;
該問(wèn)題所分解出的各個(gè)子問(wèn)題是相互獨(dú)立的,即子問(wèn)題之間不包含公共的子子問(wèn)題。
第一條特征是絕大多數(shù)問(wèn)題都可以滿(mǎn)足的,因?yàn)閱?wèn)題的計(jì)算復(fù)雜性一般是隨著問(wèn)題規(guī)模的增加而增加;
第二條特征是應(yīng)用分治法的前提它也是大多數(shù)問(wèn)題可以滿(mǎn)足的,此特征反映了遞歸思想的應(yīng)用;、
第三條特征是關(guān)鍵,能否利用分治法完全取決于問(wèn)題是否具有第三條特征,如果具備了第一條和第二條特征,而不具備第三條特征,則可以考慮用貪心法或動(dòng)態(tài)規(guī)劃法。
第四條特征涉及到分治法的效率,如果各子問(wèn)題是不獨(dú)立的則分治法要做許多不必要的工作,重復(fù)地解公共的子問(wèn)題,此時(shí)雖然可用分治法,但一般用動(dòng)態(tài)規(guī)劃法較好。
分治法例子:
一、對(duì)數(shù)組進(jìn)行快速排序
'''
時(shí)間復(fù)雜度O(nlogn)
pivot樞紐,low和high為起點(diǎn)終點(diǎn)
'''
#劃分分區(qū)(非就地劃分)
def partition(nums=list):
pivot= nums[0] #挑選樞紐
lo = [x for x in nums[1:] if x < pivot] #所有小于pivot的元素
hi = [x for x in nums[1:] if x >= pivot] #所有大于pivot的元素
returnlo,pivot,hi#快速排序
def quick_sort(nums=list):#被分解的Nums小于1則解決了
if len(nums) <= 1:returnnums#分解
lo,pivot,hi =partition(nums)#遞歸(樹(shù)),分治,合并
return quick_sort(lo) + [pivot] +quick_sort(hi)
lis= [7, 5, 0, 6, 3, 4, 1, 9, 8, 2]print(quick_sort(lis)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
二、對(duì)數(shù)組進(jìn)行歸并排序
'''名字很多:歸并排序/合并排序/二分排序
時(shí)間復(fù)雜度 O(logn)
遞歸
兩個(gè)步驟:1.拆分 2.合并'''
def merge_sort(nums=list):#取mid以及左右兩個(gè)數(shù)組
mid = len(nums)//2left_nums,right_nums=nums[:mid],nums[mid:]#遞歸分治
if len(left_nums) > 1:
left_nums=merge_sort(left_nums)if len(right_nums) > 1:
right_nums=merge_sort(right_nums)#合并
res =[]while left_nums and right_nums: #兩個(gè)都不為空的時(shí)候
if left_nums[-1] >= right_nums[-1]: #尾部較大者
res.append(left_nums.pop())else:
res.append(right_nums.pop())
res.reverse()#倒序
return (left_nums or right_nums) + res #前面加上剩下的非空nums
lis= [7, 5, 0, 6, 3, 4, 1, 9, 8, 2]print(merge_sort(lis)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
三、給定一個(gè)順序表,編寫(xiě)一個(gè)求出其最大值的分治算法
#O(nlogn)
#基本子算法(內(nèi)置算法)#雖然也可以處理大數(shù)組,這里用于解決分治問(wèn)題規(guī)模小于2時(shí)候
def get_max(nums=list):returnmax(nums)#分治法
defsolve(nums):
n=len(nums)if n <= 2: #分治問(wèn)題規(guī)模小于2時(shí)解決
returnget_max(nums)#分解(子問(wèn)題規(guī)模為 n/2)
left_list, right_list = nums[:n//2], nums[n//2:]#遞歸(樹(shù)),分治
left_max, right_max =solve(left_list), solve(right_list)#合并
returnget_max([left_max, right_max])if __name__ == "__main__":#測(cè)試數(shù)據(jù)
alist = [12,2,23,45,67,3,2,4,45,63,24,23]#求最大值
print(solve(alist)) #67
四、給定一個(gè)順序表,判斷某個(gè)元素是否在其中
#O(nlogn)#子問(wèn)題算法(子問(wèn)題規(guī)模為1)
defis_in_list(nums,key):if nums[0] ==key:print('Yes! %d in the nums' %key)else:print('Not found')#分治法
defsolve(nums,key):
n=len(nums)#N==1時(shí)解決問(wèn)題
if n == 1:returnis_in_list(nums,key)#分解
left_list,right_list = nums[:n//2],nums[n//2:]#遞歸(樹(shù)),分治,合并
res = solve(left_list,key) orsolve(right_list,key)returnresif __name__ == '__main__':#測(cè)試
lis = [12,2,23,45,67,3,2,4,45,63,24,23]#查找
print(solve(lis,45)) #YES~
print(solve(lis,5)) #NOT~
五、找出一組序列中的第 k 小的元素,要求線(xiàn)性時(shí)間
'''O(nlogn)
用快排的方法,選定pivot然后通過(guò)左右兩個(gè)分組遞歸得出結(jié)果'''
#劃分
def partition(nums=list):
pi=nums[0]
lo= [x for x in nums[1:] if x
hi= [x for x in nums[1:] if x >=pi]returnlo,pi,hi#查找第 k 小的元素
defsolve(nums,key):#分解
lo,pi,hi =partition(nums)
n=len(lo)#解決
if n ==key:returnpi#遞歸分治
elif n
else:returnsolve(lo,key)if __name__ == '__main__':
lis= [3, 4, 1, 6, 3, 7, 9, 13, 93, 0, 100, 1, 2, 2, 3, 3, 2]print(solve(lis,3))#2
print(solve(lis,10))#4
總結(jié)
以上是生活随笔為你收集整理的python分治算法_分治法及其python实现例子的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: css 垂直居中_html中div使用C
- 下一篇: python 模块 包 库_模块(包、库