1.2 绪论—— 算法(特点、评价标准、时间复杂度、空间复杂度)

什么是算法?
算法(Algorithm)是对特定问题求解步骤的一种描述,是为了解决一个或者一类问题给出的一个确定的、有限长的操作序列。

算法的特点
一个算法应该满足的5个条件:①有穷性:一个有限指令集 ;②有输入:接受一些输入(有些情况下不需要输入); ③有输出:产生输出 ;④可行性:一定在有限步骤之后终止;⑤确定性:每一条指令必须有充分明确的目标、不可以有歧义 、在计算机能处理的范围之内 、描述应不依赖于任何一种计算机语言以及具体的实现手段。
为让读者清晰了解到算法与代码的差别,并鉴于读者已学习过C语言,李老爹举个例子——选择排序:

void SelectionSort( intList[], intN )//这是算法!!
 { /* 将N个整数List[0]...List[N-1]进行非递减排序*/ 
 for( i = 0; i < N; i ++ ) 
 { MinPosition= ScanForMin( List, i,N–1 ); /* 从List[i]到List[N–1]中找最小元,并将其位置赋给MinPosition*/ 
 Swap( List[i], List[MinPosition] ); /* 将未排序部分的最小元换到有序部分的最后位置*/ 
 } }
 
void SelectSort(int r[], int n)//这是C语言代码!!
{ /*n个数值存放在r[0…n-1]中进行直接选择排序*/
int i, j, t;
int tmp;
for(i=0;i<n-1;i++)     /*作n-1趟选取 */
{   
t=i;              /*t中存放关键码最小记录的下标 */
for(j=i+1;j<n;j++)   /* n-i-1次比较选关键码最小的记录 */
if(r[t]>r[j])
t=j;
if (t!=i)           /*如果t不是待排序的第一个位置,则交换*/
{   
tmp = r[t];
r[t] = r[i];
r[i] = tmp;
}}}

算法的评价标准
通常设计一个好的算法应该达到以下4个目标:
(1) 正确性(Correctness)
(2) 可读性(Readability)
(3) 健壮性(Robustness) 包含容错性,也就是当系统非法输入时,算法能否进行很好的处理。
(4) 时间效率和存储占用量(Time Efficiency and Storage Possession) 算法分析是对一个算法所需要的执行时间和存储空间作定量分析,目的是分析算法的效率,以求改进。
举个例子:比如要你计算1~10000000的所有数字的值。如果使用for循环则语句有执行10000000次,浪费时间;如果使用迭代,浪费内存;最好的方法当然是使用等差数列求和公式咯。

一般来说,我们对算法的评价是进行上面的时间效率和存储占用量分析,即时间复杂度和空间复杂度的分析。

算法的时间复杂度
时间复杂度T(n)——根据算法写成的程序在执行时耗费时间的长度。这个长度往往也与输入数据的规模有关。时间复杂度过高的低效算法可能导致我们在有生之年都等不到运行结果。一般分析时间复杂度,是分析算法里语句中哪一句或哪一部分的执行次数最多。这是时间复杂度的几个数量级及其大小关系:O(1) 1.2 绪论—— 算法(特点、评价标准、时间复杂度、空间复杂度)_第1张图片
举两个例子:

void Bubble_sort(int a[], int n)//冒泡排序  
{ /* 将a中整数序列重新排列成自小至大有序的整数序列 */
int i, j;
for (i=n-1; i>0 ; --i)  {
for (j=0; j<i; ++j)
if (a[j]>a[j+1])  {
w=a[j];  
a[j]=a[j+1]; 
a[j+1]=w;
}}} 

显然,冒泡排序中有镶嵌的两个for 循环,第一个for 循环执行n-1次,第二个for循环执行i次,即(n-1)+(n-2)+…+2+1,等差求和得(n*n-3n+2)/2,而for 循环里的各个语句的执行次数为1,所以时间复杂度的数量级为O(n^2)。下面再举一个常见的例子:

for(i=1;i<=n;i=i*2)
printf(“i=%d”,i);

仔细分析for循环,我们可以知道for循环执行nlogn次,所以其时间复杂度为O(nlogn)。
分析时还要注意里面是否调用函数,若有要看看函数的时间复杂度为多少再返回继续分析。
同时,一般时间复杂度为n*n的算法进行优化后可以降低为nlogn,一般可以借助二叉树。之后学到二叉树读者可自行感悟、分析。

算法的空间复杂度
空间复杂度S(n)——根据算法写成的程序在执行时 占用存储单元的长度。这个长度往往与输入数据的规模有关。空间复杂度过高的算法可能导致使用的内存超限,造成程序非正常中断。空间复杂度一般分析算法执行时额外需要的空间。比如上面的冒泡排序,他要执行的是排序,但在算法中需要用到额外的变量i、j,这两个变量自然需要额外的存储空间,不过并不多。再如,为什么我们要谨慎使用递归算法?以下面的代码举一个例子。比如你令q=1000000,那么算法要计算1+2+…+1000000,前999999次,它一直是执行return函数语句,直到递归到q=1时函数才有return明确的值,而在它进行最后一步计算时,前面的999999次都要存储下来,以便后面逆着计算回去。可以见得这要额外开辟多大的存储空间,一个系统在执行时使用多个算法,如果个个这么浪费存储空间那么系统将无法正常运行。

int f(int q)//计算1+2+3+...+q
{
if (q == 1 || q == 0)return 1;
else return f(q-2)+f(q-1);
}

你可能感兴趣的:(数据结构与算法,算法,数据结构)