时间复杂度

44 阅读5分钟

什么是数据结构?

数据结构是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。

什么是算法?

算法就是定义良好的计算过程,他取一个或取一组的值为输入,并产生一个或一组作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。

1.算法效率

1.1如何衡量一个算法的好坏

如何衡量一个算法的好坏呢?比如对于一下斐波那契数列

long long Fib(int n)
{
  if(n<3)
    return 1;
    
  return Fib(n-1)+Fib(n-2);
}

斐波那契数列的递归实现方式非常简洁,但简介一定好吗?如何衡量好坏呢?

1.2算法的复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。

时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间

2.时间复杂度

在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法所花费的时间与其中语句的执行次数成正比,算法中基本操作的执行次数,为算法的时间复杂度

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出来该算法的时间复杂度。

T(n)=O(f(n))

for (int i = 0; i < n; i++) //频率为 n+1
{
	for (int j = 0; j < n; j++) //频率为 n*(n+1)
	{
		c[i][j]=0; //频率为 n*n
		for(int k=0;k<n;k++) //频率为 n*n*(n+1)
		{
		  c[i][j]=c[i][j]+b[k][j]; //频率为 n*n*n
		}
}

2.1时间复杂度的计算

步骤 1:确定「基本操作」

基本操作是算法中执行次数最多、最核心的原子操作(通常是循环体内部的赋值、比较、运算等,执行 1 次耗时固定)。

例:循环中的 a[i] = iif (x > y)sum++ 均为基本操作。

步骤 2:统计基本操作的「执行次数」

根据输入规模 n,分析循环、递归等结构对执行次数的影响,写出次数表达式 T(n)。

  • 循环结构:重点看循环的「迭代次数」(而非循环变量的初始值 / 步长,除非步长随 n 变化)。
  • 递归结构:写出递归方程,通过递推或主定理求解(下文单独讲解)。
步骤 3:简化为大 O 记法

遵循 3 条规则:

  1. 忽略常数项:T(n)=n+5 → O(n);
  2. 忽略低次项:T*(n)=n^2^+3n* → O(n^2^);
  3. 忽略最高次项的系数:T(n)=5n^3^ → O(n^3^)。

2.2常见时间复杂度

复杂度名称适用场景示例
O(1)常数时间无循环 / 递归,固定操作数数组访问、简单运算
O(logn)对数时间每次操作将问题规模减半二分查找、平衡二叉树操作
O(n)线性时间单循环遍历所有元素数组遍历、线性查找
O(nlogn)线性对数时间分治思想(循环 + 二分)归并排序、快速排序
O(n^2^)平方时间双重嵌套循环冒泡排序、插入排序
O(n^k^)多项式时间k 重嵌套循环多维数组遍历
O(2^n^)指数时间暴力枚举(子集、排列)斐波那契递归(无记忆化)
O(n!)阶乘时间全排列生成旅行商问题暴力解法

场景1:常数时间(O(1))

特征:无循环、无递归,操作数与 n 无关,固定次数。

x++; //频率为1
s=0; //频率为1
for(int i=0;i<1000;i++)
{
  x++; 
  s=0; 
}

场景2:线性时间(O(n))

特征:单循环,循环次数与 n 成正比(遍历所有元素 1 次)。

for(int i=0;i<n;i++)
{
  x++; 
  s=0; 
}

场景 3:平方时间 O(n^2^)

特征:双重嵌套循环,外层循环 n 次,内层循环每次也 n次(总次数 n×n=n^2^)。

x=0;
y=0;
for(int K=0;K<n;K++)
{
  x++;
}
for(int i=0;i<n;i++)
{
  for(int j=0;j<n;j++)
  {
    j++;
  }
}

场景 4:对数时间 O(logn)

特征:每次循环将问题规模「减半」(循环次数为 log2n,底数可忽略,记为 logn)。

for(int i=0;i<n;i=i*2)
{
  x++;
  s=0;
}
次数1234t
i1248?
i2^0^2^1^2^2^2^3^2^t-1^

ee9f6c0e41f15454976caf73a75cde06.png

场景五:线性对数时间 O(nlogn)

特征:外层循环 n 次,内层循环 logn 次(总次数 n×logn),常见于高效排序算法。

int sum=0;
for(int i=0;i<n;i++)
{
  for(int j=1;j<n;j=j*2)
  {
    sum++;
  }
}

计算时间复杂度

1.设n是描述问题规模的非负整数,下面程序片段的时间复杂度是()。

x=2;
while(x<n/2)
  x=2*x;

==A.O (log2n)== B.O (n) C.O(nlog2n) D.O (n^2^)

次数1234t
x2^2^2^3^2^4^2^5^2^t+1^

2^t+1^=n/2 2^t+2^=n log22^t+2^=log2n t+2=log2n t=log2n-2

T(n)=log2n-2 =O(log2n)

2.下列函数的时间复杂度是()。

int fun(int n)
{
  int i=0,sum=0;
  while(sum<n) sum += ++i;
  return i;
}

A.O (logn) ==B.O (n^1/2^)== C.O (n) D.O(nlog2n)

次数1234t
i1234t
sum1234t(t+1)/2

t(t+1)/2=n

t(t=1)=2n

t^2^+t=2n

t^2^约等于2n

T(n)=O (n^1/2^)

3.下列程序的时间复杂度是()。

int sum=0;
for(int i=1;i<n;i*=2)
  for(int j=0;j<i;j++)
    sum++;

A.O (logn) ==B.O (n)== C.O (nlogn) D.O(n^2^)

次数1234t
i2^0^2^1^2^2^2^3^2^t-1^
内层次数2^0^2^1^2^2^2^3^2^t-1^
  • 外层循环: i 从1开始,每次乘以2,直到 i < n ,执行次数是 log₂n 次
  • 内层循环:每次外层循环时, j 从0到 i-1 ,执行次数等于当前的 i 值。
  • 总执行次数: 1 + 2 + 4 + ... + 2^(log₂n - 1) ,这是等比数列求和,结果为 n - 1 ,时间复杂度是 O(n)。