什么是数据结构
对于什么是数据结构至今都没有统一的定义。我们日常中处理不同的数据,做法也不一样。假设我们是图书管理员,需要整理一堆书,整理起来还需要考虑以后查找方便。你可能会想到按照字母顺序排放,但是以后查找起来还是会比较麻烦要按照拼音顺序进行二分查找。此时插入新书还是会比较困难,如果是一本字母A开头的,想要插入进去,那么之后的书籍都需要往后挪一下,比较复杂。
另一种方法就是我们现实生活中采取的办法,把书架划分成几块区域,每块区域指定摆放某种类别图书,在每种类别内,按照书名的拼音字母顺序排放。此时,插入的时候就先定类别,用二分查找确定位置,移出空位。找指定数目也是,先定类别,再二分查找。此时也存在问题: 空间怎么分配,各种类别分配需要多细。
循环与递归
对于循环和递归,写了一个可以对比在迭代相同次数所耗费时间的代码,感兴趣的可以自己跑一下试试,改变number
数据的大小,就会发现递归所耗费的空间是非常巨大的。
import time
import numpy as np
import matplotlib.pyplot as plt
number = np.arange(10, 1000, 10)
print(number)
def computer_time_1(number):
cost_time = []
for j in number:
start_time = time.time()
for i in range(j+1):
print (i)
end_time = time.time()
cost = end_time - start_time
cost_time.append(cost)
return cost_time
def Print(N):
if N != 0:
Print(N - 1)
print(N)
return None
def computer_time_2(number):
cost_time = []
for i in number:
start_time = time.time()
Print(i)
end_time = time.time()
cost = end_time - start_time
cost_time.append(cost)
return cost_time
cost_1 = computer_time_1(number)
cost_2 = computer_time_2(number)
plt.plot(number, cost_1,label='For')
plt.plot(number, cost_2,label='recursive')
plt.show()
拟合二项式
写程序计算给定如下多项式在给定点处的值:
如果用for
循环实现的话,可以大体表示为如下形式:
n =3
f_x = 0
x = 1
a = [1,2,3]
for i in range(n):
f_x = f_x + a[i]*pow(x,i)
print (f_x)
但是上述的写法据陈越奶奶说,会被专业程序员鄙视。而应该先把上述公式用乘法结合律改写为如下形式:
那么计算的时候就是先算最后那一项, 然后将其作为与相乘再加上一个系数就可以。
n =1
f_x = 0
x = 1
a = [1,2,3]
for i in reversed(range(n)):
f_x = a[i] + x * f_x
print (f_x)
那上述两种方法的区别在哪里呢?可以看到两种方法都是用for
循环做的,但是for
循环里面所用的乘法不一样,第一种方法用了次乘法。第二种方法用了次乘法。因此第一个算法的时间复杂度,第二种算法的时间复杂度。当很大的时候,第一个程序就会跑地比第二个程序慢很多。
抽象数据类型
抽象数据类型需要分清楚两个概念:抽象、数据类型。数据类型一个是数据本身,另一个是对数据的操作。单纯的数据没有意义,跟操作结合起来才能实现功能。
什么是算法
算法(Algorithm
)主要会满足以下五个点
- 一个有限指令集。
- 接受- -些输入(有些情况下不需要输入)。
- 产生输出。
- 一定在有限步骤之后终止。
- 每一条指令必须有充分明确的目标,不可以有歧义计算机能处理的范围之内描述应不依赖于任何一种计算机语言以及具体的实现手段。
什么是好的算法
实现一种问题的算法不止一种,那什么是好的算法呢?好的算法时间复杂度和空间复杂度都需要比较低。
- 时间复杂度:
根据算法写成的程序在执行时耗费时间的长度。这个长度往往也与输入数据的规模有关。时间复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果。
- 空间复杂度:
根据算法写成的程序在执行时占用存储单元的长度。这个长度往往与输入数据的规模有关。空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。