时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所消耗的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。
即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。
请计算一下Func1中++count语句总共执行了多少次?
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
",count);
}
它的复杂度是跟一个N相关的函数式
从上往下看,第一个循环外面循环N次,里面也循环N次,所以第一个循环复杂度也就是F(N)=N*N
第二个循环是循环2倍的N,所以也就是2*N,加上第一个循环,复杂度也就是F(N)=N*N+2*N
第三个循环,因为M是确定的,所以加10就可以了,复杂度F(N)=N*N+2*N+10
算出来这个表达式以后再去给他值
当N是10的时候,F(N)=10^2+2*10+10=130
当N是100的时候,F(N)=100^2+2*100+10=10210
当N是1000的时候,F(N)=1000^2+2*100+10=1002010
把表达式简化,只关注影响最大的项,也就是F(N)=N^2,N越大,2*N+10对结果的影响越小,N^2的占比也越大
实际中我们计算空间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法。
先计算精确的,再计算对结果影响最大的保留下来就行(不是这个准确的值,而是这个值的估算)
那么Func1的时间复杂度:O(N^2)
大O的渐进表示法
大O符号(Big O notation):是用于描述函数渐进行为的数学符号。推到大O阶方法:
1.用常数1取代运行时间中所有加法常数。
2.在修改后的运行次数函数中,只保留最高阶项。
3.如果高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶
//计算实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
", count);
}
这题的时间复杂度为O(N),精确的算法是2N+10,N越大10对结果的影响也就越小,当N无限大的时候2N和N是一个级别,像上面说的,高阶项存在且不是1,所以去除这个相乘的常数所以为O(N)
计算Func3的时间复杂度?
void Func3(int N, int M) {
int count = 0;
for (int k = 0; k < M; ++k) {
++count;
}
for (int k = 0; k < N; ++K) {
++count;
}
printf("%d
", count);
}
这段代码的时间复杂度是O(M+N)
一般情况下时间复杂度计算时间未知数都是用的N但是也可以是M、K、X等等其它的
如果M远大于N,结果就是O(M)
如果N远大于M,结果就是O(N)
如果M和N差不多大,结果就是O(M)或O(N)
没有说名M和N的大小关系,结果就是O(M+N)
计算Func4的时间复杂度?
void Func4(int N) {
int count = 0;
for (int k = 0; k < 100; ++k) {
++count;
}
printf("%d
", count);
}
这题的时间复杂度为O(1)
因为没有未知数了,K<100是个常数,也就是把常数换成1,所以结果是O(1)
O(1)不是代表算法运行一次,是常数次
计算strchr的时间复杂度?
const char * strchr (const char * str, int character);
这段代码是查找字符的库函数
while(*str)
{
if(*str==character)
{
return str;
}
else
++str;
}
最好的情况是1,平均的情况是N/2,最坏的情况是N
当一个算法随着输入不同,时间复杂度不同,时间复杂做悲观预期,看最坏的情况,所以是O(N)
计算冒泡排序的时间复杂度?
void bubblesort(int *a, int n) {
assert(a);
for (size_t end = n; end > 0; --end) {
for (size_t i = 1; i < end; ++i) {
if (a[i - 1] > a[i]) {
Swap(&a[i - 1], &a[i])
exchange = 1;
}
}
if (exchange == 0)
break;
}
等差数列,比较次数是N-1,N-2,N-3……
精确的时间复杂度是F(N)=N*(N-1)/2
N阶数不一样,我们只去看阶数最高的那一项,所以时间复杂度是:O(N^2)
int Binarysearch(int *a,int n,int x)
{
assert(a);
int begin=0;
int end=n;
while(begin<end)
{
int mid=begin+((end-begin)>>1)
if(a[mid]<x)
begin=mid+1;
else if(a[mid]>x)
end=mid;
else
return mid;
}
return -1;
}
这个时间复杂度是O(log以2为底N次方) O(log2N)
假设我们要查找x次,因为每次都折半也就是2^x次,也就是x=log2N