数据结构(1.2.2) -- 算法的时间复杂度

一、什么是时间复杂度

  • 时间复杂度:评价算法的时间开销的一个指标

二、如何计算

  • 事后估计:让算法运行一下,看看花费时间;存在问题:和机器性能有关、和编程语言有关、和编译程序产生的机器指令质量有关、有些算法不能事后统计
  • 事先估计:事前预估算法时间开销T(n)与问题规模n的关系(T表示time) --即时间复杂度表达式

三、算法例子

void loveYou(int n) // n为问题规模
{
    
    
①	int i=1; // 爱你的程度
②	while(i<=n)
	{
    
    
③		i++; // 每次+1
④		printf("I Love You %d\n", i);
	}
⑤	printf("I Love You More Than %d\n", n);
}

int main()
{
    
    
	loveYou(3000);
}

解:假设n为3000

  • 语句频度:① --1次;② --3001次;③ --3000次;④ --3000次;⑤ --1次
  • 耗时:T(3000) = 1 + 3001 + 2*3000 + 1
  • 时间开销与问题规模n的关系:T(n) = 3n + 3 = O(n)

四、大O表示法

  • 基本概念:大O表示"同阶",同等数量级。即:当n -> ∞时,二者之比为常数
  • 加法规则:T(n) = T₁(n) + T₂(n) = O(f(n)) + O(g(n)) = O(max{f(n), g(n)}) --只保留最高阶,且系数为1
  • 乘法规则:T(n) = T₁(n) × T₂(n) = O(f(n)) × O(g(n)) = O(f(n) × g(n))
  • 小结:之前求T(n)是一行一行代码数的,当代码很多时不适用。
    • 结论1. 顺序执行的代码只会影响常数项,可以忽略
    • 结论2. 只需挑循环中的一个基本操作分析它的执行次数与n的关系即可

五、小练习1:指数递增型爱你

void loveYou(int n) // n为问题规模
{
    
    
	int i=1; // 爱你的程度
	while(i<=n)
	{
    
    
		i=i*2; // 每次翻倍
		printf("I Love You %d\n", i);
	}
	printf("I Love You More Than %d\n", n);
}
解:设最深层循环的语句频度(总共循环的次数)为x,则
	由循环条件可知,循环结束时刚好满足2^x>n
	x = log₂n + 1
	T(n) = O(x) = O(log₂n) + O(1) = O(log₂n)

六、小练习2:搜索数字型爱你

void loveYou(int flag[], int n) // n为问题规模
{
    
    
	printf("I Am Iron Man\n");
	for(int i=0; i<n; i++) // 从第一个元素开始查找
	{
    
    
		if(flag[i]==n) // 找到元素n
		{
    
    
			printf("I Love You %d\n", n);
			break; // 找到后立即跳出循环
		}
	}
}
解:
最好情况:元素n在第一个位置 --最好时间复杂度T(n)=O(1)
最坏情况:元素n在最后一个位置 --最坏时间复杂度T(n)=O(n)
平均情况:假设元素n在任意一个位置的概率相同为1/n --平均时间复杂度T(n)=O(n)
		 循环次数x=(1+2+3+...+n)*1/n=(n(1+n)/2)*1/n=(1+n)/2(期望值) T(n)=O(n)

猜你喜欢

转载自blog.csdn.net/m0_46218511/article/details/107753118