Python数据结构(第1讲导论-第2讲算法分析)


如果你是大学新生,想学数据结构,最好的语言一定是 Python3

笔记来源 :
Python数据结构与算法第二版(runestone有免费英文版);
老师上课ppt;

学习步骤:
1、Python
2、Algorithm
3、Basic Data Structure

语言基础:Python

you can learn it from
by Python 教程

数据结构

第一讲:DS导论

一、抽象数据类型ADT

1、 通俗比喻:

用户相当于开车的人;
我们码农相当于组装车的人;
(那些零件就是ADT,我们只需要知道怎么用那些零件就好)
最底层的复杂的基础工作:怎么做车零件我们装的人不用知道;

请添加图片描述

二、 Python需要注意的问题

第二讲:算法分析

Algorithm: ways to solve things.

一个程序的Algorithm好坏决定因素

  1. 解决问题时要占用的空间或内存
  2. 执行所需的时间进行分析和比较

一、基准技术计算实际执行时间

由于我们不知道使用哪类函数对算法的运行时间表现进行建模,所以这个做法并没得到有用的度量;所以我们需要找到独立于所使用的程序或者计算机的算法特征。

1、举例函数

1)迭代求和

迭代解决函数:

def sumOfN(n):
theSum=0
for i in range(1,n+1):
theSum=theSum+i
return theSum
2)非迭代求和

def sumOfN3(n)利用了一个封闭的方程

#在不迭代的情况下计算n的总和 return (n*(n+1))/2
ns=np.linspace(10,10_000,100,dtype=int)
ts3=[timeit.timrit('sumOfN3(r)',setup=f'r={
      
      n}',number=1000,globals=globals()) for n in ns]
plt.plot(ns,ts3,'ob')

2、测量技术(时间、内存)

1)测量执行时间:Time 类

ps: 测试占用内存:MemoryMonitor类

例1:对累加问题sumOfN® 计算时间成本

sum运行时间变化的绘图函数:

import matplotlib.pyplot as plt
import numpy as np
import timeit
ns=np.linspace(10,10_000,100,dtype=int)#问题规模
ts=[timeit.timeit('sumOfN(r)',setup=f'r={
      
      n}',number=1000,globals=globals())for n in ns]
plt.plot(ns,ts,'or')#绘制图像:问题规模为横轴,时间成本为纵轴
#ts=[timeit.timeit('sum(r)',setup=f'r=range{n}',number=1000,globals=globals())for n in ns]

请添加图片描述

例2:sumrange(n)平均斜率得出近似拟合曲线(邻两点之间的平均斜率)
total=0
for i in range(len(ns)-1):
total+=(ts[i+1]-ts[i])/(ns[i+1]-ns[i])#	所有相邻两点之间的斜率之和
avg_slope=total/(len(ns)-1)
plt.plot(ns,ts,'or')
plt.plot(ns,[avg_slope*n for n in ns],'--b']
#运行时间估计
for n in np.linspace(1,100_000_000,11,dtype=int)
 print(f'Rumtime of sum(range({
      
      n:>11,})~{
      
      avg_slope*n/100:>5.2f}s')
 >>>>>Runtime of sum(range(  1)~0.00s
 >>>>>Runtime of sum(range(10,000,000)~0.08s

请添加图片描述

例3:polyfit为sum(range(n))数据计算任意次数的最佳拟合多项式函数
degree=100
coefffs=np.polyfit(ns,ts,degree)
p=np.ploy1d(coeffs)
pt.plot(ns,ts,'or')
plt.plot(ns,[p(n) for n in ns],'-b')
for n in np.linspace(1,100_000_000,11,dtype=int)
 print(f'Rumtime of sum(range({
      
      n:>11,})~{
      
      p(n)/100:2f}s')
  >>>>>Runtime of sum(range(  1)~0.00s
 >>>>>Runtime of sum(range(10,000,000)~929393014.....s

请添加图片描述

2) 测量sum(range(n))&sumOfN3(n)执行时间
ns=np.linspace(10,10_000,100,dtype=int)
ts=[timeit.timrit('sum(r)',setup=f'r=range({
      
      n})',number=1000,for n in ns]
ts3=[timeit.timeit('sumOfN3(r)',setup=f'r={
      
      n}',number=1000,globals=globals()) for n in ns]
plt.plot(ns,ts,'or')
plt.plot(ns,ts3,'ob')

请添加图片描述

二、独立于使用计算机的算法特征

1、n,T(n),S(n)

算法执行时间:可用 解决问题所需步骤数进行表示(T(n)=S(n))
问题规模:n
T(n):解决n的问题所花的时间
S(n):解决n的问题所需的步骤

2、如何计算S(n)

#程序1 S(n)=5
i=1 #1
j=2 #1
temp=i #1
i=j #1
j=temp #1
#程序2
x=0 #1
n=2 #1
for i in range(1,2*n):#⚠️range(a,b)是从a到b-1
x=x+1#2n-1

3、解释S(n)如何随着n的大小而变化

S(n)=O(f(n)) :算法运行时间增长量级的上界
f(n):S(n)中起决定性增长的部分

4、f(n)=S(n)中起决定性增长的部分

1)大O的数量级


ps:常量阶,对数阶,线性阶,线性对数阶,平方阶,多项式阶,指数阶,阶乘阶
请添加图片描述
Ps: 指数阶与阶乘阶数量级复杂度为难解问题。

2)大O的性质
  • 取高阶:O(n^a + n^b) = O(n^a)
  • 忽略常系数:O(c*f(n))=O(f(n))
  • O(3n^2) =O(n^2) ; O(5)=O(1)
  • 更复杂的运算原则:
    O(f(n))+O(g(n))=O(max{f(n),g(n)})
    O(f(n))*O(g(n))=O(f(n)*g(n))

例(函数):
请添加图片描述
例(程序):
f(n):S(n)增长最快的部分
T(n)=O(f(n))=O(n^2)**

#程序1 s(n)=3+(n-1)+(n-1)*(zn+1) f(n)=S(n)增长最快的部分
y=0 #1 T(n)=O(f(n))=O(n^2)
x=0 #1
n=3 #1
for i in range (1,n):
x=y+1#(n-1)
 for j in range(2*n+1)
 x=x+1#(2n+1)
 
#程序2 s(n)=n^2 T(n)=O(f(n))=O(n^2)
for i in range(n):#n
for j in range(n):#n
M1[i][j]=M1[i][j]+M2[i][j]
3)矩阵相乘的时间复杂度分析

