一、什么是算法
算法是计算机处理信息的本质,因为计算机程序解决一个问题本质上是通过一套算法来告诉计算机确切的步骤。一般的,算法在处理信息的时候,从输入设备中读取数据,处理完后,将结果写入输出设备中。
对于算法而言,实现的语言并不重要,重要的是思想。
算法可以有不同的语言描述实现版本(如C描述、C++描述、Python描述等),我们现在是在用Python语言进行描述实现。
二、算法的五大特性
- 输入: 算法具有0个或多个输入
- 输出: 算法至少有1个或多个输出
- 有穷性: 算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成
- 确定性:算法中的每一步都有确定的含义,不会出现二义性
- 可行性:算法的每一步都是可行的,也就是说每一步都能够执行有限的次数完成
三、算法效率的衡量
时间复杂度与大“O”表示法
首先单纯的依靠运行时间来比较算法的优劣不一定是准确的,因为程序的执行离不开计算机配置、编程语言不同而不同。
我们假定计算机执行一个基本操作的时间是固定的一个时间单位,那么有多少个基本操作就代表会花费多少时间单位。
对于算法的时间效率,我们可以用“大O记法”来表示。
时间复杂度:假设存在函数g,使得算法A处理规模为n的问题示例所用时间为T(n)=O(g(n)),则称O(g(n))为算法A的渐近时间复杂度,简称时间复杂度,记为T(n)。
常见的时间复杂度
执行次数函数举例 | 阶 | 非正式术语 |
---|---|---|
12 | O(1) | 常数阶 |
2n+3 | O(n) | 线性阶 |
3n2+2n+1 | O(n2) | 平方阶 |
5log2n+20 | O(logn) | 对数阶 |
2n+3nlog2n+19 | O(nlogn) | nlogn阶 |
6n3+2n2+3n+4 | O(n3) | 立方阶 |
2n | O(2n) | 指数阶 |
注意,经常将log2n(以2为底的对数)简写成logn
所消耗的时间从小到大
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
""" O(1) """ print('Hello World') print('Hello Python') print(‘Hello Algorithm’) """ O(n**2) """ for i in range(n): print('Hello World’) for j in range(n): print('Hello World') """ O(n**2) """ for i in range(n): for j in range(i): print('Hello World') """ O(log2n) """ while n > 1: print(n) n = n // 2
如何一眼判断出时间复杂度?
循环减半的过程 : O(logn) 几次循环就是n的几次方的复杂度
空间复杂度
空间复杂度:用来评估算法内存占用大小的一个式子。“空间换时间”
四、递归的复习
1.递归的两个特点:
- 调用自身
- 结束条件
2. 递归练习:
""" 先打印,后递归 假设x为5的话,那么打印的结果为:5,4,3,2,1 """ def func3(x): if x>0: print(x) func3(x-1) """ 先递归,后打印 假设x为5的话,那么打印的结果为:1,2,3,4,5 """ def func4(x): if x>0: func4(x-1) print(x)
递归汉诺塔问题解决
C语言解决汉诺塔实现:
#include <stdio.h> #include <stdlib.h> void hanoi(int i,char a,char b,char c); int main(void) { char a = 'A'; char b = 'B'; char c = 'C'; int i=0; printf("请输入盘子的个数:"); scanf("%d",&i); hanoi(i,a,b,c); return 0; } void hanoi(int i,char A,char B,char C) { if(i == 1)//如果是1个盘子 { printf("将编号为%d的盘子直接从%c,移到%c ",i,A,C);// 直接将A上的盘子移到C } else//否则 { hanoi(i - 1,A,C,B);//将A上的n-1个盘子借助C移到B printf("将编号为%d的盘子直接从%c,移到%c ",i,A,C);//将A上的盘子移到C hanoi(i - 1,B,A,C);//最后将B上的n-1个盘子借助A移到C } }
Python解决汉诺塔实现:
""" 1. 借助C柱将A柱上的n-1盘子移动到B柱 2. 将第n个盘子移到C柱 3. 借助A柱将B柱上的盘子移到C柱 """ def hanoi(n,A,B,C): # if x > 0: # print("借助%s从%s移到%s"%(C,A,B)) # print("%s---->%s"%(A,C)) # print("%s---->%s"%(B,C)) if n >0: # 借助C柱将A柱上的n-1盘子移动到B柱 hanoi(n - 1, A, C, B) # 将第n个盘子移到C柱 print("%s-->%s"%(A,C)) # 借助A柱将B柱上的盘子移到C柱 hanoi(n-1,B,A,C) hanoi(3,"A","B","C")
总结:汉诺塔移动次数的递推式:h(x)=2h(x-1)+1。
台阶问题:
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2)
""" 一段有n个台阶组成的楼梯,小明从楼梯的最底层向最高处前进, 它可以选择一次迈一级台阶或者一次迈两级台阶。问:他有多少种不同的走法? n - 1 n - 2 """ def taijie(n): if n <= 2: return n else: return taijie(n-1) + taijie(n-2)