文章目录
数据结构与算法
数据结构
数据结构和算法的关系类似于图书馆和图书管理员,相互依靠,缺一不可,一个庞大的图书馆如果没有一个有能力的管理员(算法)和完善的图书摆放规则(数据结构)将会难以高效的找到目标书籍并且难以维护。
Python并不像c一样,所有数据结构都需要自己去编写,Python给开发者提供了几种非常常用的数据结构。
- 列表(list)
- 字典(dict)
- 元组(tuple)
- 集合(set)
算法
算法是解决问题的一种思想和方式,算法的实际就是告诉计算机应该在什么时候做什么事情,就好比古时打仗用的策略,告诉军队什么时候已什么方式进攻撤退,好的策略能做到以少胜多,以弱胜强,好的算法他让程序能更加简洁高效的执行。
算法的性质:有穷性,可行性,确定性,且有输入和输出。
- 有穷性:这里的有穷性不仅代表的是算法不会出现死循环,并且要在可接受的时间内计算完成。
- 可行性:代码必须使可行的,不会出现死循环这种类型的意外。
- 确定性:算法中每行代码都是确定的,不会出现多种意义造成不确定性。
- 输入和输出:算法中可以不输入或是输入多个值,但必须最少要输出一个值。没有输出值得算法是没有意义的。## 程序执行时间
查看程序的运行时间我们就可以直观的看出程序的速度。但程序执行的速度快慢并不一定就代表了程序的好坏。
程序执行时间不仅受到算法好坏的影响,还受到电脑性能以及处理的数据量影响。
大O表示法(时间复杂度)
时间复杂度用来判断和对比程序算法的工具,但是通过时间复杂度,我可以通过肉眼就能直观的看出算法的优劣。
T(n)=O(f(n))
符合 | 含义 |
---|---|
T(n) | 代码执行时间 |
n | 数据规模 |
f(n) | 代码执行次数总和 |
O | 正比 |
1. 大O表示法只关注循环次数最多的一段代码,总复杂度为量级最大的一段,而不是每段相加。
2. 一般我们只看最坏时间复杂度最优时间复杂度和平均时间复杂度参考意义较小。
阶 | 非正式术语 |
---|---|
常数阶 | O(1) |
线性阶 | O(n) |
平方阶 | O(n2) |
对数阶 | O(logn) |
nlogn阶 | O(nlogn) |
指数阶 | O(2n) |
最坏时间复杂度
算法完成操作最多需要多少基本操作。在最坏的情况下查看程序是否能完成工作,用于提供一种保证。
time模块
time模块是Python内置模块之一,可以用它来直观的查看程序的执行时间。只看程序执行速度的快慢无法判断一个程序算法的好坏。运行速度会受到硬件和处理的数据影响
import time
start = time.time()
li = list(range(1000))
print(li)
end = time.time()
print('程序运行的时间为:', end - start)
timeit模块
timeit模块同样也是Python的内置模块,这个模块相对于time来说上手难度较高,但是对测试程序运行时间来说更加方便。
使用方法
- 直接调用timeit:
timeit(stmt=“pass”, setup=“pass”, timer=default_timer, number=default_number, globals=None)
timeit | 是测量小段代码执行速度的一个类 |
---|---|
stmt | 要测试的代码语句 |
setup | 运行代码时需要的设置 |
timer | 定时器函数,于平台有关 |
number | 测试的次数(默认测试一百万次)返回测试总时间值,并不是平均值 |
n():
li1 = list(range(10000))
print(li1)
t = timeit.timeit('fn()', 'from __main__ import fn', number=10)
print(t)
- 使用Timer方法间接调用,Timer是timerit中的一个方法,也有timeit中的stmt,setup,timer等属性,但是并不能传number测试次数,测试次数需要在实例化调用时传入。
def fn():
li1 = list(range(10000))
print(li1)
t = timeit.Timer('fn()', 'from __main__ import fn')
print(t.timeit(10))
测试Python内置的列表和字典结构
列表
用不同的方式创建一个包含所以四位一下的整数
# 不同的方法创建一个包含0到999的序列
def fn1():
li1 = list(range(1000))
def fn2():
li2 = []
i = 0
while i < 1000:
li2.append(i)
i += 1
def fn3():
li3 = []
for i in range(1000):
li3.append(i)
def fn4():
li4 = []
i = 0
while i < 1000:
li4.append(i)
i = i + 1
def fn5():
li5 = []
for i in range(1000):
li5.append(i)
def fn6():
li6 = []
for i in range(1000):
li6 += [i]
def fn7():
li7 = []
for i in range(1000):
li7 = li7 + [i]
def fn8():
li8 = [i for i in range(1000)]
a = 1
while a <= 8:
t = timeit.Timer(f'fn{a}()', f'from __main__ import fn{a}')
print(f'fn{a}的执行时间为', t.timeit(10000))
a += 1
fn1的执行时间为 0.0796674
fn2的执行时间为 0.8380289
fn3的执行时间为 0.506642
fn4的执行时间为 0.8352526999999998
fn5的执行时间为 0.5292444000000001
fn6的执行时间为 0.5967790000000002
fn7的执行时间为 9.032878199999999
fn8的执行时间为 0.2779138999999997
字典
# 做一个key为0~999的整数,value为0~999的字符的字典
def fn1():
lis = [str(i) for i in range(1000)]
dic = dict(enumerate(lis))
def fn2():
dic = {}
i = 0
while i < 1000:
dic[i] = str(i)
i += 1
def fn3():
i = 0
dic = dict.fromkeys(list(range(1000)))
while i < 1000:
dic[i] = str(i)
i += 1
a = 1
while a <= 4:
t = timeit.timeit(f'fn{a}()', f'from __main__ import fn{a}', number=1000)
print(t)
a += 1
fn1: 0.1935567
fn2: 0.22425840000000002
fn3: 0.2588895
Python内置数据结构
使用内置的sys库中getsizeof方法可以查看数据占据的字节数!
int_empty = int()
int1 = 1
str_empty = str()
str1 = '1'
bool_empty = bool()
bool1 = True
float_empty = float()
float1 = 1.0
list_empty = list()
list1 = [1]
tuple_empty = tuple()
tuple1 = (1,)
dict_empty = dict()
dict1 = {1: 1}
set_empty = set()
set1 = {1}
print(type(int1), '整数型初始占用字节:', sys.getsizeof(int_empty), ',存入的数据占用:', sys.getsizeof(int1) - sys.getsizeof(int_empty))
print(type(str1), '字符型初始占用字节:', sys.getsizeof(str_empty), ',存入的数据占用:', sys.getsizeof(str1) - sys.getsizeof(str_empty))
print(type(bool1), '布尔型初始占用字节:', sys.getsizeof(bool_empty), ',存入的数据占用:', sys.getsizeof(bool1) - sys.getsizeof(bool_empty))
print(type(float1), '浮点型初始占用字节:', sys.getsizeof(float_empty), ',存入的数据占用:', sys.getsizeof(float1) - sys.getsizeof(float_empty))
print(type(list1), '列表初始占用字节:', sys.getsizeof(list_empty), ',存入的数据占用:', sys.getsizeof(list1) - sys.getsizeof(list_empty))
print(type(tuple1), '元组初始占用字节:', sys.getsizeof(tuple_empty), ',存入的数据占用:', sys.getsizeof(tuple1) - sys.getsizeof(tuple_empty))
print(type(dict1), '字典初始占用字节:', sys.getsizeof(dict_empty), ',存入的数据占用:', sys.getsizeof(dict1) - sys.getsizeof(dict_empty))
print(type(set1), '数组初始占用字节:', sys.getsizeof(set_empty), ',存入的数据占用:', sys.getsizeof(set1) - sys.getsizeof(set_empty))
输出的结果如下
<class ‘int’> 整数型初始占用字节: 24 ,存入的数据占用: 4
<class ‘str’> 字符型初始占用字节: 49 ,存入的数据占用: 1
<class ‘bool’> 布尔型初始占用字节: 24 ,存入的数据占用: 4
<class ‘float’> 浮点型初始占用字节: 24 ,存入的数据占用: 0
<class ‘list’> 列表初始占用字节: 56 ,存入的数据占用: 8
<class ‘tuple’> 元组初始占用字节: 40 ,存入的数据占用: 8
<class ‘dict’> 字典初始占用字节: 232 ,存入的数据占用: 0
<class ‘set’> 数组初始占用字节: 216 ,存入的数据占用: 0