第1章 基本概念 —— 1.3 算法(Algorithm)

来源:互联网 发布:linux avi转rmvb 编辑:程序博客网 时间:2024/06/07 21:58

1.3.1 定义

  • 有限的指令;
  • 接受一些输入(有些情况下不需要输入);
  • 产生输出;
  • 一定在有限步骤之后终止;
  • 每一条指令必须: a.明确 b.计算机可处理 c.不依赖单独某一种特定的计算机语言。

示例:选择排序算法的伪码描述。

void SelectionSort ( int List[], int N ){ /* 将N个整数List[0]...List[N-1]进行非递减排序 */ for ( i = 0; i < N - 1; i++ ) {   /* 从List[i]到List[N–1]中找最小元,并将其位置赋给MinPosition */   MinPosition = ScanForMin( List, i, N–1 );   /* 将未排序部分的最小元换到有序部分的最后位置 */   Swap( List[i], List[MinPosition] );   }}

这里写图片描述
通过代码的描述可以看到:选择排序基本分为两步,首先找出未排序部分的最小元,然后将之换到有序部分的队尾。上述描述不依赖于具体实现手段,如:List到底是数组还是链表(虽然看上去很像数组)、Swap用函数还是用宏去实现。
算法不是程序。

1.3.2 衡量算法优劣的指标:算法复杂度

什么是好的算法?
除了算法的描述风格外,具体衡量、比较算法优劣的指标主要有:空间复杂度、时间复杂度。

1.3.2.1 空间复杂度S(n)

空间复杂度S(n):根据算法写成的程序在执行时占用存储单元的长度。这个长度往往与输入数据的规模有关。空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。
示例:“打印从1到N的全部整数”PrintN()的递归算法,N非常大时,程序无法执行,就是由于每次递归都要占用内存,导致计算机内存不足造成程序的非正常中断。
它的空间复杂度就与递归的深度有关:这里写图片描述。其中N是需要打印的整数的个数,是变量;C是1个单位的内存空间占用存储单元的长度,是一个固定常数。

1.3.2.2 时间复杂度T(n)

时间复杂度T(n):根据算法写成的程序在执行时耗费时间的长度。这个长度往往也与输入数据的规模有关。时间复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果。
示例:计算多项式值的秦九韶算法和简单直接算法,秦九韶算法的计算速度更快。
分析:
这里写图片描述

在分析一般算法的效率时,我们经常关注下面两种复杂度:
这里写图片描述

1.3.3 复杂度的渐进表示法

1.3.3.1 T(n) = O(f(n))、T(n) = Ω(g(n))、T(n) = Θ(h(n))

在比较算法优劣时,人们只考虑宏观渐进性质。即当输入规模n“充分大”时,我们观察不同算法复杂度的“增长趋势”,以判断哪种算法必定效率更高。为此引入下面几种数学符号。
这里写图片描述
这三种符号不仅用于分析时间复杂度,对空间复杂度也同样适用。如“打印1到N全部正整数”PrintN():循环算法具有常数级的空间复杂度S(n)=O(1),递归算法具有线性空间复杂度S(n)=O(n)。
表1 常用函数增长表
这里写图片描述
图1 常用函数增长曲线
这里写图片描述
注意:表1和图1必须牢记!设计算法时,必须避免指数级如O(这里写图片描述)复杂度、O(n!)的算法;面对O(这里写图片描述)复杂度的算法时,engineer本能的反应就是将之优化为一个O(nlogn)的算法。
表2 10亿指令每秒计算机的运行时间表
这里写图片描述

1.3.3.2 复杂度渐进表示法的计算技巧

这里写图片描述