3、增长阶数描述伸缩性

1)最好、最坏、普通情况(经典的异序词检测问题)

算法的性能有时不仅依赖于问题规模,
还依赖于数据值。
经典的异序词检测问题
1、用None替换相同的元素遍历
异序词:一个字符串与另一个字符串所含元素相同,但是排序不同。
S1[0]在S2遍历,与S2中的元素依次比较直到有相同的出现,将S2中的元素等于None.
每个元素每次情况:

  • 最好:访问一次就找到了,1
  • 最坏:访问到最后才找到,n
  • 平均:(1+n)/2
  • n个元素:n(1+n)/2
  • 时间复杂度:O(n^2)

2、按照字母表顺序给字符排序,异序词得到的结果将是同一个字符串。

Python 中,可以先将字符串转换为列表,然后使用内建的 sort 方法对列表排序。乍看可能只需要遍历一次比较基本字符,但是还需要考虑sort()的代价。

3、因为字符可能有26 种,所以使用 26 个计数器,对应每个字符。每遇到一个字符,就将对应的计数器加 1。
ord()函数:
print(ord(‘5’)) # 53
print(ord(‘A’)) # 65
print(ord(’$’)) # 36

def  ang(s1,s2):
    c1=[0]*26
    c2=[0]*26
    for i in range(len(s1)):
        pos=ord(s1[i])-ord('a')
        print(pos)
        c1[pos]=c1[pos]+1
        print(c1)
    for i in range(len(s2)):
        pos=ord(s2[i])-ord('a')
        c2[pos]=c2[pos]+1
    j=0

    Stillok=True
    while j<26 and Stillok:
        if c1[i]==c2[j]:
            j=j+1
            print(j)
        else:
            Stillok=False

    return Stillok

ang("za","bdca")


我举了一个很明显的例子:
"za"print(pos)print(c1)
请添加图片描述
观察结果可以明显看出pos和c1计数器的用途。

不同数量级的算法
展示不同数量级的算法,

2)比较sumofN(n)&sumofN3(n)算法的优劣

请添加图片描述

3)各Python数据结构效率(大O性能分析)
创建列表的4种方式:

4种方式

#被测试函数
def test1(n):#连接
l=[]
for i in range(n):
l=l+[i]

def test2(n):#追加
l=[]
for i in range(n):
l.append(i)

def test3(n):#列表解析式
l=[i for i in range(n)]

def test4(n):#range函数+列表构造器
l=list(range(n))

比较四种构造列表方式的效率:绘图time类函数

