第一节–走入算法的世界
“云"其实就是泛指"网络”,因为工程师在网络结构示意图中通常习惯用"云多状"图来代表不同的网络。云计算是指将网络中的运算能力提供出来作为一种服务,只要用户可以通过网络登录远程服务器进行操作,就能使用这种运算资源
物联网(Internet of Things,IOT)与因特网结合起来,并通过网络技术让各种实体对象,自动化设备彼此沟通和交换信息,也就是通过网络把所有东西都连接在一起
一.都处是算法
大数据(Big Data,又称海量数据),有IBM于2010年提出,是指在一定时效(Velocity)内进行大量(Volume),多样性(Variety),低价值密度(Value),真实性(Veracity)数据的获得,分析,处理,保存等操作,主要特性包含5个方面:Volume(大量),Velocity(时效性),Variety(多样性),Value(低价值密度),Veracity(真实性)
1.算法定义
为了解决某项工作或某个问题,所需要有限数量的机械性或重复性指令与计算步骤
2.算法的条件
算法所必须符合的五个条件:
算法的特性 | 内容与说明 |
---|---|
输入(Input) | 0个或多个输入数据,这些输入必须有清楚的描述或定义 |
输出(Output) | 至少会有一个输出结果,不可以没有输出结果 |
明确性(Definiteness) | 每一个指令或步骤必须是简洁明确的 |
有限性(Finiteness) | 在有限步骤后一定会结束,不会产生无限循环 |
有效性(Effectiveness) | 步骤清楚且可行 |
算法和过程(procedure)的不同:过程不一定要满足有限性的要求,例如操作系统或机器上运作的过程。除非宕机,否则永远在等待循环中(waiting loop),这就违反了算法中的"有限性"
3.时间复杂度O(f(n))
1.时间复杂度的定义
用一种"估算"的方法来衡量程序或算法的运行时间反而更加恰当,这种估算的时间就是"时间复杂度"(Time Complexity)。详细定义如下:
在一个完全理想状态下的计算机中,我们定义T(n)来表示程序执行所要花费的时间,其中n代表数据输入量。当然程序的运行时间(Worse Case Executing Time)或最大运行时间是时间复杂度的衡量标准,一般以Big-oh表示
O(f(n))可视为某算法在计算机中所需运行时间不会超过某一常数倍数的f(n),也就是说某算法运行时间T(n)的时间复杂度(time complexity)为O(f(n))(读成Big-oh of f(n)或Order is f(n))
意思是存在两个常数c和n0,当n>=n0,T(n)<=cf(n)。f(n)又被称为运行时间的成长率(rate of growth)
二.常见算法简介
1.分治法
分治法(Divide and Conquer,也称为"分而治之法")是一种很重要的算法,我们可以应用分治法来逐一拆解复杂的问题,核心思想就是将一个难以直接解决的大问题依照相同的概念,分割成两个或更多的子问题,以便各个击破,即"分而治之"。
用途:快速排序法(quick sort),递归算法
2.递归法
递归是一种很特殊的算法,分治法和递归法很像一对孪生兄弟,都是将一个复杂的算法问题进行分解,让规模越来越小,最终使子问题容易求解
从程序设计语言的角度来说,递归的正式定义为:一个函数或子程序,是由自身所定义或调用的,就称为递归(Recursion)。递归至少要满足2个条件:一个可以反复执行的递归过程;一个可以离开递归执行过程的出口
python语言的n!递归函数算法则可以写成如下形式:
def factorial(i):
if i==0:
return 1
else:
ans = i*factorial(i-1)
return ans
斐波拉项数列
def fib(n):
if n==0:
return 0
elif n==1 or n==2:
return 1
else:
return (fib(n-1)+fib(n-2))
n = int(input("请输入要计算第几项斐波拉项数列:"))
for i in range(n+1):
print("fib(%d)=%d" %(i,fib(i)))
3.贪心算法
贪心法(Greed Method)又称为贪婪算法,方法是从某一起点开始,在每一个解决问题步骤中使用贪心原则,即采取在当前状态下最有利或最优化的选择,不断地改进该解答,持续在每一步骤中选择最佳的方法,并且逐步逼近给定的目标,当达到某一步骤不能再继续前进时,算法就停止,就是尽可能快地求得更好的解
贪心法经常用于找出图的最小生成树(MST),最短路径与哈夫曼编码等
4.动态规划法
动态规划法(Dynamic Programming Algorithm,DPA)。主要做法:如果一个问题答案与子问题相关的话,就能将大问题拆解成各个小问题,其中与分治法最大不同的地方是可以让每一个子问题的答案被存储起来,以供下次求解求解时直接取用
前面斐波拉项数列使用类似分治法的递归法,如果改用动态规划法,那么已计算过的数据就不必重复计算了,也不会再往下递归,因而实现了提高性能的目的,例如:求斐波拉项数列的第4项数Fib(4),它的递归过程可以用下图表示出来
从上面的执行路径图中我们可以得知递归调用了9次,而执行加法运算4次,Fib(1)和Fib(0)共执行了3次,我们根据动态规划法的思想,可以将算法修改如下:
output = [None]*1000 # fibonacci的暂存区
def Fibonacci(n):
result = output[n]
if result = None:
if n==0:
result = 0
elif n==1:
result = 1
else:
result = Fibonacci(n-1)+Fibonacci(n-2)
output[n]=result
return result
5.迭代法
迭代法(iterative method)是指无法使用公式一次求解,而需要使用迭代,例如用循环取重复执行程序代码的某些部分来得到答案
请使用for循环来设计一个计算1!–n!阶乘的递归程序
sum=1
n=int(input("请输入n="))
for i in range(0,n+1):
for j in range(i,0,-1):
sum*=j
print("%d!=%3d" %(i,sum))
sum=1
6.枚举法
枚举法又称为穷举法,它的核心思想就是列举所有的可能。但是缺点就是速度太慢
7.回溯法
“回溯法”(Backtracking)也算是枚举法中的一种。一旦发现不正确的数值,就不再递归到下一层,而是回溯到上一层,以节省时间。它的特点主要是在搜索过程中寻找问题的解,当发现不满足求解条件时,就回溯(返回),尝试别的路径,避免无效搜索