一、概念
算法指的是计算机处理信息的本质,因为计算机程序本质上就是一个算法,它告诉计算机确切的步骤来执行一个指定的任务。
算法是独立存在的一种解决问题的方法和思想。 对于算法而言,用什么语言实现算法并不重要,重要的是算法的思想。
算法可以有不同的语言描述实现版本(如C描述、C++描述、Python描述等),我们现在是在用Python语言对算法进行描述与实现。
二、特性
对于一个算法而言,它有着五大特性:
- 有输入:算法具有0个或多个输入
- 有输出:算法至少有1个或多个输出
- 有穷性:算法必须在有限步或者有限时间内完成
- 确定性:算法中的每一步都有确定的含义,不能出现二义性
- 可行性:算法的每一步都是可行的
三、设计准则
在解决同一个问题时,会有多种算法来解决问题,那么这个时候就需要通过下面对算法各方面进行比较选择一个最优的算法出来:
- 正确性:算法能够达到预期结果,这对于一个算法来说时首要问题
- 可读性:算法应该要易于理解、易于实现和易于调试
- 健壮性:算法不仅要能够对于合法的数据能够正确处理,对于非法数据也要能够做出处理,防止程序出现失控状况
- 高效性:算法执行时间要尽可能短,占用储存空间要尽可能少(由于现在硬件空间有了极大提升,在设计过程中优先保证时间效率而不考虑空间效率)
四、时间复杂度
不同的算法怎么体现出他们各自的执行效率呢?如果用程序的实际执行时间来体现的话,由于程序的实际执行时间会受到多个方面的影响,例如数据量的大小、硬件的性能等等,这样每一次的时间都会不一样。
为了解决这个问题,人们提出了时间复杂度的概念。在时间复杂度中,一个算法的时间复杂度并不代表代码的实际执行时间,用算法中语句的执行次数来代表算法的时间复杂度。
# 求1到n的累加
def getsum(n):
sum = (1 + n) * n / 2
return sum
在上面的代码中,不管n取多少,上面的代码都只执行2次,那么它的时间复杂度就是T(n)= 3。
五、“大O”表示法
那么是否有必要精确计算算法中语句执行的具体次数呢?答案是没有必要的。因为我们在很多情况下是很难精确计算出语句的执行次数,在另一些情况下又没有必要精确计算出代码的执行次数,只需要知道是什么数量级就行了。
例如:T(n) = n² + 10n + 100,在这个时间复杂度中,n²在这个时间复杂度中是主要成分,后面两项可以忽略掉。这样我们估算一个算法的时间复杂度时只需要保留主项,给出数量级,这种表示方法就是渐进式时间复杂度。渐进式时间复杂度通常用“大O”表示法来表示。
“大O”表示法定义:
当且仅存在正整数c和N时,使得对所有的n≥N,有T(n)≤cf(n)成立,则称T(n)是O(f(n)),记为T(n) = O(f(n))。渐进时间复杂度常简称为时间复杂度。
六、常见的时间复杂度
1. 常量阶
def demo(n):
x = n / 2
return x
不管传入的n有多大,上面的代码都只执行一次,
故时间复杂度为T(n) = O(1)
2. 线性阶
def demo(n):
sums = 0
for i in range(n):
sums += i
return sums
随着传入的n的数据量逐渐增大,其代码执行也随着n呈现线性增加,
故时间复杂度T(n) = O(n)
3. 幂函数阶
def demo(n):
sums = 0
for i in range(n):
for j in range(n):
sums += i * j
return sums
随着传入的n的数据量逐渐增大,其代码执行也随着n呈现平方增加,
故时间复杂度T(n) = O(n²)
4. 对数阶
def demo(n):
i = 0
while i <= n:
print(i)
i *= i
随着传入的n的数据量逐渐增大,其代码执行也随着n以对数趋势增加,
故时间复杂度T(n) = O(㏒₂ n)
5. 其他
算法的时间复杂度还有指数阶O(2^n),阶乘阶O(n!)等。
时间复杂度关系:O(1) < O(㏒₂ n) < O(n) < O(n㏒₂ n) < O(n²) < O(n³) < O(2^n)
< O(n!) < O(n^n)
七、最坏时间复杂度
对于一个算法,它的时间复杂度不仅与自身算法有关,还和输入的数据有关。那么同一个算法就有最好时间复杂度、平均时间复杂度和最坏时间复杂度之分。
在实际使用过程中,我们一般关心最坏时间复杂度,常常以算法的最坏时间复杂度来进行比较。