复杂度
纲要:
算法效率
时间复杂度
概念
大O的渐进表示法
示例
空间复杂度
概念
示例
在我们学习完C语言之后,我们就要蹦着向更高处走了,所以今天,我们来到了数据结构。
下面呢,就正式开启数据结构的大门!
一.算法效率
算法效率分析分为两种:
1.时间效率
时间效率又叫做时间复杂度,它衡量的主要是一个算法的运行速度。
2.空间效率
空间效率又叫做空间复杂度,它衡量的主要是一个算法所需要的额外空间。在计算机发展的早期,因为科技水平有限,往往计算机的容量很少,但如今科技急速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。
二.时间复杂度
1.概念
在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一 个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是同一个算法在不同性能的机器上也会有不同的差异,所以才有了时间复杂度这个分析方式。
因一个算法所花费的时间与其中语句的执行次数成正比例,所以,算法中的基本操作的执行次数,为算法的时间复杂度。
比如所如下代码,它的执行次数为多少呢?
复制代码
#include <stdio.h>
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
for (int j = 0; j < N ; ++ j)
{
++count;
}
}
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M–)
{
++count;
}
printf("%d\n", count);
}
复制代码
显而易见,它的执行次数为 F=NN+2N+10;
往往我们在计算时间复杂度的时候,我们写的是一个概数,为什么呢?
我们不妨设想一下,对于上面的执行次数函数,当N趋向于无穷大时,那个10对于它的影响微乎其微。如果是一个高阶函数,这个函数的大小往往取决于表达式中次数最高的项,所以我们的时间复杂度也采取这种思想。
我们不妨来测试一下:
复制代码
#include <stdio.h>
#include <time.h>
void Func1(int N)
{
int start = clock();
int count = 0;
for (int i = 0; i < N ; ++ i)
{
for (int j = 0; j < N ; ++ j)
{
++count;
}
}
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M–)
{
++count;
}
int end = clock();
printf("%d\n", end - start);//单位为毫秒
}
int main()
{
Func1(0);//0
Func1(100);//0
Func1(10000);//386
return 0;
}
复制代码
我们发现,差异主要是在最高次上面。所以接下来我们来介绍大O的渐进表示法。
2.大O的渐进表示法
实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。
大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
所以,使用大O的渐进表示法以后,Func1的时间复杂度为:O(N^2);
通过上面,我们可以得到现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:
复制代码
//描述:传递一个数组,给定一个数,查找该数组中是否含有这个数
int FindNum(int* arr,int N,int search_num)
{
int i = 0;
for(i=0;i<len;i++)
{
if(search_num == arr[i])
return 1;//找到则返回 1
}
return 0;//找不到则返回 0
}
复制代码
它的最好情况为 1 ,即只执行一次就找到了
平均情况:N/2
最差情况: N ,遍历了整个数组。
那么,对于这个算法,它的时间复杂度是多少呢?答案是: O(N)
在计算时间复杂度时,我们往往取得是它的最差情况。
3.示例
复制代码
// 1.计算Func2的时间复杂度?
void Func2(int N)
{
int count = 0;
for (int k = 0; k < 2 * N ; ++ k)
{
++count;
}
int M = 10;
while (M–)
{
++count;
}
printf("%d\n", count);
}
复制代码
它的时间复杂度为多少呢? ---- O(N)
复制代码
// 2.计算Func3的时间复杂度?
void Func3(int N, int M)
{
int count = 0;
for (int k = 0; k < M; ++ k)
{