02 《算法图解——像小说一样有趣的算法书》1

《算法图解——像小说一样有趣的算法书》

本书在此只记录结果,算法。


1 二分法

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:		//item为要搜索的值,guess>item:规定了上界。
			high=mid-1
		else:				//item为要搜索的值,guess<item:规定了下界。
			low=mid+1

my_list=[1,3,5,7,9]
print(binaty_search(my_list,3))		# =>1
print(binaty_search(my_list,-1))	# =>None

2 选择排序

def findSmallest(arr):
	smallest=arr[0]
	smallest_index=0
	for i in range(1,len(arr)):
		if arr[i]<smallest:
			smallest=arr[i]
			smallest_index=i
	return smallest_index		//返回下标

def selectionSort(arr):
	newArr=[]
	for i in range(len(arr)):
		smallest=findSmallest(arr)
		newArr.append(arr.pop(smallest))
	return newArr

print(selectionSort([5,3,6,2,10]))

3 递归

  1. 用递归的方法,在盒子中找钥匙的步骤:
    ① 检查盒子中的每样东西。
    ② 如果是盒子,就回到第一步。
    ③ 如果是钥匙,就大功告成!
def look_for_key(box):
	for item in box:
		if item.is_a_box():
			look_for_key(item)		//递归
		elif item.is_a_key():
			print("found the key! ")
  1. 基线条件(base case) 和 递归条件(recursive case)
    编写递归函数时,必须要告诉它何时停止递归。正因为如此,每个递归函数都有两部分:基线条件(base case)递归条件(recursive case)递归条件指的是函数调用自己,而基线条件则指的是函数不再调用自己,从而避免形成无限循环
def countdown(i):
	print(i)
	if i<=0:				//==>基线条件(base case)
		return
	else:					//==>递归条件(recursive case)
		countdown(i-1)
  1. 递归调用栈
    递归函数factorial的调用栈( 5! )
    5!=5 x 4 x 3 x 2 x 1
def fact(x):
	if x==1:				//==>基线条件(base case)
		return 1
	else:					//==>递归条件(recursive case)
		return x*fact(x-1)


原来盒子堆存储在栈中!这个栈包含未完成的函数调用,每个函数调用都包含还未检查完的盒子。使用栈很方便,因为你无需自己跟踪盒子堆——栈替你这样做了。


4 快速排序

分而治之(divide and conquer,D&C)——一种著名的递归式问题解决办法。
快速排序

def quicksort(array):
	if len(arr)<2:
		return array
	else:
		pivot=array[0]
		less=[i for i in array[1:] if i<=pivot]
		greater=[i for i in array[1:] if i>pivot]
	return quicksort(less)+[pivot]+quicksort(greater)

print(quicksort([10,5,2,3]))

合并排序
这个函数遍历列表中的每个元素并将其打印出来。它迭代整个列表一次,并在打印每个元素前休眠一秒。

from time import sleep
def print_item2(list):
	for item in list:
		sleep(1)
		print(item)

5 散列表

使用函数 dict( )来创建散列表。散列表由键和值组成。散列表将键映射到值,键不可重复。 在散列表book中,键为商品名,值为商品价格。

book=dict()
book["apple"]=0.67
book["milk"]=1.49
book["avocado"]=1.49
print(book)
>>>{'apple':0.67,'milk':1.49,'avocado':1.49}
print(book["avocado"])
>>>1.49

练习:请问下面哪些散列函数是一致的?
① f(x)=1 <-------------------无论输入是什么,都返回1
② f(x)=rand( ) <-------------------每次都返回一个随机数
③ f(x)=next_empty_slot( ) <---------------返回散列表中下一个空位置的索引
④ f(x)=len(x) <-------------------将字符串的长度用作索引
答案:① ③


应用案例

  1. 将散列表用于查找
    手机都内置了方便的电话簿,其中每个姓名都有对应的电话号码。假设你要创建一个类似这样的电话簿,将姓名映射到电话号码。该电话簿需要提供如下功能。
  • 添加联系人及其电话号码。
  • 通过输入联系人来获悉其电话号码。
  • 创建映射。
  • 查找。
phone_book=dict()	//新建一个散列表,phone_book={},与phone_book=dict()等效
phone_book["jenny"]=8675309
phone_book["emergency"]=911
print(phone_book["jenny"])
>>>8675309

DNS解析(DNS resolution)
散列表能让你能够轻松地模拟映射关系。散列表被用于大海捞针的查找。例如你在访问http://adit.io这样的网站,计算机必须将adit.io转换成IP地址。
ADIT.IO→173.255.248.55
无论你访问哪个网站,其网址都必须转换成IP地址。
GOOGLE.COM→74.125.239.133
FACEBOOK.COM→173.252.120.6
SCRIBD.COM→23.235.47.175
DNS解析(DNS resolution),散列表是提供这种功能的方式之一。

  1. 防止重复

假设你负责管理一个投票站。显然,每人只能投一票,但如何避免重复投票呢?有人来投票时,你询问他的全名,并将其与已投票者名单进行比对。如果名字在名单中,就说明这个人已经投过票了,因此将他拒之门外!否则,就将他的姓名加入到名单中,并让他投票。现在假设有很多人来投过了票,因此名单非常长。每次有人来投票时,你都得浏览这个常常的名单,以确定他是否投过票。但有一种更好的办法,就是用散列表。

voted={}					//创建一个散列表,记录已投票的人
def check_voter(name):
	if voted.get(name):		//name在散列表中,返回value
		print("kick them out ! ")
	else:					//name在散列表中,返回None
		voted[name]=True
		print("let them vote ! ")

>>>check_voter("tom")
>let them vote ! 
>>>check_voter("mike")
>let them vote ! 
>>>check_voter("mike")
>kick them out ! 

//value=voted.get("tom")
//如果"tom"在散列表中,函数get将返回它;否则返回None
  1. 将散列表用作缓存
    散列表在缓存方面的应用。
    ① 你将Facebook服务器发出请求。
    ② 服务器作出处理,生成一个网页并将其发送给你。
    ③ 你获取一个网页。
    如果你登录了Facebook,你看到的所有内容都是为你定制的。你每次访问facebook.com,其服务器都须考虑你感兴趣什么内容。如果你没有登录,看到的将是登录页面。每个人看到的登录页面都相同。Facebook被反复要求做同样的事情:“当我注销时,请向我显示主页。”有鉴于此,它不让服务器去生成主页,而是将主页储存起来,并在需要时将其直接发送给用户。
    这就是缓存,具有以下两个优点:
  • 用户能够更快看到网页,就像你记住了月球与地球之间的距离一样,下次你侄女再问你时,你就不用再使用Google搜索,立刻就可以告诉她答案。
  • Facebook需要做的工作更少。

缓存是一种常用的加速方式,所有大型网站都使用缓存,而缓存的数据则存储在散列表中。

具体代码如下:

cache={}

def get_page(url):
	if cache.get(url):
		return cache(url)<------------------返回缓存中的数据
	else:
		data=get_data_from_server(url)
		cache[url]=data<----------------先将数据保存在缓存中
		return data

仅当URL不在缓存中时,你才让服务器做些处理,并将处理生成的数据存储到缓存中,再返回它。当下次有人请求该URL时,你就可以直接发送缓存中的数据,而不用再让服务器进行处理了。

你几乎根本不用自己去实现散列表,因为你使用的编程语言提供了散列表实现。你可使用Python提供的散列表,并假定能够获得平均情况下的性能。


算法图解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值