用大O法表示运行时间,log都表示log2(以2为底的对数)
所有的算法都是基于python写的
1、输入:一个有序的元素列表
2、输出:如果要查找的元素包含在列表中,二分查找返回其位置,否则返回NULL.
3、使用二分查找,每次排除一半的数字
4、算法过程:检查中间元素,若小了,就改变low,如果大了就修改high
5、完整代码如下:
def binary_search(list,item):
low=0
high=len(list)-1
while low<=high: #只要范围没有缩小到只剩一个元素
mid=(low+high)/2
guess=list[mid]
if guess==item:
return mid
if guess > item:
high=mid-1
if guess < item:
low=mid+1
return None
//测试一下
mylist=[1,3,5,7,9]
print binary_search(mylist,3)
print binary_search(mylist,-1)
6、运行时间:大O表示法,指出了最糟情况下的运行时间
①简单查找:O(n)
②二分查找:O(log n)
③快速排序:O(n*log n)
④选择排序:O(n^2)
⑤旅行商问题:一种非常慢的算法O(n!)
旅行商问题:找最短路径
①数组:内存单位相连,固定好了一定的内存空间,如果不够不可以临时加,只能重新划定一个连续内存空间
②链表:元素可存储在内存的任何地方,每一个元素都存储了下一个元素的地址,优势在插入元素方面。但是当你要访问某一个元素时,你就得从链表头开始一个个访问过去,对于跳跃真的很不方便,因为你不知道后面的元素的地址,只能一个个往后推着走。
运行时间 | 数组 | 链表 |
---|---|---|
读取 | O(1) | O(n) |
插入 | O(n) | O(1) |
删除 | O(n) | O(1) |
①使用链表插入,只需要改变前面那个元素指向的地址,通常都记录了链表的第一个元素和最后一个元素
②使用数组,则必须将后面的元素都向后移,这样感觉会很麻烦,有时候要是数目大于数组的已划分的内存的长度,那就得复制到一个新的数组中了
③链表只能顺序访问,数组支持随机访问
所以,插入用链表,删除同理
每次从剩下的元素中查找到最大(或最小的元素),之后将元素挑出来放在新列表中接下去的位置中。
def findSmallest(arr):
smallest = arr[0] #用于存储最小的值
smallest_index=0 #用于存储最小的索引
for i in range(1,len(arr)):
if arr[i]return smallest_index
def selectionSort(arr):
newArr=[]
for i in range(len(arr)):
smallest=fomdSmallest(arr)
newArr.append(arr.pop(smallest))#找出数组中最小的元素,并将其加入到新数组中,从原来的数组中pop出来
return newArr
print selectionSort([5,3,6,2,10,85])
以上python中数组的操作比如pop可以参考:https://blog.csdn.net/anneqiqi/article/details/71057069
递归指的是函数调用自己,相关数据结构—栈(压栈和出栈),每次调用函数时,计算机都将函数调用所涉及到的所有变量的值存储在内存中,如果陷入没完没了的递归会导致栈溢出。
①找一个元素作为基准值
②找出比基准值小的元素还有比基准值大的元素,得到——一个由所有小于基准值的数字组成的子数组 + 基准值 + 一个由所有大于基准值的数字组成的子数组
③对子数组继续进行排序(递归调用)
归纳证明:归纳条件和基线条件
#O(n log n)
def quicksort(array):
if len(array) <2:
return array #基线条件:为空或者只包含一个元素的数组(有序)
else:
plvot=array[0]
less=[i for i in array[1:] if i<=plvot]
greater=[i for i in array[1:] if i > plvot]
return quicksort(less)+[plvot]+quicksort(greater)
print quicksort([10,5,2,6,8,9])
①最佳/平均:O(log n)
②最差:O(n^2)
①散列函数总是将同样的输入映射到相同的索引,每次取相同已知数的值的函数值时都能得到一样的函数值结果
②散列函数将不同的输入映射到不同的索引
③散列函数知道数组多大,只返回有效的索引
①创建 number=dict() 或者 number={} ( 一对大括号 )
②添加元素number[“Marry”]=8945968
域名 → IP 就是用散列表
③散列表可以防止重复(键)
④将散列表用作缓存:网站将数据记住,不再需要重新计算获取。
⑤当访问一个网站页面时,它会先检查散列表中是否存储了该页面。
cache={} #创建散列表
def get_page(url):
if cache.get(url): #散列表的get方法
return cache[url]
else:
data=get_data_from_server(url)
cache[url]=data
return data
⑥散列表用于模拟映射关系
⑦冲突:如果两个键映射到了同一个位置,就在这个位置存储一个链表
⑧好的散列函数应该做到将键均匀地映射到散列表的不同位置
⑨性能:在平均情况下,散列表执行各种操作的时间都是O(1),是常量时间,并不意味着马上,而是说不管散列表多大,所需的时间都一样。
散列表 | 平均情况 | 最糟情况 | 数组 | 链表 |
---|---|---|---|---|
查找 | O(1) | O(n) | O(1) | O(n) |
插入 | O(1) | O(n) | O(n) | O(1) |
删除 | O(1) | O(n) | O(n) | O(1) |
⑩填装因子=散列表包含的元素数 / 位置总数,用于度量散列表中有多少位置是空的,填装因子大于1意味着元素数量超过了数组的位置数。填装因子越低,散列表性能越高。
均匀分布:即尽量让不同的键值拥有不同的散列值
①从节点A出发,有前往节点B的路径吗?
②从节点A出发,前往节点B的哪条路径最短?
首先在一度关系中搜索,确定一度关系中没有结论后才在二度关系中进行搜索,搜索范围从起点开始逐渐向外延伸
队列的操作
①queue()
定义一个空队列,无参数,返回值是空队列。
②enqueue(item)
在队列尾部加入一个数据项,参数是数据项,无返回值。
③ dequeue()
删除队列头部的数据项,不需要参数,返回值是被删除的数据,队列本身有变化。
④isEmpty()
检测队列是否为空。无参数,返回布尔值。
⑤ size()
返回队列数据项的数量。无参数,返回一个整数。
⑥deque()
双向队列https://www.cnblogs.com/zhenwei66/p/6598996.html
from collections import deque
def search(name):
search_queue = deque()
search_queue += graph[name]
searched=[] #用于记录检查过的人的数组
while search_queue:
person=search_queue.popleft() #获取最左边一个元素,并在队列中删除
if not person in searched:
if person_is_seller(person):
print person + " is a mango seller!"
return true
else:
search_queue += graph[person] #可能是个数组
searched.append(person)
return False
graph={} #创建一个散列表
graph["you"]=["alice","bob","cici"]
graph["alice"]=["peggy"]
graph["bob"]=["ann"]
........ #表示图的邻居关系,一度关系
search["you"]
V:表示顶点数,E表示边数
找出权重最小的路径
①找出最便宜的节点,即在最短时间内可以前往的节点
②对于该节点的邻居,检查是否有前往它们的更短路径,如果有,更新开销
③重复这个过程,直到对图中的每个节点都这样做了
④计算最终路径
负权边不适合用狄克斯特拉算法,包含负权边应该使用贝尔曼-福德算法
def find_lowest_cost_node(costs):
lowest_cost=float("lnf")
lowest_cost_node=None
for node in costs:
cost=costs[node]
if cost < lowest_cost and node not in processed: #如果当前节点的开销更低且未经过处理
lowest_cost=cost #将其视为开销最低的节点
lowest_cost_node=node
return lowest_cost_node
node = find_lowest_cost_node(costs)#在未处理的节点中找出开销最小的节点
while node is not None:
cost =costs[node]
neighbors=graph[node]
for n in neighbors.keys(): #遍历所有的邻居节点
new_cost=cost + neighbors[n]
if costs[n] >new_costs: #如果经当前节点前往该邻居更近
costs[n]=new_cost #更新该邻居的开销
parents[n]=node #同时将该邻居的父节点设置为当前节点
processed.append(node) #将当前节点加入到处理队列
node=find_lowest_cost_node(costs) #找出接下来要处理的节点
1、将问题分成小问题,并先着手解决小问题,每个动态规划解决方案都设计网格。
1、推荐电影?根据喜好?
2、计算两点的距离,可以使用毕达哥斯拉公式
3、涉及机器学习:
① OCR:光学字符识别 ——人脸识别、语音识别
② 垃圾邮箱过滤器—朴素贝叶斯分类器
4、KNN用于分类和回归,需要考虑最近的邻居。分类就是编组,回归就是预测结果
1、数:二叉树、B树(平衡树)
B树、平衡树是什么?性能比较好的树
2、反向索引:搜索引擎、搜索
3、傅里叶变换:分析成分,处理信号、压缩音乐;
4、并行算法
5、归并函数
6、布隆过滤器
7、SHA算法
8、Diffie-Hellman算法:公开密钥算法,非对称
9、线性规划:Simplex算法
《算法图解》笔记
https://blog.csdn.net/dongrixinyu/article/details/78775057