读书笔记:算法图解 using Python
![](https://i-blog.csdnimg.cn/blog_migrate/86d85285b186d2b92ac01441585b6d14.jpeg)
阅读书目:[美] Aditya Bhargava. “算法图解”
写在前面:
作者称自己是“视觉型学习者,对图解式写作风格钟爱有加”。这一点和我学东西的思维方式很想,对作者很有好感。事实上在阅读过程中也感到很愉快,有些类似近藤麻理惠《怦然心动的人生整理魔法》的图解和讲解方式,深入浅出,常看常新。
阅读这本书主要是想帮自己回忆上课学过的数据结构和算法的相关内容,希望帮自己建立起形象的体系和深刻的理解。此外,当时上课是基于C/C++,这次学习数据结构和算法希望能基于Python实现,为之后的刷题道路铺路。
目录
ch1 算法简介
二分查找
# 二分查找
# lst为有序数组,若item存在lst中则返回下标,否则返回-1
def binary_search(lst, item):
# 查找的下标范围
low = 0
high = len(lst) - 1
while low <= high:
# 每次查找中间的元素
mid = (low + high) // 2 # 向下取整
guess = lst[mid]
if guess == item:
return mid
elif guess < item: # 如果猜的数字小了,修改low
low = mid + 1
else: # 如果猜的数字大了,修改high
high = mid - 1
return -1
>>> lst = [1,4,5,6,8,13,15,61,543]
>>> binary_search(lst, 8)
4
>>> binary_search(lst, 9)
-1
二分查找的时间复杂度为 O ( log n ) O(\log n) O(logn)。
大O表示法
介绍了大O表示法的含义和目的,结合图像和实际问题说明了不同时间复杂度之间的差异。
ch2 选择排序
数组和链表
- 内存上的差异:计算机内存犹如一大堆抽屉。
- 数组的元素都在一起。
- 链表的元素是分开的,其中每个元素都存储了下一个元素的地址。
- 常见操作的运行时间:读取/插入/删除,要根据实例的操作需求选择数据结构。
- 数组的读取速度很快。/ 数组擅长随机访问。
- 链表的插入和删除速度很快。/ 链表擅长插入和删除。
- 练习:Facebook如何存储用户名?
选择排序
# 找出数组中最小元素
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_index = findSmallest(arr)
newArr.append(arr.pop(smallest_index))
return newArr
>>> selectionSort([5, 3, 6, 2, 10])
[2, 3, 5, 6, 10]
选择排序的运行时间为 O ( n 2 ) O(n^2) O(n2)。
ch3 递归
递归
递归
是指函数调用自己。
递归只是让解决方案更清晰,并没有性能上的优势。实际上,在有些情况下,使用循环的性能更好。
编写递归函数时,必须告诉它何时停止递归。
递归条件 recursive case
:函数调用自己基线条件 base case
:函数不再调用自己
从而避免形成无限循环。
调用栈 call stack
栈有两种操作:压入和弹出。
计算机在内部使用被称为调用栈
的栈。这个栈用于存储多个函数的变量。所有函数调用都进入调用栈。
栈在递归中扮演着重要角色。使用栈虽然很方便,但是也要付出代价:存储详尽的信息可能占用大量的内存。调用栈可能很长,这将占用大量的内存。在这种情况下,你有两种选择。
-
重新编写代码,转而使用循环。
-
使用
尾递归
。这是一个高级递归主题,不在本书的讨论范围内。另外,并非所有的语言都支持尾递归。
ch4 快速排序
快速排序采用了分而治之的策略。
我们将探索分而治之 (divide and conquer,D&C)
——一种著名的递归式问题解决方法。
分治
D&C将问题逐步分解。使用D&C处理列表时,基线条件很可能是空数组或只包含一个元素的数组。
- 一个直观的示例:农场主的土地划分
- 一个代码的示例:函数
sum(lst)
的实现原理 - 快速排序
# 练习4.1: 请编写前述sum 函数的代码。
def my_sum(lst):
if not lst: return 0
return lst[0] + my_sum(lst[1:])
>>> my_sum([1,2,3,4,5])
15
# 练习4.2: 编写一个递归函数来计算列表包含的元素数。
def my_count(lst):
if not lst: return 0
return 1 + my_count(lst[1:])
>>> my_count([1,2,3,4,5])
5
# 练习4.3: 找出列表中最大的数字。
def