数据结构与算法基础知识

本文详细阐述了数据结构的基础概念,包括逻辑结构(线性、非线性、集合、线性关系、层次与网状结构)和存储结构(顺序、链式、索引、散列)。此外,介绍了算法的定义、时间复杂度分析,以及列表和字典操作的时间效率实例。通过timeit模块演示了不同操作的性能对比。
摘要由CSDN通过智能技术生成

数据结构

定义

  • 官方定义:数据元素不是孤立存在的,它们之间存在着某种关系,数据元素相互之间的关系称为结构(Structure)。
  • 简单来说:元素按照什么样的方式组织和保存起来,就叫做数据结构。例如:身份信息可以通过列表,元组,字典的方式存储。列表,元组,字典就是一些Python封装的高级数据结构。

分类

  1. 逻辑结构(研究对象的特性及其相互之间的关系):
  • 划分方法一:

{ ( 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):
  1. 存储结构(有效地组织计算机存储)
    { 顺 序 存 储 : 数 组 一 个 接 着 一 个 链 式 存 储 : 数 据 同 时 存 储 指 针 地 址 索 引 存 储 : 附 加 索 引 表 ( 目 录 ) 散 列 存 储 : 关 键 字 直 接 计 算 \begin{cases} 顺序存储:数组一个接着一个\\ 链式存储:数据同时存储指针地址\\ 索引存储:附加索引表(目录)\\ 散列存储:关键字直接计算 \end{cases}

算法

定义

求解方法和步骤: 算法就是解决问题的方法和步骤。
为了实现目的,将思想用计算机实现的过程。


算法时间复杂度

  • 为了便于比较不同算法的时间效率,我们仅比较它们的数量级,只关注操作数量的最高次项

(1)渐进函数 T ( n ) = k ∗ g ( n ) + c T(n)=k*g(n)+c T(n)=kg(n)+c
含义:k只反映图像的陡峭程度,忽略k,近似的反应时间复杂度

(2)大O表示法:g(n); 忽略其他因素,只关注数量级

(3)最坏时间复杂度(最常用):指在最坏情况下,算法的时间复杂度。不考虑最优时间复杂度和平均时间复杂度

时间复杂度计算基本准则

  1. 基本准则
  • 顺序结构,时间复杂度按加法进行计算
  • 循环结构,时间复杂度按乘法进行计算
  • 分支结构:时间复杂度取最大值(if,else 哪一个多选哪个)
  1. 例子
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 ( n 3 ) T(n) = O(n*n*n) = O(n^3) T(n)=O(nnn)=O(n3)


常见时间复杂度

执行次数函数举例
12O(1)
2n+3O(n)
3 n 2 n^2 n2+2n+1O(n^2)
5 l o g 2 n log_2n log2n+20O(logn)
2n+ 3 n l o g 2 n 3nlog_2n 3nlog2n+19O(nlogn)
6 n 3 + 2 n 2 n^3+2n^2 n3+2n2+3n+4O(n3)
2 n 2^n 2nO( 2 n 2^n 2n)

所消耗的时间从小到大
O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) 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)<On)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

  • ** 列表**
OperationBig-O Efficiencycomprehension
index[]O(1)索引的取值不是从头遍历,而是一步找到
index assignmentO(1)索引方式赋值,一步
appendO(1)队尾加,一步
pop()O(1)队尾删,一步
pop(i)O(n)从指定位置,最坏的可能是第一个,需要遍历整个列表
insert(i,item)O(n)同上
del operatorO(n)清空每一个元素
iterationO(n)迭代
contains (in)O(n)判断是否存在,要遍历一遍
get slice [x:y]O(k)直接定位到x,从x到y中有k个元素
del sliceO(n)删除中间位置后,将整个后面的往前移
set sliceO(n+k)切片赋值,先删掉,遍历一遍,再赋值
  • 字典
OperationBig-O Efficiencycomprehension
copyO(n)将每个元素都复制一遍
get itemO(1)通过key直接找到
set itemO(1)通过key直接找到
delete itemO(1)通过key直接找到
contains (in)O(1)通过key直接找到
iterationO(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. 例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次        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值