1.概念
时间复杂度是一个函数,用于定量描述该算法的运行时间。
算法中的基本操作执行次数,为算法的时间复杂度。
举例:
- //语句中count++;被执行多少次?
-
- void func(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(N) = N^2 + 2*N + 10
当N->无穷大时,后两项对整个结果的影响将忽略不计。
为表达方便,采用大O渐近表示法。
打O符号:用于描述函数渐近行为的数学符号。
推导大O阶方法
1)用常数1取代运行时间中的所有加法函数。
2)再修改后的运行次数函数中,只保留最高阶项。
3)如果最高阶项存在且不是1,则去除与这个项数相乘的常数,得到的结果就是大O阶。
一般关注的都是最坏的运行情况。
举例:
- //计算count++被运行了多少次?
- void fun()
- {
- int count = 0;
- for (int i = 0; i < 100; i++)
- {
- count++;
- }
- printf("%d\n", count);
- }
循环了100次,按照大O阶规则为O(1).
- //语句中count++;被执行多少次?
-
- void func(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(N) = N+2*N+10,根据大O阶表示为:O(N^2)
- //计算时间复杂度
- void fun(int N, int M)
- {
- int count = 0;
- for (int i = 0; i < M; i++)
- {
- count++;
- }
- for (int i = 0; i < N; i++)
- {
- count++;
- }
- printf("%d\n", count);
- }
N和M的未知,则可表示为O(N+M)
对于冒泡函数可知
- void Bubble_sort(int* a, int n)
- {
- for (int end = n; end > 0; end--)
- {
- int exchange = 0;
- for (int i = 1; i < end; i++)
- {
- if (a[i - 1] > a[i])
- {
- swap(&a[i], &a[i - 1]);
- exchange = 1;
- }
- }
- if (exchange == 0)
- break;
- }
- }
最坏的情况f(N) = (N-1)*Nhttps://files.jxasp.com/image/2
最好的情况:f(N) = N
所以冒泡的时间复杂度为O(N^2)
二分的时间复杂度
- int BinarySearch(int* a, int n, int x)
- {
- 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(1)
最坏的情况 :O(logN)
f(N) = Nhttps://files.jxasp.com/image/2https://files.jxasp.com/image/2....https://files.jxasp.com/image/2 = 1; --> 2^x = N -->x = logN
注意:时间复杂度中会将写为logN
进阶:
递归算法时间复杂度计算
1)每次函数调用是O(1),那么就看他的递归次数。
2)每次函数调用不是O(1),那么就看他的递归调用次数的累加。
举例:
- int fun(int N)
- {
- if (N == 0)
- return 1;
- return N * fun(N - 1);
- }
时间复杂度为O(N)
第一次: N*fun(N-1)
第二次:(N-1)*fun(N-2)
……
第N-1次 1*fun(0)
第N次:1
这个为第一个情形,只需看其递归次数。
- int fun(int N)
- {
- if (N == 0)
- {
- return 1;
- }
- for (int i = 0; i < N; i++)
- {
- printf("%d\n", i);
- }
- printf("\n");
- return fun(N - 1) * N;
- }
第一次递归:执行循环 N次
第二次递归: 执行循环N-1次
……
第N-1次:执行循环2次
第N次:执行循环 1 次
求和可知f(N) = N+N-1+N-2+…+1 = N*(N+1)https://files.jxasp.com/image/2 ~ N^2
这个是第二种情况
计算斐波那契数列递归写法的时间复杂度
- int fun(int N)
- {
- if (N < 3)
- return 1;
- return fun(N - 1) + fun(N - 2);
- }
时间复杂度为O(2^N)
计算过程:
开始语句: fun(N)
第一次: fun(N-1) + fun(N-2)
第二次:fun(N-2)+fun(N-3) + fun(N-3)+fun(N-4)
……
可知:
每次调用两次,递归循环N次
f(N) = 1+2+4+……+2^(N-2) ~ 2^N
小白一只,出错请斧正。