《算法图解》笔记

爷,独闯天下 提交于 2020-03-09 03:38:22

看书还得写笔记,文字的写不来,还是写电子的,自己的字跟狗爬一样,打出来的字好多了。

后续把自己看的基本关于网络的书也写点博客,一便于查寻,二便于加强记忆,要不然跟小说一样,看了就忘了。

 

第1章:算法介绍

理解大O表示法,并非以秒为单位。大O表示法让你能够比较操作数,它指出了算法运行时间的增速。

 

大O表示法说的是在查找情况中最糟的情形。

从快到慢晕倒的5种大O运行时间。

O(log n),也叫对数时间,这样的算法包括二分查找。

O(n), 也叫线性时间,这样的算法包括简单查找。

O(n * log n),这样的算法包括快速排序---一种比较快的排序算法

O(n2)【表示n的平方】, 这样的算法包括选择排序---一种速度较慢的排序算法

O(n!), 这样的算法包括旅行商的解决方案---一种非常慢的算法

 

第一章主要理解:

算法的速度指的并非时间,而是操作数的增速。

讨论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。

算法的运行时间用大O表示法表示。

O(log n)比O(n)快,当需要搜索的元素越多时,前者比后者快很多。

 

小结:

二分查找的速度比简单查找快很多。

O(logn)比O(n)快。需要搜索的元素越多,前者比后者就快得更多

算法运行时间并不以秒为单位。

算法运行时间是从其增速的角度度量的。

算法运行时间用大O表示法表示

 

最后上书中的二分查找代码

def binary_search(list, item):
    # 初始化序列的开始序列号,为末尾的序列号
    low = 0
    high = len(list) - 1
    # 只有在开始的序列号小于等于结束的序列号,才执行2分,否则就是找不到元素
    while low <= high:
        # 地板除取出中间值
        middle = (low + high) // 2
        # 取出中间值的值
        guess = list[middle]
        # 如果是的话,就返回这个索引
        if guess == item:
            return middle
        # 当取出来的中间值比要帅选的值大,按取出来中间值的前一位索引就是下一次寻找的结尾。
        elif guess > item:
            high = middle - 1
        # 反之,下一次查找的开始索引中间值的后一位索引,这里我还是比较容易搞混的
        else:
            low = middle + 1
    return None


if __name__ == '__main__':
    print(binary_search('123456', '2'))

 

第2章 选择排序

主要学习数组与链表

数组与链表的运行时间

        数组    链表

读取   O(1)   O(n)

插入    O(n)   O(1)

删除     O(n)   O(1)

 

这里指出一下,仅当能够立即访问要删除的元素时,删除操作的运行时间才为O(1)。通常我们都记录了链表的第一个元素和最后一个元素,因此删除这些元素时运行时间为O(1)

 

选择排序的时间:O(n2)【表示n的平方】

小结:

计算机的内存犹如一大堆抽屉。

需要存储多个元素时,可使用数组或者链表

数组的元素都在一起

链表的元素是分开的,其中每个元素都存储了下一个元素的地址

数组的读取速度很快

链表的插入和删除速度很快

在同一个数组中,所有元素的类型都必须相同(都为int,double等)

 

代码:

这是我自己写的:

def my_sort(arr):
    # 首相取选址范围,从大到小取,最大为最大索引,最小为0
    for i in range(len(arr) - 1, -1, -1):
        # 开始循环对数组的数据进行比较
        for i in range(i):
            # 如果前面的数字大于后面的数字,两个数字互相,确保后面的数字大
            if arr[i] > arr[i + 1]:
                arr[i], arr[i + 1] = arr[i + 1], arr[i]
    return arr


if __name__ == '__main__':
    print(my_sort([9, 3, 33, 3, 2, 1, 5, 6]))

 

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

if __name__ == '__main__':
    print(selectionSort(list('6754345678987654')))

 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

我写的不用额外占用内存空间,书中的代码还是需要额外新建一个新列表,但书中的代码更加容易理解,而且逻辑也很漂亮

 

第三章 递归

递归时我最讨厌的主题,希望书中学完,能够让我爱上它一点

 

实际使用中,使用循环的性能更好。高手在Stark Overflow上说过:如果使用循环,程序的性能可能更高;如果使用递归,程序可能更容易理解。如何选择要看什么对你来说更重要

 

每个递归函数都有两部分组成:基线条件(base case)和递归条件(recursive case)。递归条件指的是函数调用自己,而基线条件则指的是函数不再调用自己,从而避免形成无限循环。

书中举例了一个好简单的例子,真的很基础,但讲的不错。

def fact(x):
    if x == 1:
        return 1
    else:
        return x * fact(x-1)

 注意每个fact调用都有自己的x变量。在一个函数中不能访问另一个x变量

书p39页,结合盒子的例子。这个栈包含未完成的函数调用,每个函数调用都包含未检查完的盒子。使用栈很方便,因为你无需自己跟踪盒子堆-栈替你这样做了。

原来Python确实有递归次数限制,默认最大次数为998

 

小结:

递归指的是调用自己的函数

每个递归函数都有两个条件:基线条件和递归条件

栈有两种操作:压入和弹出

所有函数调用都进入调用栈

调用栈可能很长,这将占用大量的内存

 

第4章 快速排序

学习分而治之和快速排序。分而治之是本书学习的第一种通用的解决方法。

学习快速排序---一种常用的优雅的排序算法。快速排序使用分而治之的策略。

 

分而治之D&G(divide and cpnquer)

工作原理:

找出基线条件,这个条件必须尽可能的简单

不断将问题分解(或者说缩小规模),直到符合基线条件

 

涉及数组的递归函数时,基线条件通常是数组为空或只包含一个元素。陷入困境时,请检查基线条件是不是这样的。

 

书中的3道编程题,没能写出来,只能抄答案了。

请编写书中要求sum函数的代码

def sum(arr):
    if len(arr) == 0:
        return 0
    # 把第一个值取出来,后面的进行递归,当只有一个元素的arr会满足基线条件
    return arr[0] + sum(arr[1:])

if __name__ == '__main__':
    print(sum(list(range(997))))

 编写一个递归函数来计算列表包含的元素数:

def count(arr):
    if arr == []:
        return 0
    return 1 + count(arr[1:])

if __name__ == '__main__':
    print(count(list(range(100))))

 跟第一个原理差不多

找出列表中最大的数字

def find_max_num(arr):
    # 当两个元素的时候,进行比较,返回最大值,基线条件
    if len(arr) == 2:
        return arr[0] if arr[0] > arr[1] else arr[1]
    # 递归条件,拆分后面索引1的元素到最后的元素进行递归条件。
    sun_max = find_max_num(arr[1:])
    return arr[0] if arr[0] > sun_max else sun_max

# 这个我自己真心写不出来,看的我都有点绕了
if __name__ == '__main__':
    print(find_max_num([1, 2, 3, 4, 99, 5]))

 

正式进入快速排序:

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!