数据结构之算法的时间复杂度和空间复杂度
创始人
2024-05-26 10:36:47
0

本章重点:

1.算法效率
2.时间复杂度
3.空间复杂度
4. 常见时间复杂度以及复杂度oj练习

目录

1.算法效率

1.2算法的复杂度

2.时间复杂度 

2.1  时间复杂度的概念

2.2 大O的渐进表示法

2.3常见时间复杂度计算举例

3.空间复杂度 

 4. 常见复杂度对比

5.复杂度的oj练习 

5.1消失的数字 

5.2旋转数组



1.算法效率


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

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

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


1.2算法的复杂度

 算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般
是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。在计算
机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计
算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

2.时间复杂度 

2.1  时间复杂度的概念

 可以将算法的时间复杂度看成是一个函数,类似于一个函数式子 F(N) = NN^{2} + 2*N + 10,算法中的基本操作的执行次数,为算法的时间复杂度。即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。
 

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;
}

这个函数执行的基本操作次数:可以用函数式子N^{2} + 2*N + 10

来表示当N 变化时候 

N = 10 F(N) = 130
N = 100 F(N) = 10210
N = 1000 F(N) = 1002010

对应的函数结果是不同的 那怎么衡量他的时间复杂度呢?实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法

2.2 大O的渐进表示法

 大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为:O(^{N^{2}})

N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000

通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。
另外有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)

2.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);
}

最差情况下 运行 2N + 10 大O渐进法 去掉影响因素较小的 以及系数,所以时间复杂度为O(N)

 实例2:

// 计算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\n", count);
}

这个程序中并没有介绍M 和N 的大小 所以时间复杂度为O(M + N).

实例3:
 

// 计算Func4的时间复杂度?
void Func4(int N)
{
int count = 0;
for (int k = 0; k < 100; ++ k)
{
++count;
}
printf("%d\n", count);
}

所有常数的时间复杂度都可以优化到O(1)。

实例4:
 

// 计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );

寻找字符串函数 最差情况就是O(N)

实例5:

// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
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;
}
}

 最好的情况下:是顺序的 只需要两两比较,只需要O(N),如果不是有序的 需要每个比较 那就是O(N方)

实例6:

// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
assert(a);
int begin = 0;
int end = n-1;
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;
}

二分查找,前提是有序 就像折纸一样,最悲观的情况 1 * 2 *2 *2 .......x = N 总共运行了x次

根据指数公式 x = \log 2^{^{N}}

 实例7:

// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N)
{
if(0 == N)
return 1;
return Fac(N-1)*N;

不为零 就要运行一次 一直运行到N = 0; 一共N + 1次 去掉没用的那就是O(N)

实例8:
 

// 计算斐波那契递归Fib的时间复杂度?
long long Fib(size_t N)
{
if(N < 3)
return 1;
return Fib(N-1) + Fib(N-2);
}

2^{0} + 2^{1} +2^{2} + 2^{3} +.......2^{N} 悲观计算法 时间复杂度 就是O(N) 

 

3.空间复杂度 

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用额外存储空间大小的量度 。
空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。
空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。
注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因
此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定
实例1:
 

// 计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{
assert(a);
for (size_t end = n; end > 0; --end)
{
int exchange = 0;
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;
}
}

额外变量只有一个 所以空间复杂度是O(1)

实例2:
 

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{
if(n==0)
return NULL;
long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n ; ++i)
{
fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
}
return fibArray;
}

额外申请了n+ 1 个空间 所以空间复杂度为O(N)

实例3:
 

// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
if(N == 0)
return 1;
return Fac(N-1)*N;
}

递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N)
 

 4. 常见复杂度对比

 

 

5.复杂度的oj练习 

5.1消失的数字 

#include
//  利用异或的知识点,交换律不改变最终结果,所以 定义一个变量 初始值为0,与数组异或后,在与给定数组异或,剩下的值就是我们要找的
int missingNumber(int* nums, int numsSize)
{int x = 0;for (int i = 0; i <= numsSize; i++)// 不缺失,所以正常数组大小比给定数组大小大1{x ^= i;}for (int i = 0; i < numsSize; i++){x ^= *(nums + i);}return x;
}
int main()
{int nums[100] = { 0 };int num = sizeof(nums) / sizeof(nums[0]);for (int i = 0; i < num; i++){scanf("%d", nums[i]);}printf("%d", missingNumber(nums, num));return 0;
}

