常见算法-python实现总结
排序:
1.堆排序:
堆是一种特殊的数据结构,它的通常的表示是它的根结点的值最大或者是最小。python标准库模块heapq提供了相关堆排序的实现
heapq的常见用法
heapq=[] #创建一个堆
heapq.heappush(heap,item)#往堆中插入一条新的值
heapq.heappop(heap)#弹出最小的值
heap.heapify(list)#将转换列表成为堆结构
heap[0] # 如果只是想获取最小值而不是弹出,使用heap[0]
heap.heapreplace(heap,item)#弹出一个最小的值,然后将item插入到堆当中。堆的整体的结构不会发生改变。
heapq.heappoppush()#弹出最小的值,并且将新的值插入其中
heapq.nlargest(n , iterbale, key=None)#从堆中找出做大的N个数,key的作用和sorted( )方法里面的key类似,用列表元素的某个属性和函数作为关键字
heapq.merge(*iterables) #方法,用于合并多个排序后的序列成一个排序后的序列, 返回排序后的值的迭代器。
1.创建一个堆:
两种方法,第一种就是创建空列表,然后用heapq.heappush()方法把值加入堆中;第二种就是用heap.heapify(list)方法转换列表成为堆结构;
import heapq
lis=[2, 3, 5, 1, 54, 23, 132]
heap = []
for num in lis:
heapq.heappush(heap, num) #第一种方式
print([heapq.heappop(heap) for _ in range(len(lis))]) # 堆排序结果
# out: [1, 2, 3, 5, 23, 54, 132]
lis = [2, 3, 5, 1, 54, 23, 132]
heapq.heapify(lis)# 第二种方式
print([heapq.heappop(nums) for _ in range(len(nums))]) # 堆排序结果
# out: [1, 2, 3, 5, 23, 54, 132]
#通过heapq.merge(*iterables) 方法,合并多个排序后的序列成一个排序后的序列, 返回排序后的值的迭代器。
n1=[32, 3, 5, 34, 54, 23, 132]
n2=[23, 2, 12, 656, 324, 23, 54]
n1=sorted(n1)
n2=sorted(n2)
me=heapq.merge(n1, n2)
print(list(me))
#out: [2, 3, 5, 12, 23, 23, 23, 32, 34, 54, 54, 132, 324, 656]
2.获取堆的最大或最小值:
"""
从列表中找出最大的或最小的N个元素
堆结构(大根堆/小根堆)
"""
import heapq
list1 = [34, 25, 12, 99, 87, 63, 58, 78, 88, 92]
list2 = [
{
'name': 'IBM', 'shares': 100, 'price': 91.1},
{
'name': 'AAPL', 'shares': 50, 'price': 543.22},
{
'name': 'FB', 'shares': 200, 'price': 21.09},
{
'name': 'HPQ', 'shares': 35, 'price': 31.75},
{
'name': 'YHOO', 'shares': 45, 'price': 16.35},
{
'name': 'ACME', 'shares': 75, 'price': 115.65}
]
print(heapq.nlargest(3, list1))
print(heapq.nsmallest(3, list1))
"""
输出:
[99, 92, 88]
[12, 25, 34]
"""
print(heapq.nlargest(2, list2, key=lambda x: x['price']))
print(heapq.nlargest(2, list2, key=lambda x: x['shares']))
"""
输出:
[{'name': 'YHOO', 'price': 16.35, 'shares': 45},
{'name': 'FB', 'price': 21.09, 'shares': 200},
{'name': 'HPQ', 'price': 31.75, 'shares': 35}]
[{'name': 'AAPL', 'price': 543.22, 'shares': 50},
{'name': 'ACME', 'price': 115.65, 'shares': 75},
{'name': 'IBM', 'price': 91.1, 'shares': 100}]
"""
3.实现堆排序算法:
>>> def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for i in range(len(h))]
>>> heapsort([1,3,2,5,4,9,6,8,10])
[1, 2, 3, 4, 5, 6, 8, 9, 10]
2.简单选择排序:
>>> def select_sort(items, comp=lambda x, y: x < y):#默认参数用lambda表达式来规定排序规则
"""简单选择排序"""
items = items[:]
for i in range(len(items) - 1):
min_index = i
for j in range(i + 1, len(items)):
if comp(items[j], items[min_index]):
min_index = j
items[i], items[min_index] = items[min_index], items[i]
return items
>>> select_sort([1,2,5,4,9,8,7,6])
[1, 2, 4, 5, 6, 7, 8, 9]
3.冒泡排序:
>>> def bubble_sort(items, comp=lambda x, y: x > y):#默认参数仍然选用lambda表达式规则
"""冒泡排序"""
items = items[:]
for i in range(len(items) - 1):
swapped = False
for j in range(i, len(items) - 1 - i):
if comp(items[j], items[j + 1]):
items[j], items[j + 1] = items[j + 1], items[j]
swapped = True
if not swapped:
break
return items
>>> bubble_sort([1,2,5,4,9,8,7,6])
[1, 2, 4, 5, 6, 7, 8, 9]
4.冒泡排序plus:
def bubble_sort(items, comp=lambda x, y: x > y):
"""(冒泡排序优化版)"""
items = items[:]
for i in range(len(items) - 1):
swapped = False #在排序过程中,进行记录,可以检测到整个序列是否已经排序完成,进而可以避免掉后续的循环:
for j in range(i, len(items) - 1 - i):
if comp(items[j], items[j + 1]):
items[j], items[j + 1] = items[j + 1], items[j]
swapped = True
if swapped:
swapped = False
for j in range(len(items) - 2 - i, i, -1):
if comp(items[j - 1], items[j]):
items[j], items[j - 1] = items[j - 1], items[j]
swapped = True
if not swapped:
break
return items
5.归并排序:
def merge(items1, items2, comp=lambda x, y: x < y):
"""合并(将两个有序的列表合并成一个有序的列表)"""
items = []
index1, index2 = 0, 0
while index1 < len(items1) and index2 < len(items2):
if comp(items1[index1], items2[index2]):
items.append(items1[index1])
index1 += 1
else:
items.append(items2[index2])
index2 += 1
items += items1[index1:]
items += items2[index2:]
return items
def _merge_sort(items, comp):
"""归并排序"""
if len(items) < 2:
return items
mid = len(items) // 2
left = _merge_sort(items[:mid], comp)
right = _merge_sort(items[mid:], comp)
return merge(left, right, comp)
def merge_sort(items, comp=lambda x, y: x < y):
return _merge_sort(list(items), comp)
查找:
1.顺序查找:
顺序查找用到了一个python内置enumerate() 函数:
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
举例:
>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
顺序查找:
def seq_search(items, key):
"""顺序查找"""
for index, item in enumerate(items):
if item == key:
return index
return -1
2.折半查找:
def bin_search(items, key):
"""折半查找"""
start, end = 0, len(items) - 1
while start <= end:
mid = (start + end) // 2
if key > items[mid]:
start = mid + 1
elif key < items[mid]:
end = mid - 1
else:
return mid
return -1
常见算法:
- 穷举法 - 又称为暴力打表法,对所有的可能性进行验证,直到找到正确答案。
- 贪婪法 - 在对问题求解时,总是做出在当前看来是最好的选择,不追求最优解,快速找到满意解。
- 分治法 - 把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题,直到可以直接求解的程度,最后将子问题的解进行合并得到原问题的解。
- 回溯法 - 按选优条件向前搜索,当搜索到某一步发现原先选择并不优或达不到目标时,就退回一步重新选择。
- 动态规划 - 基本思想也是将待求解问题分解成若干个子问题,先求解并保存这些子问题的解,避免产生大量的重复运算。
穷举举例:
#穷举法:
'''鸡兔同笼问题:今有鸡兔同笼,上有三十五头,下有九十四足,问鸡兔各几只?
这个问题的大致意思是:在一个笼子里关着若干只鸡和若干只兔,从上面数共有35个头,从下面数共有94只脚。问笼中鸡和兔的数量各是多少?
'''
for i in range(1,35):
for j in range(1,35):
if (i*2 + j*4) == 94 and (i + j == 35):
print("There are %d chickens,and %d rabbits" % (i,j))
#列表推导式实现:
list = [(i,j) for i in range(1,35) for j in range(1,35) if (i*2 + j*4) == 94 and i + j ==35]
'''百钱百鸡问题: 公鸡5元一只 母鸡3元一只 小鸡1元三只,用100元买100只鸡 问公鸡/母鸡/小鸡各多少只'''
for x in range(20):
for y in range(33):
z = 100 - x - y
if 5 * x + 3 * y + z // 3 == 100 and z % 3 == 0:
print(x, y, z)
贪婪举例:
拍卖会,假有一个背包,最多能装20公斤物品,有如下表所示的物品。很显然,不能把所有物品都装进背包,所以必须装哪些物品,留下哪些物品。
名称 | 价格(¥) | 重量(kg) |
---|---|---|
电脑 | 200 | 20 |
收音机 | 20 | 4 |
钟 | 175 | 10 |
花瓶 | 50 | 2 |
书 | 10 | 1 |
油画 | 90 | 9 |
class Thing(object):
"""物品"""
def __init__(self, name, price, weight):
self.name = name
self.price = price
self.weight = weight
@property
def value(self):
"""价格重量比"""
return self.price / self.weight
def input_thing():
"""输入物品信息"""
name_str, price_str, weight_str = input().split()
return name_str, int(price_str), int(weight_str)
def main():
max_weight, num_of_things = map(int, input().split())
all_things = []
for _ in range(num_of_things):
all_things.append(Thing(*input_thing()))
all_things.sort(key=lambda x: x.value, reverse=True)
total_weight = 0
total_price = 0
for thing in all_things:
if total_weight + thing.weight <= max_weight:
print(f'拿走了{thing.name}')
total_weight += thing.weight
total_price += thing.price
print(f'总价值: {total_price}美元')
if __name__ == '__main__':
main()
'''
输入:
20 6
电脑 200 20
收音机 20 4
钟 175 10
花瓶 50 2
书 10 1
油画 90 9
'''
'''
输出:
拿走了花瓶
拿走了钟
拿走了书
拿走了收音机
总价值: 255美元
'''
分治法举例:
"""
快速排序 - 选择枢轴对元素进行划分,左边都比枢轴小右边都比枢轴大
"""
def quick_sort(items, comp=lambda x, y: x <= y):
items = list(items)[:]
_quick_sort(items, 0, len(items) - 1, comp)
return items
def _quick_sort(items, start, end, comp):
if start < end:
pos = _partition(items, start, end, comp)
_quick_sort(items, start, pos - 1, comp)
_quick_sort(items, pos + 1, end, comp)
def _partition(items, start, end, comp):
pivot = items[end]
i = start - 1
for j in range(start, end):
if comp(items[j], pivot):
i += 1
items[i], items[j] = items[j], items[i]
items[i + 1], items[end] = items[end], items[i + 1]
return i + 1
动态规划举例:
子列表元素之和的最大值。
子列表指的是列表中索引(下标)连续的元素构成的列表;列表中的元素是int类型,可能包含正整数、0、负整数;程序输入列表中的元素,输出子列表元素求和的最大值,例如:
输入:1 -2 3 5 -3 2
输出:8
输入:0 -2 3 5 -1 2
输出:9
输入:-9 -2 -3 -5 -3
输出:-2
def main():
items = list(map(int, input().split()))
overall = partial = items[0]
for i in range(1, len(items)):
partial = max(items[i], partial + items[i])
overall = max(partial, overall)
print(overall)
if __name__ == '__main__':
main()
回溯法举例:
全排列问题:给定一个没有重复数字的序列,返回其所有可能的全排列
def DFS(res,sublist,nums):
if len(sublist)==len(nums):
res.append(sublist[:])
for i in nums:
if i in sublist:
continue
sublist.append(i)
DFS(res,sublist,nums)#递归
sublist.remove(i)#回溯
def main():
res=[]
sublist=[]
nums=list(eval(input()))
DFS(res,sublist,nums)
print(res[:])
main()
'''
输入:1,2,3
输出:[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
'''