分治算法的通用形式:
def divide_and_conquer(S, divide, combine):
if len(S) == 1:
return S
L, R = divide(S)
A = divide_and_conquer(L, divide, combine)
B = divide_and_conquer(R, divide, combine)
return combine(A, B)
二分搜索就是典型的分治算法,该算法的的时间为O(nLogn),其主要来自于该算法要求数组要经过排序算法。
#coding:utf-8
from random import randint
def binarySearch(L, k, start, end):
# 递归结束条件,即要搜索的数组长度为1
if start == end:
if L[start] == k:
return True
return False
# 数组长度不为1,继续分
mid = (start + end) // 2
if k == L[mid]:
return True
elif k < L[mid]:
binarySearch(L, k, start, mid)
else:
binarySearch(L, k, mid, end)
if __name__ == "__main__":
# 随机生成20长度的1-100整数数组
L = [randint(1, 100) for t in range(20)]
print(L)
# 随机生成1-100之间的整数
k = randint(1, 100)
print(k)
# 对L排序
sorted(L)
# 二分搜索
if binarySearch(L, k, 0, len(L)):
print("Yes")
print("No")
运行结果如下图所示:
接下来是折半搜索,这是一个可以在线性时间找出无序序列中第k大的数字,同时该方法也是快速排序的基础。
# coding:utf-8
from random import randint
def partition(L):
# pi就是所需用来判断其他数字相对大小的值
pi, L = L[0], L[1:]
# 以pi为中间值,将数组分成两部分
li = [item for item in L if item <= pi]
ab = [item for item in L if item > pi]
return li, ab, pi
def select(L, k):
li, ab, pi = partition(L)
length_li = len(li)
if length_li == k:
return pi
elif length_li < k:
return select(ab, k-length_li-1)
else:
return select(li, k)
if __name__ == "__main__":
# 生成长度20的随机整数数组
L = [randint(0, 100) for t in range(20)]
# 输出随机数组
print("随机数组:", L)
# 产生随机数k,这里从0位置开始计数
k = randint(0, 19)
# 输出k
print("随机数k:", k)
# 输出第k大的数值
print("第k大的数值:", select(L, k))
# 输出排序过的数组
print("排序过数组:", sorted(L))
程序结果如下图所示:
有了折半搜索,快速排序就打好了基础。该算法在平均时间复杂度是O(nLogn), 最坏情况则是平方级算法,这里的关键就是在于分数组时,作为大小比较的数值的选取。如果能较好的方法选取该值,就能稳定在对数级的复杂度。下面程序并没有考虑这一点。
# coding:utf-8
from random import randint
import partitionSecelect # 上个算法文件
def quickSort(L):
# 终止条件注意小于等于1,要考虑可能数组为0的特殊情况
if len(L) <= 1:
return L
li, ab, pi = partitionSecelect.partition(L)
return quickSort(li) + [pi] + quickSort(ab)
if __name__ == "__main__":
L = [randint(1, 100) for t in range(20)]
# 输出20长度随机数组
print(L)
print(quickSort(L))
程序结果如下图所示:
本文中关于分治的最后一个算法就是归并排序,这也是一个时间复杂度O(nLogn)的算法。
# coding:utf-8
from random import randint
def mergeSort(L):
res = []
mid = len(L) // 2
lft, rgt = L[:mid], L[mid:]
if len(lft) > 1:
lft = mergeSort(lft)
if len(rgt) > 1:
rgt = mergeSort(rgt)
while lft and rgt:
if lft[-1] >= rgt[-1]:
# 注意pop函数是从列表的最后一位开始
res.append(lft.pop())
else:
res.append(rgt.pop())
res.reverse()
return (lft or rgt) + res
if __name__ == "__main__":
L = [randint(1, 100) for t in range(20)]
# 输出20长度随机数组
print(L)
print(mergeSort(L))