python之搜索算法与贪心算法。

一、搜索算法

搜索算法又叫查找算法。在日常生活中,几乎每天都要进行一些查找的工作,在电话簿中查阅某个人的电话,在电脑的文件夹中查找某个具体的文件等等。
查找表是由同一类型的数据元素构成的集合。例如电话号码簿和字典都可以看作是一张查找表。

一般对于查找表有以下几种操作:

在查找表中查找某个具体的数据元素;
在查找表中插入数据元素;
从查找表中删除数据元素;

静态查找表和动态查找表
在查找表中只做查找操作,而不改动表中数据元素,称此类查找表为静态查找表;
在查找表中做查找操作的同时进行插入数据或者删除数据的操作,称此类表为动态查找表。
关键字又细分为主关键字和次关键字
若某个关键字可以唯一地识别一个数据元素时,称这个关键字为主关键字,例如学生的学号就具有唯一性;
像学生姓名、年龄这类的关键字,由于不具有唯一性,称为次关键字。

当然,我们的搜索算法比较常用的就是顺序查找和折半查找,下面我们一一介绍。

顺序查找算法

从表中的最后一个数据元素开始,逐个同记录的关键字做比较, 如果匹配成功,则查找成功;
如果直到表中第一个关键字查找完也没有成功匹配,则查找失败。
具体实现和结果如下:

def sequence_search(array,key):
    """
    顺序查找
    """
    for i in range(len(array)):
        if array[i]==key:
            return i
    return False

array=[1,5,7,4,6,3]
print(sequence_search(array,4))

这个结果就会返回4这个元素在表中的索引下标。

折半查找算法

折半查找又叫二分法。
在这里插入图片描述
具体实现和结果如下:

def halffind(nums,key,low,high):
	"""
    :param nums: 查找的对象
    :param key: 查找的元素
	"""
    mid = (low+high)//2
    if key == nums[mid]:
        return mid
    if low >high:
        return False
    if key>nums[mid]:
        return halffind(nums,key,mid +1,high)
    else:
        return halffind(nums, key, low, mid - 1)
nums=[1,2,3,4,5,6,7,8]
print(halffind(nums,3,0,(len(nums)-1)))

这个算法我们主要是用递归来实现的,每次需要查找的元素和中间值mid进行比较。最终找到元素位置,返回3这个元素在表中的索引下标。

二、贪心算法

在对问题求解时,总是作出在当前看来是最好的选择。也就是说,不从整体上加以考虑,它所作出的仅仅是在某种意义上的局部最优解(是否是全局最优,需要证明)。
我们平时其实也有不觉中使用了贪心算法,只是我们没有发觉。下面我们通过两个问题来具体理解贪心算法。
最优装载问题
有一天海盗们截获了一艘装满各种各样古董的货船,每一件都价值连城,一旦打碎就是去了价值,海盗船载重量为C,每件固定的重量为wi,海盗们该如何尽可能装载最多数量的古董呢?

  1. 船载重量固定为C,只要每次选择重量最小的古董,直到不能再装为止,这样装载的古董数量最大,
    这就是贪心策略;
  2. 把古董按重量从小到大排序,根据策略选出尽可能多的古董。

具体实现和结果如下:

def max_ans(antique,key):
    anti_sort =sorted(antique)
    ans,tmp=0,0
    ship=[]
    for a in anti_sort:
        tmp +=a
        if tmp <=key:
            ans +=1
            ship.append(a)
    print("装载的古董数量:",ans)
    print("装载的古董:",ship)

antique=[4,3,15,5,12,6,7,8]
max_ans(antique,40)

在这里插入图片描述
背包问题
假设山洞中有n种宝物,每种宝物有一定重量w和相应的价值v,毛驴运载能力一种宝物只能拿一样,宝物可分割。怎样才能使毛驴运走宝物的价值最大呢?
可以尝试三种贪心策略:
3. 每次挑选价值最大的装东西入背包;
4. 每次挑选最重的东西;
5. 每次选取单位重量价值最大的东西。
我们现在来看下我们的算法设计:

  1. 计算出每件宝物的性价比,按照从高到低排序;
  2. 根据贪心策略,按性价比从大到小选取宝物,直到达到毛驴的运载能力。每次选择宝物后判断是否
    小于m,如果不小于则取走宝物的一部分,程序结束

具体实现和结果如下:

# datas中每个元素代表一个古董,每个列表第一个元素代表古董重量,第二个元素代表古董价值
datas = [[4, 3], [2, 8], [9, 18], [5, 6], [5, 8], [8, 20], [5, 5], [4, 6], [5, 7], [5, 15]]
m = 30 # 毛驴运载能力
w = 0 # 获取的总价值
# 计算出每件宝物的性价比,按照从高到低排序
for i in range(len(datas)):
	price = datas[i][1] / datas[i][0]
	datas[i].append(price)  # 增加性价比
datas.sort(key=lambda data: data[2], reverse=True) # 按性价比排序
# 按性价比从大到小选取宝物,直到达到毛驴的运载能力
for data in datas:
	if data[0] <= m:
		w += data[1]
		m -= data[0]
	else:
		w += data[2] * m  # 取走宝物的一部分
		break
print('总价值:',w)

在这里插入图片描述
这个问题的难点就在于分割宝物,理解起来有些困难。
我们试想一下如果宝物不可分割,贪心算法得到的是否是最优解?
注意: 物品可分割的装载问题称为背包问题,不可分割问题的装载问题称为0-1背包问题。
0-1背包问题不具有贪心选择性质,贪心算法不能得到全局最优解,仅仅是最优解的近似解。
0-1背包问题可用动态规划算法求解。

动态规划

动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。
通过两个实例来具体了解动态规划。
动态规划之Fib数列
问题: 有个小孩上楼梯,共有N阶楼梯,小孩一次可以上1阶,2阶。走到N阶楼梯,一共有多少种走法?
DP之自顶向下分析方式:
爬到第N阶楼梯,一共只有2种情况(全划分,加法原理),从第N-1阶爬1阶到第N阶;从第N-2阶爬2阶到第N阶;
故:way(N)=way(N-1)+way(N-2)
具体实现和结果如下:

def fib2(n):
    memo=[-1 for x in range(n+1)]
    memo[0]=0
    memo[1]=1
    memo[2]=2
    for i in range(3,n+1):
        memo[i]=memo[i-1]+memo[i-2]
    return memo[n]

print(fib2(5))

运行结果就是3+5=8种走法。

不相邻数最大和
问题: 给定数组A=[1,2,4,1,7,8,3],求出数组A中互不相邻的数的最大和。
例如:如果选择了8,则不能选择7和3,在本例中最大的和为1+4+7+3=15
具体实现和结果如下:

arr=[1,2,4,1,7,8,3]
def dp_opt(arr):
    len_arr=len(arr)
    opt = [0 for i in range(len_arr)]
    opt[0]=arr[0]
    opt[1]=max(arr[0],arr[1])
    for  i in range(0,len(arr)):
        A=opt[i-1]
        B=arr[i]+opt[i-2]
        opt[i]=max(A,B)
    return opt

print(dp_opt(arr))

在这里插入图片描述
返回的是我们选择每一个数字的最大和,很明显最后一个的时候最大。也就是我们的预期结果1+4+7+3=15。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值