5.2旋转数组

// 先封装一个转置函数
void reverse(int* pa, int left, int right)
{while (left < right){int temp = 0;temp = *(pa + left);*(pa + left) = *(pa + right);*(pa + right) = temp;++left;--right;}
}void rotate(int* nums, int numsSize, int k)
{if (k >= numsSize){k %= numsSize;}// 将前 numsSize - k - 1 个数 转置reverse(nums, 0, numsSize - k - 1);// 将后 k 个数 转置reverse(nums, numsSize - k, numsSize - 1);// 将整体转置 个数 转置reverse(nums, 0, numsSize - 1);}

 

 

相关内容

热门资讯

美味星球2的结局为什么是失败 美味星球2的结局为什么是失败美味星球的目标是吃掉一切,但那个乌龟塔无穷无尽,永远吃不完,所以灰粘质输...
旋律平稳中学生流行歌曲2015 旋律平稳中学生流行歌曲2015旋律平稳中学生流行歌曲2015中学时代,水木年华的明天你好 青春修炼...
氛围灯电压不稳怎么解决 氛围灯电压不稳怎么解决调整电路。纤兄氛围灯里面是有安装好的电路的,胡哗如果电压不稳,需要进行调整电路...
幼儿数学认知的核心目标是理解数... 幼儿数学认知的核心目标是理解数量关系。(  )幼儿数学认知的核心目标是理解数量关系。(  )A、正确...
求一首欧美MV歌曲的名字,一开... 求一首欧美MV歌曲的名字,一开始是一个美女准备开车,之后是跟几个男青年在跑车上唱歌,歌曲类型带点HI...
《伊索寓言》中“北风和太阳”的... 《伊索寓言》中“北风和太阳”的故事告诉了人们一个怎样的道理?   告诉我们  待人处事不是给人压...
200匹马力的摩托车,相当于多... 200匹马力的摩托车,相当于多少排量的自然吸气汽油发动机?摩托车200匹马力相当于汽车自然吸气的2....
找几个女孩爱听的笑话,要爆笑的... 找几个女孩爱听的笑话,要爆笑的。   2月30日 星期一 晴  今天一天都没有出太阳,真不好,...
求《蛇蝎女佣》第三季资源,谢谢... 求《蛇蝎女佣》第三季资源,谢谢~作品相关简介:《蛇蝎女佣》是2012-2013年的一部季中剧,将于2...
昂立无诀珠心算--项目介绍 昂立无诀珠心算--项目介绍孩子正在学,有些效果,希望宝加油!
小学生英语五年级下册单词表第7... 小学生英语五年级下册单词表第7课strawberry草莓 grape葡萄 like喜欢 some一些...
大话西游2三世界男魔转什么最好... 大话西游2三世界男魔转什么最好?这个就要看你喜欢什么啦!3世法满男魔转什么都是超敏的建议你转个女魔吧...
关于天龙八部中峨眉的灭式剑? 关于天龙八部中峨眉的灭式剑?别用灭剑了,浪费哦,绝剑加快回怒的速度,灭剑的血上限降低的状态消失时他的...
历史上过度依赖别人而失败的例子 历史上过度依赖别人而失败的例子张士诚——依赖自己的弟弟——结果他弟弟被杀,立刻一蹶不振吕布,依赖自己...
人活着本来就很累 很难 生活苦 人活着本来就很累 很难 生活苦对啊,可是还得好好生活,我每天都有很多烦恼。但我还想好好的生活,所以说...
师生关系有什么意义 师生关系有什么意义也可以是朋友一曰为师,终身为父当我们讨论意义的时候我们一般是在问这2个问题。1、对...
我给前女友发红包,他给我回你有... 我给前女友发红包,他给我回你有这个心就好了。我真的不能收 什么意思?既然是前女友她是不愿意欠你人情所...
描写春天的句子有哪些.短句 描写春天的句子有哪些.短句绿油油的小草从土地里钻出头来,树上的花儿也竞放出鲜艳的小花朵,到处都是一片...
炸酱面的做法详细步骤 炸酱面的做法详细步骤这道菜是在看一期美食节目里学习到的,当时教的是韩式炸酱面,我自己根据家里有的现有...
邻居知道我家是超市还在门口卖水... 邻居知道我家是超市还在门口卖水怎么办?邻居知道你家是超市在门口卖水又怎样呢?他又管不了你,如果你是正...