数据结构
定义
- 官方定义:数据元素不是孤立存在的,它们之间存在着某种关系,数据元素相互之间的关系称为结构(Structure)。
- 简单来说:元素按照什么样的方式组织和保存起来,就叫做数据结构。例如:身份信息可以通过列表,元组,字典的方式存储。列表,元组,字典就是一些Python封装的高级数据结构。
分类
- 逻辑结构(研究对象的特性及其相互之间的关系):
- 划分方法一:
{(1)线性结构:只有一个直接前趋和一个直接后继。例如:线性表、栈、队列、串(2)非线性结构:一个结点可能有多个直接前趋和直接后继。例如:树、图\begin{cases} (1) 线性结构:\\ 只有一个直接前趋和一个直接后继。 例如: 线性表、栈、队列、串\\ (2) 非线性结构:\\ 一个结点可能有多个直接前趋和直接后继。 例如: 树、图 \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧(1)线性结构:只有一个直接前趋和一个直接后继。例如:线性表、栈、队列、串(2)非线性结构:一个结点可能有多个直接前趋和直接后继。例如:树、图
- 划分方式二——四类基本逻辑结构:
{(1)集合结构:除了同属于一个集合的关系外,无任何其它关系。(2)线性结构:存在着一对一的线性关系。(3)树形结构:存在着一对多的层次关系。(4)图状结构或网状结构:数据元素之间存在着多对多的任意关系。\begin{cases} (1)集合结构:除了同属于一个集合的关系外,无任何其它关系。\\ (2)线性结构:存在着一对一的线性关系。\\ (3)树形结构:存在着一对多的层次关系。\\ (4)图状结构或网状结构:数据元素之间存在着多对多的任意关系。 \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧(1)集合结构:除了同属于一个集合的关系外,无任何其它关系。(2)线性结构:存在着一对一的线性关系。(3)树形结构:存在着一对多的层次关系。(4)图状结构或网状结构:数据元素之间存在着多对多的任意关系。
- 存储结构(有效地组织计算机存储)
{顺序存储:数组一个接着一个链式存储:数据同时存储指针地址索引存储:附加索引表(目录)散列存储:关键字直接计算\begin{cases} 顺序存储:数组一个接着一个\\ 链式存储:数据同时存储指针地址\\ 索引存储:附加索引表(目录)\\ 散列存储:关键字直接计算 \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧顺序存储:数组一个接着一个链式存储:数据同时存储指针地址索引存储:附加索引表(目录)散列存储:关键字直接计算
算法
定义
求解方法和步骤: 算法就是解决问题的方法和步骤。
为了实现目的,将思想用计算机实现的过程。
算法时间复杂度
- 为了便于比较不同算法的时间效率,我们仅比较它们的数量级,只关注操作数量的最高次项。
(1)渐进函数:T(n)=k∗g(n)+cT(n)=k*g(n)+cT(n)=k∗g(n)+c
含义:k只反映图像的陡峭程度,忽略k,近似的反应时间复杂度
(2)大O表示法:g(n); 忽略其他因素,只关注数量级
(3)最坏时间复杂度(最常用):指在最坏情况下,算法的时间复杂度。不考虑最优时间复杂度和平均时间复杂度
时间复杂度计算基本准则
- 基本准则
- 顺序结构,时间复杂度按加法进行计算
- 循环结构,时间复杂度按乘法进行计算
- 分支结构:时间复杂度取最大值(if,else 哪一个多选哪个)
- 例子
for a in range(0, 1001): #重复1000遍
for b in range(0, 1001): #重复1000遍
for c in range(0, 1001):# 重复1000遍
if a**2 + b**2 == c**2 and a+b+c == 1000: #重复1遍
print("a, b, c: %d, %d, %d" % (a, b, c)) #重复1遍
时间复杂度:
T(n)=O(n∗n∗n)=O(n3)T(n) = O(n*n*n) = O(n^3)T(n)=O(n∗n∗n)=O(n3)
常见时间复杂度
| 执行次数函数举例 | 阶 |
|---|---|
| 12 | O(1) |
| 2n+3 | O(n) |
| 3n2n^2n2+2n+1 | O(n^2) |
| 5log2nlog_2nlog2n+20 | O(logn) |
| 2n+3nlog2n3nlog_2n3nlog2n+19 | O(nlogn) |
| 6n3+2n2n^3+2n^2n3+2n2+3n+4 | O(n3) |
| 2n2^n2n | O(2n2^n2n) |
所消耗的时间从小到大
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)O(1) <O(logn) <O(n) <O(nlogn) <O(n^2) <O(n^3) <O(2^n) <O(n!) <O(n^n)O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
- ** 列表**
| Operation | Big-O Efficiency | comprehension |
|---|---|---|
| index[] | O(1) | 索引的取值不是从头遍历,而是一步找到 |
| index assignment | O(1) | 索引方式赋值,一步 |
| append | O(1) | 队尾加,一步 |
| pop() | O(1) | 队尾删,一步 |
| pop(i) | O(n) | 从指定位置,最坏的可能是第一个,需要遍历整个列表 |
| insert(i,item) | O(n) | 同上 |
| del operator | O(n) | 清空每一个元素 |
| iteration | O(n) | 迭代 |
| contains (in) | O(n) | 判断是否存在,要遍历一遍 |
| get slice [x:y] | O(k) | 直接定位到x,从x到y中有k个元素 |
| del slice | O(n) | 删除中间位置后,将整个后面的往前移 |
| set slice | O(n+k) | 切片赋值,先删掉,遍历一遍,再赋值 |
- 字典
| Operation | Big-O Efficiency | comprehension |
|---|---|---|
| copy | O(n) | 将每个元素都复制一遍 |
| get item | O(1) | 通过key直接找到 |
| set item | O(1) | 通过key直接找到 |
| delete item | O(1) | 通过key直接找到 |
| contains (in) | O(1) | 通过key直接找到 |
| iteration | O(n) | 迭代 |
算法时间测量模块 timeit module
- Timer:是测量小段代码执行速度的类。
class timeit.Timer(stmt=‘pass’, setup=‘pass’,timer=<timer function>)
stmt: 参数是要测试的代码语句(statment);需要传一个字符串
setup:参数是运行代码时需要的设置; 从当前窗口载入
timer: 参数是一个定时器函数,与平台有关,有默认值。不用管。
timeit.Timer.timeit(number=1000000)
Timer类中测试语句执行速度的对象方法。number参数是测试代码时的测试次数,默认为1000000次。方法返回执行代码的平均耗时,一个float类型的秒数。
- 例1: 列表类型不同操作的时间效率
from timeit import Timer #从timeit模块中载入Timer
def t1():
li=[]
for i in range(10000):
li.append(i)
def t2():
li = []
for i in range(10000):
li+=[i]
def t3():
li = [i for i in range(10000)] #列表生成器
def t4():
li=list(range(10000))
def t5():
li=[]
for i in range(10000):
li.extend(10000)
#从当前窗口载入,窗口名称默认为是__mian__
timer1= Timer("t1","from __main__ import t1") # __main__前后都有空格
print("append:", timer1.timeit(1000))
timer2= Timer("t2","from __main__ import t2") ,
print("+:",timer2.timeit(1000))
timer3= Timer("t3","from __main__ import t3")
print("i for i in range:",timer3.timeit(1000))
timer4= Timer("t4","from __main__ import t4")
print("list(range()):",timer4.timeit(1000))
timer5= Timer("t5","from __main__ import t5")
print("list(range()):",timer5.timeit(1000))
--------------------------------------
append: 4.935400000000145e-05
+: 1.8091999999997332e-05
i for i in range: 1.8264000000003944e-05
list(range()): 1.7505000000000992e-05
list(range()): 2.4399000000008275e-05
疑难解答
Q1: 为什么不用时间表示时间效率?
算然对于不同的机器环境而言,确切的单位时间是不同的,但是对于算法进行多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的,由此可以忽略机器环境的影响而客观的反应算法的时间效率。
Q2:N是什么?
代表问题的基本规模
例如:
# 迭代1000次和迭代2000次在本质上只是循环重复的次数不同,在计算时间复杂度时,引入N代表1000,2000或更多,使之有一种统一的表示
for a in range(0, 1001): # 重复1000次
for a in range(0, 2001): # 重复2000次
for a in range(0, n): # 重复n次
本文详细阐述了数据结构的基础概念,包括逻辑结构(线性、非线性、集合、线性关系、层次与网状结构)和存储结构(顺序、链式、索引、散列)。此外,介绍了算法的定义、时间复杂度分析,以及列表和字典操作的时间效率实例。通过timeit模块演示了不同操作的性能对比。

被折叠的 条评论
为什么被折叠?



