算法教程学习——分治算法

分治算法的通用形式:

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))

同样,运行结果如下图所示:
在这里插入图片描述

你可能感兴趣的:(经典算法)