第一章什么是算法算法是解决一个计算问题的一系列计算步骤有序、合理的排列。
对一个具体问题(有确定的输入数据)依次执行一个正确的算法中的各操作步骤,最终将得到该问题的解(正确的输出数据)。
算法的三个要素1).数据:运算序列中作为运算对象和结果的数据•2).运算:运算序列中的各种运算:赋值,算术和逻辑运算3).控制和转移:运算序列中的控制和转移.算法分类从解法上:数值型算法:算法中的基本运算为算术运算;非数值型算法:算法中的基本运算为逻辑运算.从处理方式上:串行算法:串行计算机上执行的算法;并行算法:并行计算机上执行的算法算法的五个重要的特性(1)有穷性: 在有穷步之后结束。
(2)确定性: 无二义性。
(3)可行性: 可通过基本运算有限次执行来实现。
(4)有输入f表示存在数据处理(5)伪代码有输出A程序设计语言(PDL),也称为结构化英语或者伪代码,它是一种混合语言,它采用一种语言(例如英语)的词汇同时采用类似另外一种语言(例如,结构化程序语言)的语法。
特点:1)使用一些固定关键词的语法结构表达了结构化构造、数据描述、模块的特征;2)以自然语言的自由语法描述了处理过程;3)数据声明应该既包括简单的也包括复杂的数据结构;4)使用支持各种模式的接口描述的子程序定义或者调用技术。
求两个n阶方阵的相加C=A+B的算法如下,分析其时间复杂度。
#define MAX 20 //定义最大的方阶void matrixadd (int n,int A[MAX][MAX], int B[MAX][MAX],i nt C[MAX][MAX]) { int i,j;for (i=0;i <n ;i++)for (j=0;j< n;j++)C[i][j]=A[i][j]+B[i][j]; }该算法中的基本运算是两重循环中最深层的语句n 1 n 11T(n)= i 0j 0分析以下算法的时间复杂度。
void fun c(i nt n) { int i=0,s=0;while (s<n){ i++;s=s+i; } C[i][j]=A[i][j]+B[i][j],分析它的频度,即:n n 1 n* n i 0 i 02n=0( n2)对于while 循环语句,设执行的次数为 m , i 从0开始递增1直到m 为止,有:s=0+1+2+…+(m-1)=m(m-1)/2,并满足 s=m(m_1)/2<n ,则有 m v n 。
T(n)=0( n )所以,该算法的时间复杂度为 0( n )。
有如下算法:void fun (int a[],int n,int k) // 数组 a 共有 n 个元素 { int i; if (k==n-1)for (i=0;i<n;i++) //n 次prin tf("%d\n",a[i]); else{ for (i=k;i<n;i++)//n-k 次a[i]=a[i]+i*i; fun (a ,n ,k+1); }}调用上述算法的语句为fun (a ,n ,0),求其时间复杂度。
设fun(a,n,0)的时间复杂度为 T(n),贝U fun(a,n,k)的执行时间为T1(n,k),由fun()算法可知:T1(n,k)=n 当 k= n-1 时T1(n,k)= (n-k)+T1(n,k+1) 其他情况 贝U:T( n)=T1( n,0)=n+T1( n,1)=n+( n-1)+T1( n,2) =••• =n+(n _1)+ …+2+T1( n,n _1) =n+(n _1)+ …+2+n=O(n2) 所以调用fun(a,n,0)的时间复杂度为 0(n2)。
估计如下二重循环算法在最坏情况下时间复杂性T(n)的阶。
for i:= 1 to n dofor j:=1 to i do{s1,s2,s3,s4} ; s1,s2,s3,s4 为单一赋值语句分析:内循环体只需 O(1)时间,故渐进分析时间复杂性渐进阶分析的规则:(最坏情况)1).赋值,比较,算术运算,逻辑运算,读写单个变量(常量)只需 1单位时间2).执行条件语句 if c then S1 else S2 的时间为 TC +max(TS1,TS2). 3).选择语句 case A of a1: s1; a2: s2; ...; am: sm需要的时间为 max (TS1,TS2 ,..., TSm .4) .访问数组的单个分量或纪录的单个域需要一个单位时间 5) .执行for 循环语句的时间=执行循环体时间*循环次数. 6) . while c do s (repeat s until c)语句时间=(Tc+Ts)循环次数. 7) .用goto 从循环体内跳到循环体末或循环后面的语句时,不需额外时间8) .过程或函数调用语句:对非递归调用,根据调用层次由里向外用规则1-7进行分析;对递归调用,可建立关于 T(n)的递归方程,求解该方程得到T(n).插入排序算法的实现要点:(1) 【参数和返回值】 确定输入数据个数和数据类型,输出个数和数据类型,数据的组织形iiO(1 O( 1) O()内循环共需j 1j 1N O(i) 外循环共需「1NO( i)i 1。
(呼)O(N 2)式(即逻辑结构:线性表、树、图,线性表还包括栈、队列),数据的存储格式(数组还是链表),函数返回值。
(2)【数据设置】变量定义与初值设定。
要考虑访问的所有数据,包括变量和常量。
每个变量都要考虑它的数据类型、存储结构、访问控制(局部变量、全局变量、静态变量、公共属性、保护属性、私有属性等)和初始值。
(3)【关键代码】要考虑直接转换还是需要建立相应的独立函数。
对于赋值和下标通常可以直接转换。
一些操作,比如数据输入、创建、求长度、查找、排序、插入、删除、显示、修改等操作,通常需要通过建立专门的独立函数来实现,也可以通过系统提供的命令或函数来实现。
归并排序算法的实现要点:(1)【参数和返回值】确定输入数据个数和数据类型,输出个数和数据类型,数据的组织形式(即逻辑结构:线性表、树、图,线性表还包括栈、队列),数据的存储格式(数组还是链表),函数返回值。
参数:序列A[p…r]的子序列A[p…q]和A[q+1…r],可以表示为区间[p,q],[q,r]指针(或迭代器)p, q, r:p指向第一个子序列的首元素,q指向第二个子序列首元素,r指向第二个子序列末尾元素之后,单个元素数据长度及比较函数指针。
返回值:无(2)【数据设置】变量定义与初值设定。
要考虑访问的所有数据,包括变量和常量。
每个变量都要考虑它的数据类型、存储结构、访问控制(局部变量、全局变量、静态变量、公共属性、保护属性、私有属性等)和初始值。
(3)【关键代码】要考虑直接转换还是需要建立相应的独立函数。
对于赋值和下标通常可以直接转换。
一些操作,比如数据输入、创建、求长度、查找、排序、插入、删除、显示、修改等操作,通常需要通过建立专门的独立函数来实现,也可以通过系统提供的命令或函数来实现。
序列的划分算法的实现要点:(1)【参数和返回值】确定输入数据个数和数据类型,输出个数和数据类型,数据的组织形式(即逻辑结构:线性表、树、图,线性表还包括栈、队列),数据的存储格式(数组还是链表),函数返回值。
参数:A是数组或序列p, r分别是整数或者迭代器返回值:分界点位置的整数或者迭代器(2)【数据设置】变量定义与初值设定。
要考虑访问的所有数据,包括变量和常量。
每个变量都要考虑它的数据类型、存储结构、访问控制(局部变量、全局变量、静态变量、公共属性、保护属性、私有属性等)和初始值。
(3)【关键代码】要考虑直接转换还是需要建立相应的独立函数。
对于赋值和下标通常可以直接转换。
一些操作,比如数据输入、创建、求长度、查找、排序、插入、删除、显示、修改等操作,通常需要通过建立专门的独立函数来实现,也可以通过系统提供的命令或函数来实现。
第二章直接或间接地调用自身的算法称为递归算法。
用函数自身给出定义的函数称为递归函数。
分治法的设计思想:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
分治策略在每一层递归包括 3个步骤:分解 将问题分解成若干个子问题。
治理 递归地解决各子问题。
不过若子问题的规模足够小,就以直接的方式(不再递归)解 决子问题。
合并 将子问题的解合并成原问题的一个解。
divide-a nd-c onq uer(P) {if ( | P | <= nO) adhoc(P); //解决小规模的问题divide P into smaller subinstances P1,P2,...,Pk ; // 分解问题for (i=1,i<=k,i++)yi=divide-and-conquer(Pi); // 递归的解各子问题 return merge(y1,...,yk); II 将各子问题的解合并为原问题的解}分治法的复杂性分析:一个分治法将规模为 n 的问题分成k 个规模为n /m 的子问题去解。
设分解阀值 n0=1,且 adhoc 解规模为1的问题耗费1个单位时间。
再设将原问题分解为k 个子问题以及用 merge将k 个子问题的解合并为原问题的解需用f(n)个单位时间。
用 T(n)表示该分治法解规模为11通过迭代法求得方程递归小结:优点:结构清晰,可读性强, 法、调试程序带来很大方便。
缺点:递归算法的运行效率较低, 无论是耗费的计算时间还是占用的存储空间都比非递归算法^<多。
解决方法:在递归算法中消除递归调用,使其转化为非递归算法。
1、 采用一个用户定义的栈来模拟系统的递归调用工作栈。
该方法通用性强,但本质上还是 递归,只不过人工做了本来由编译器做的事情,优化效果不明显。
2、 用递推来实现递归函数。
3、 通过变换能将一些递归转化为非递归,从而迭代求出结果。
二分搜索算法:template<class Type>int Bin arySearch(Type a[], const Type & x, int l, i nt r) {while (r >= l){int m = (l+r)I2; if (x == a[m]) return m; if (x < a[m]) r = m-1; else l = m+1; }return -1;}n f(n) nT(n)kT( n/m)|P|=n 的问题所需的计算时间,则有:T(n)的解: lo g m k n mbg mn而且容易用数学归纳法来证明算法的正确性, 因此它为设计算算法复杂度分析:每执行一次算法的while循环,待搜索数组的大小减少一半。