欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第1节 数据结构和算法基础

程序员文章站 2022-05-23 11:10:05
...

本笔记是传智播客python就业班的《数据结构与算法》。为了理解各种结构而来。

1 算法引入

如果将最终写好运行的程序比作战场,我们码农便是指挥作战的将军,而我们所写的代码便是士兵和武器。
那么数据结构和算法是什么?答曰:兵法!

1.1 引例

例子:
如果 a+b+c=1000,且 a^2 + b^2 = c^2(a,b,c 为自然数),如何求出所有a、b、c可能的组合?

第一次尝试:

# 注意是三重循环
for a in range(0, 1001):
    for b in range(0, 1001):
        for c in range(0, 1001):
            if a**2 + b**2 == c**2 and a+b+c == 1000:
                print("a, b, c: %d, %d, %d" % (a, b, c))

这种方式很笨,但是这就是算法,无关语言。

1.2 算法的定义

引出算法的定义:算法是独立存在的一种解决问题的方法和思想。

算法的五大特性
1. 输入: 算法具有0个或多个输入
2. 输出: 算法至少有1个或多个输出
3. 有穷性: 算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成
4. 确定性:算法中的每一步都有确定的含义,不会出现二义性
5. 可行性:算法的每一步都是可行的,也就是说每一步都能够执行有限的次数完成

1.3 改进算法的思路

算法题一般有两种解法,笨法和聪明解法。一般来说面试的最佳状态是:
1. 你读懂题目,按照要求写出了笨法。
2. 面试官给你小小的提示;
3. 你写出聪明方法。

这样,你和面试官都有很大的满足感,面试一般就ok了。

我们来看具体的这道题目:我们知道 a+b+c=1000。那么 c = 1000 - a - b,就不用再三层遍历了。 这样会节省很多时间,改进如下:

# 注意是两重循环
for a in range(0, 1001):
    for b in range(0, 1001-a):
        c = 1000 - a - b # 按照题目要求得出。
        if a**2 + b**2 == c**2:
            print("a, b, c: %d, %d, %d" % (a, b, c))

2 时间复杂度

2.1 算法效率衡量O(n)

实现算法程序的执行时间可以反应出算法的效率,即算法的优劣,可以用“时间复杂度T(n”和“空间复杂度”两个概念来衡量。

我们假定计算机执行算法每一个基本操作的时间是固定的一个时间单位,那么有多少个基本操作就代表会花费多少时间单位。一半包括三种程序运算:
1. 顺序结构
2. 判断(分支)
3. 循环

时间复杂度的几条基本计算规则
1. 基本操作,即只有常数项,认为其时间复杂度为O(1)
2. 顺序结构,时间复杂度按加法进行计算
3. 循环结构,时间复杂度按乘法进行计算
4. 分支结构,时间复杂度取最大值
5. 判断一个算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略
6. 在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度

2.2 在本题中的时间复杂度

在本题中:

第一次笨法尝试的算法核心部分:

T(n) = O(n*n*n) = O(n3)

第二次尝试的算法核心部分

T(n)= n * n * ( 1 + max(1,0) ) 
      = 2 * n^2 
      = O(n^2)

2.3 常见时间复杂度

第1节 数据结构和算法基础

常见时间复杂度之间的关系:

所消耗的时间从小到大

O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)

如图:

第1节 数据结构和算法基础

3 Python列表和字典

  1. 列表和字典不是基本数据类型,它是容器。
  2. 测试pop操作:从结果可以看出,pop最后一个元素的效率远远高于pop第一个元素

    • list内置操作的时间复杂度

第1节 数据结构和算法基础

少用+号、

  • dict内置操作的时间复杂度

第1节 数据结构和算法基础

4 数据结构引入

4.1 算法与数据结构的区别

算法的重点是解决问题的思路,而数据结构只是静态的描述了数据元素之间的关系。

总结:算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体

4.2 概念

比如:

我们如何用Python中的类型来保存一个班的学生信息? 如果想要快速的通过学生姓名获取其信息呢?

实际上当我们在思考这个问题的时候,我们已经用到了数据结构。

列表和字典都可以存储一个班的学生信息,但是想要在列表中获取一名同学的信息时,就要遍历这个列表,其时间复杂度为O(n),而使用字典存储时,可将学生姓名作为字典的键,学生信息作为值,进而查询时不需要遍历便可快速获取到学生信息,其时间复杂度为O(1)。

在上面的问题中我们可以选择Python中的列表或字典来存储学生信息。列表和字典就是Python内建帮我们封装好的两种数据结构。

而有些数据组织方式,Python系统里面没有直接定义,需要我们自己去定义实现这些数据的组织方式,这些数据组织方式称之为Python的扩展数据结构,比如栈,队列等。

4.3 抽象数据类型(Abstract Data Type)

抽象数据类型(ADT)的含义是指一个数学模型以及定义在此数学模型上的一组操作。即把数据类型和数据类型上的运算捆在一起,进行封装。

引入抽象数据类型的目的是把数据类型的表示和数据类型上运算的实现与这些数据类型和运算在程序中的引用隔开,使它们相互独立。

最常用的数据运算有五种:

  1. 插入
  2. 删除
  3. 修改
  4. 查找
  5. 排序