一、算法入门
程序设计 = 数据结构 + 算法
算法时为了解决实际问题而设计的,数据结构是算法需要处理的问题载体
数据结构只是静态的描述呢数据元素之间的关系
高效的程序需要再数据结构的基础上设计和选择算法
1. 数据结构
1.1 数据结构存在的意义
如果用Python的类型来保存一个班学生的信息,并如何通过学生姓名快速获取其信息呢?
Python中的列表和字典均可以来存储学生信息。
列表存储:获取一名学生的信息时,就要遍历这个列表,其时间复杂度为O(n);
字典存储:可以将学生姓名作为字典的键,学生信息作为值,查询直接使用键获取值,其时间复杂度为O(1)
明显的字典存储的数据结构数据的处理效率更高,数据存储方式(即数据结构)越优化,算法处理时效率越高。
1.2 数据结构概念
数据结构:数据元素相互之间存在的一种或多种特定关系的集合(数据结构指数据对象中数据元素之间的关系)。数据结构分为逻辑结构和物理结构。
逻辑结构:是指数据对象中数据元素之间的相互关系。
(1)集合结构:数据元素除了同属于一个集合外,没有什么其他关系
(2)线性结构:线性结构中的数据元素之间是一对一的关系
(3)树形结构:元素之间存在一种一对多的层次关系
(4)图形结构:元素是多对多的关系
物理结构:是指数据的逻辑结构在计算机中的存储形式。
(1)顺序存储:把数据元素存放在地址连续的存储单元你,其数据间的逻辑关系和物理关系是一致的
(2)链式存储:把数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以是不连续的。链式存储结构的数据元素存储关系不能反映其逻辑关系,需要用一个指针存放数据元素的地址,这样通过地址就可以找到相关数据元素的位置。
Python的数据结构分两种:
内置数据结构:列表、元组、字典等
扩展数据结构:Python系统里面没有直接定义,需要我们自己取定义实现这些数据的组织方式,如栈、队列等
1.3 抽象数据类型
抽象数据类型(Abstract Data Type):把数据类型和数据类型上的运算捆在一起,进行封装。
引入抽象数据类型目的是把数据类型的表示和数据类型上运算的实现与这些数据类型和运算在程序中引用隔开,使他们相互独立。常见的物种数据运算:
插入
删除
修改
查找
排序
2. 算法
算法:是独立存在(不依赖特定的编程语言)的一种解决问题的方法和思想。算法有五大特性:
(1)输入:算法有0个或多个输入
(2)输出:算法至少有一个或多个输出
(3)有穷性:算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成
(4)确定性:算法中的每一步都有确定的含义,不会出现二义性
(5)可行性:算法的每一步都是能够执行有限次数完成的
程序在每台机器执行的总时间不同,但是执行基本运算数量大致相同。
2.1 最坏时间复杂度
时间复杂度:假设存在函数g,使得算法A处理规模为n的问题所用时间为T(n)=O(g(n)),则O(g(n))为算法A的奖金时间复杂度,简称时间复杂度,记为T(n)
最优时间复杂度:算法完成工作最少需要多少基本操作 --- 没有什么参考价值
* 最坏时间复杂度:算法完成工作做多需要多少基本操作 --- 基本操作都能完成
平均时间复杂度:算法完成工作平均需要多少基本操作
2.2 时间复杂度计算规则
1. 基本操作:只有常数项,认为其时间复杂度为O(1)
2. 顺序结构:时间复杂度按加画进行计算
3. 循环结构:时间复杂度按惩罚进行计算
4. 分支结构:时间复杂度取最大值
5. 判断一个算法的效率时,只需要关注操作数量的最高次项,其他次要项和参数项可以忽略
6. 在没有特殊说明时,我们所分析的时间复杂度指的是 最坏时间复杂度
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : 01_abc.py
@Time : 2019/10/22 12:18
@Author : Crisimple
@Github : https://crisimple.github.io/
@Contact : Crisimple@foxmail.com
@License : (C)Copyright 2017-2019, Micro-Circle
@Desc : 如果 a + b +c = 1000 且 a**2 + b**2 = c**2(a, b, c均为自然数),求解a, b, c的所有组合
"""
import time
start_time = time.time()
print("程序开始执行时间: %s" % start_time)
# 算法一
# 时间复杂度:
# T(n) = O(n*n*n) = O(n**3)
for a in range(1001):
for b in range(1001):
for c in range(1001):
if a + b + c == 1000 and a**2 + b**2 == c**2:
print("a, b, c: %d, %d, %d" % (a, b, c))
# 算法二
for a in range(1001):
for b in range(0, 1001):
c = 1000 - a - b
if a**2 + b**2 == c**2:
print("a, b, c: %d, %d, %d" % (a, b, c))
# 算法三
# 时间复杂度:
# T(n) = O(n*n(1+1))) = O(n**2)
for a in range(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))
end_time = time.time()
print("程序执行结束时间: %s" % end_time)
all_times = end_time - start_time
print("总耗时all_times: %s" % all_times)
print("执行完毕!")
2.3 常见时间复杂度
非正式术语
执行次函数
时间复杂度
常数阶
12
O(1)
线性阶
2n + 3
O(n)
平方阶
3n**2+3n+2
O(n**2)
对数阶
5log2n+20
O(logn)
nlogn阶
2n+3nlog2n+19
O(nlogn)
立方阶
6n**3 + 2n **2+3n+4
O(n**3)
指数阶
2**n
O(2**n)
所消耗的时间从小到大:
O(1) < O(logn) < O(n) < O(nlogn) < O(n **2) < O(n **3) < O(2 **n) < O(n!) < O(n **n)
2.4 Python内置类型性能分析
timeit模块可以用来测试一小段Python代码的执行速度。class timeit.Timer(stmt='pass', setup='pass', timer=)
Timer是测量小段代码执行速度的类。
stmt参数是要测试的代码语句(statment);
setup参数是运行代码时需要的设置;
timer参数是一个定时器函数,与平台有关。
timeit.Timer.timeit(number=1000000)
Timer类中测试语句执行速度的对象方法。number参数是测试代码时的测试次数,默认为1000000次。方法返回执行代码的平均耗时,一个float类型的秒数。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : 202_timeit.py
@Time : 2019/10/22 19:27
@Author : Crisimple
@Github : https://crisimple.github.io/
@Contact : Crisimple@foxmail.com
@License : (C)Copyright 2017-2019, Micro-Circle
@Desc : None
"""
# class timeit.Timer(stmt='pass', setup='pass', timer=)
# Timer是测量小段代码执行速度的类。
# stmt参数是要测试的代码语句(statment);
# setup参数是运行代码时需要的设置;
# timer参数是一个定时器函数,与平台有关
# timeit.Timer.timeit(number=1000000)
# Timer类中测试语句执行速度的对象方法。number参