#横轴:问题规模n
ns=np.linspace(10,10_00,100,dtype=int)
#纵轴:解决问题的时间成本
lts1=[timeit.timeit('test1(r)',setup=f'r={
      
      n}',number=100,globals=globals()) for n in ns]
lts2=[timeit.timeit('test2(r)',setup=f'r={
      
      n}',number=100,globals=globals()) for n in ns]
lts3=[timeit.timeit('test3(r)',setup=f'r={
      
      n}',number=100,globals=globals()) for n in ns]
lts4=[timeit.timeit('test4(r)',setup=f'r={
      
      n}',number=100,globals=globals()) for n in ns]
#绘制函数1-4 问题规模n与对应时间成本的函数
plt.plot(ns,lts1,'sb')
plt.plot(ns,lts2,'g')
plt.plot(ns,lts3,'r')
plt.plot(ns,lts4,'K')
列表各种操作的性能分析

请添加图片描述

POP

#函数
popzero=timeit.Timer("x.pop(0)","from_main_import x")#从列表头pop出,要遍历完列表
popend=timeit.Timer("x.pop()","from_main_import x")#从列表尾pop出,与长度无关
#纵轴:时间成本
popendtime=[]
popzerotime=[]
for i in range(10000,1000001,100):
 x=list(range(i))
 pop_end_t = pop_end.timeit(number=1000)
 popendtime.append(pop_end_t)#插入利用timeit函数计算的时间成本数组
 x = list(range(i))
 pop_zero_t = pop_zero.timeit(number=1000)
 popzerotime.append(pop_zero_t)#插入利用timeit函数计算的时间成本数组
#横轴:
ns=np.linspace(10000,1000001,100,dtype=int)
plt.plot(ns,popendtime,'sb')
plt.plot(ns,popzerotime,'dr')

index(x)查找

#函数
index=timeit.Timer("lst.index(x)","from_main_import lst,x")
#纵轴:时间成本
indextime=[]
for  n in range(1000,100001,1000):
 lst=list(range(n))
 x=n//2
 index_t=index.timeit(number=1000)
 indextime.append(index_t)#插入利用timeit函数计算的时间成本数组
 #横轴:
ns=np.linspace(1000,100000,100,dtype=int)
plt.plot(ns,indextime,'.g',label='index')
plt.lengend()
 

insert(i,x)

#函数
insert=timeit.Timer("lst.index(i,x)","from_main_import lst1,x")
#纵轴:时间成本
inserttime=[]
for  n in range(1000,100001,1000):
 lst1=list(range(n))
 i=0
 x=0
 insert_t=insert.timeit(number=1000)
 inserttime.append(insert_t)#插入利用timeit函数计算的时间成本数组
  #横轴:
ns=np.linspace(1000,100000,100,dtype=int)
plt.plot(ns,insertime,'.b',label='insert')
plt.lengend()

remove(x)

remove=timeit.Timer("lst2.remove(x)","from_main_import lst2,x")

del lst[i]

delete=timeit.Timer("del lst3a[i][0];i=i+1","from_main_import lst3a,i")

sort()

sort=timeit.Timer("lst4.reverse()","from_main_import lst4")

reverse()

reverse=timeit.Timer("lst5.reverse()","from_main_import lst5")

count(x)

count=timeit.Timer("lst6.count(x)","from_main_import lst6,x")

append(x)

append=timeit.Timer("lst7a[i].append(0);i+=","from_main_import lst7a,i")

列表索引赋值操作[ ]

#函数
idexassign=timeit.Timer("lst8[i]=0)","from_main_import lst8,i")
#纵轴:时间成本
idxassigntime=[]
for  n in range(10000,1000001,10000):
 lst1=list(range(n))
 i=n//2
 idxa_t=idxassign.timeit(number=1000)
 inserttime.append(idxa_t)#插入利用timeit函数计算的时间成本数组
#横轴:
ns=np.linspace(10000,1000001,100,dtype=int)
plt.plot(ns,idxassigntime,'.','color='darkorange',![请添加图片描述](https://img-blog.csdnimg.cn/5e66689e05664f189d11b8b87301facb.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA54mn5rO954-j,size_20,color_FFFFFF,t_70,g_se,x_16)
label='insert')
plt.lengend()

请添加图片描述

字典与列表性能比较

判断随机数在列表和字典是否存在的时间对比

import timeit
import random
#定义 存储时间的数组
lst_timelst=[]
d_timelst=[]
for i in range((10000, 1000001, 20000):
   t=timeit.Timer("random.randrange(%d)in x"%i,"from_main_import random,x")
   x=list(range(i))#列表构造器
   list_time=t.timeit(number=1000)
   #列表数组存入所得对应时间成本
   lst_timelst.append(list_time)
   x={
    
    j:None for j in range(i))
   d_time=t.timeit(number=1000)#字典构造
   #字典数组存入所得对应时间成本
   d_timelst.append(d_time)
   #drawing the curve
   plt.plot(ns,lst_timelst,'.b',label='list')#列表
   plt.plot(ns,d_timelst,'.r',label='dict')#字典
 
   #我没有写输出操作

猜你喜欢

转载自blog.csdn.net/qq_45750937/article/details/119412206
今日推荐