时间复杂度

举报
用户已注销 发表于 2021/11/19 03:52:50 2021/11/19
【摘要】 目录 一,确定性算法 1,已知数组中有且仅有一个负数,找到这个负数 2,插入排序 3,快速排序 二,随机算法 1,已知数组中有且仅有一个负数,找到这个负数 2,已知数组中存在负数,找出任意一个负数 三,分治算法的时间复杂度 1,主定理的简化版本 2,主定理 3,Akra-Bazzi定理的简化版本 4,Akra-B...

目录

一,确定性算法

1,已知数组中有且仅有一个负数,找到这个负数

2,插入排序

3,快速排序

二,随机算法

1,已知数组中有且仅有一个负数,找到这个负数

2,已知数组中存在负数,找出任意一个负数

三,分治算法的时间复杂度

1,主定理的简化版本

2,主定理

3,Akra-Bazzi定理的简化版本

4,Akra-Bazzi定理

5,Leighton定理

四,常见时间复杂度和数据规模

五,平摊分析

1,平摊分析

2,聚集分析

(1)栈操作

(2)二进制计数器

3,记账方法

(1)栈操作

(2)二进制计数器

4,势能方法

(1)栈操作

(2)二进制计数器

5,动态表

(1)动态表扩张

(2)动态表扩张和收缩


一,确定性算法

确定性算法的时间复杂度,一般有2个维度:好坏情况,上下界

1,已知数组中有且仅有一个负数,找到这个负数

采用枚举法,代码:


  
  1. int findNegative(vector<int>v)
  2. {
  3. for (int i = 0; i < v.size(); i++)if (v[i] < 0)return v[i];
  4. return 0;
  5. }

最好情况:一次找到

最坏情况:最后一次才找到

平均情况:找了一半元素才找到

时间复杂度

渐进下界Ω

渐进上界O

渐进确界θ

最好情况

1

1

1

最坏情况

n

n

n

平均情况

n

n

n

 

2,插入排序

时间复杂度

渐进下界Ω

渐进上界O

渐进确界θ

最好情况

n

n

n

最坏情况

n^2

n^2

n^2

平均情况

n^2

n^2

n^2

插入排序的最坏情况下,渐进下界为Ω(n^2),也可以说是Ω(n)

渐进上界为O(n^2),也可以说是 O(n^3)


3,快速排序

快速排序的好坏平均,其实是分2个维度,一个是数列中元素和元素重复的程度,一个是分治划分的均匀程度。

时间复杂度

渐进下界Ω

渐进上界O

渐进确界θ

最好情况

n logn

n logn

n logn

最坏情况

n^2

n^2

n^2

平均情况

n logn

n^2

/

如果限定所有元素都互不相同,那么好坏平均只涉及分治划分的均匀程度,那么渐进确界为O(n logn)

 

二,随机算法

随机算法的好坏平均,分2个维度,一个是问题需要处理的数据的好坏,一个是算法本身采用的随机数的好坏

快速排序选取划分节点的这一步,可以随机选一个,也可以固定选待排序段的第一个元素,本质上是一样的,所以也可以说快速排序也是一种随机算法

1,已知数组中有且仅有一个负数,找到这个负数

不断随机尝试,代码:


  
  1. int findNegative(vector<int>v)
  2. {
  3. while (true) {
  4. int i = rand() % v.size();
  5. if (v[i] < 0)return v[i];
  6. }
  7. }

假设rand函数的随机数范围足以覆盖v.size()的大小。

最好情况:一次找到

最坏情况:永远找不到

平均情况:尝试次数的均值恰好是n

时间复杂度

渐进下界Ω

渐进上界O

渐进确界θ

最好情况

1

1

1

最坏情况

平均情况

n

n

n

2,已知数组中存在负数,找出任意一个负数

算法同上,代码不变。

数据的最好情况:全都是负数

数据的最坏情况:只有一个负数

数据的平均情况:恰好有一半是负数

时间复杂度

算法最好情况

算法最坏情况

算法平均情况

数据最好情况

θ(1)

θ(1)

θ(1)

数据最坏情况

θ(1)

Ω(∀)

θ(n)

数据平均情况

θ(1)

Ω(∀)

θ(1)

PS:

恰好有一半是负数时,尝试次数的均值恰好是2,所以是θ(1)

 

三,分治算法的时间复杂度

1,主定理的简化版本

 

考虑形如T(n)=aT(n/b)+\Theta(n^d)的递归式,

  • 如果a>b^d,那么T(n)=\Theta(n^{\log_ba})
  • 如果a=b^d,那么T(n)=\Theta(n^d\log n)
  • 如果a<b^d,那么T(n)=\Theta(n^d)

2,主定理

主定理是用来求分治算法的时间复杂度的公式定理。

分析:

这个递推式其实不难求解,就是高中数学里面的数列递推式,做个n = b^t 的代换即可,后面就是三种类型的级数求和、对数的换底公式。

(3)中,其实前半句所描述的条件可以省略,因为 af(n/b) <= cf(n) 就包含了 f(n) = Ω(n^...)这个条件。

3,Akra-Bazzi定理的简化版本

4,Akra-Bazzi定理

5,Leighton定理

 

四,常见时间复杂度和数据规模

ACM里面,常见的时间复杂度和数据规模的对应关系:

O(n^2) n=10^3-10^4

O(nlong) n=10^4 - 10^6

O(n) n=10^6 - 10^8

O(sqrt(n)) n=10^8 – max_int

O(log n) n=10^8 – max_int

 

五,平摊分析

1,平摊分析

平摊分析指的是一系列操作执行的平均时间。

和平均情况下的时间复杂度不同,平摊分析指的是最坏情况下,一系列操作的平均时间。

例如:


  
  1. int x[100];
  2. void out(int id)
  3. {
  4. if(id==88)for(int i=0;i<100;i++)cout<<x[i];
  5. }
  6. void out2()
  7. {
  8. for(int i=0;i<100;i++)out(i);
  9. }

首先,out函数在最坏情况下是O(n),在平均情况下是O(1)

其次,out2函数在平均情况下是O(n),这几个都是毫无疑问的。

那么out2函数的最坏情况呢?

在不知道out函数的内部实现的情况下,只知道out函数在最坏情况下是O(n),在平均情况下是O(1),我们对out2函数的最坏时间复杂度的评估只能是O(n^2)

但是在知道out函数的内部实现之后,我们发现out2的最坏时间复杂度是O(n)

所以,我们可以把out函数在平均情况下是O(1)表述成,n次调用out函数的平摊时间复杂度是O(1)

2,聚集分析

聚集分析指的是,要求平摊性能,可以先求n个操作的总时间T(n),然后就能得到平摊时间T(n)/n

(1)栈操作

假设push和pop的时间都是O(1),考虑一个新操作multiPop,它可以一直执行pop操作直到清空栈

如果有n个操作,每个操作都是push、pop、multiPop中的一个,初始栈是空的,

那么multiPop的时间复杂度是O(n),因为最多只有n-1个元素可以弹出

然而n次操作的平摊时间是O(1),因为其中所有multiPop操作的弹出元素数目总和不会超过n-1

(2)二进制计数器

一个k位的整数初始值为0,执行n次加1操作,会有多少次进位呢?(n<2^k)

比如1到2是1次进位,11到12是2次进位。

单次操作最多有k次进位,但单次操作的平摊时间是O(1)

3,记账方法

记账方法是给每种操作赋予一个平摊代价,这个值可能大于也可能小于实际代价,我们把平摊代价大于实际代价的部分,称为存款。

但是根据平摊代价计算出来的总代价,一定不低于实际总代价。

(1)栈操作

以栈为例,我们分别赋予push、pop、multiPop平摊代价2、0、0

那么据此算出来的总代价上限是2n,即O(n),而实际总代价的上限是2n-2,即O(n)

(2)二进制计数器

把一位上的0变成1的子操作赋予平摊代价2元,把1变成0的操作赋予平摊代价0元,

0变成1的时候,1元是实际代价,1元是存款,所以每一位值为1的位上都有1元存款,所以1变成0的时候只需要存款即可,这样,总平摊代价就不低于实际总代价。

这样,单次操作的平摊代价就是2了,即O(1)

4,势能方法

势能方法就是给整个状态赋予一个数,叫做势能,或者势。

把平摊代价表示为实际代价加上势能的增量,那么总平摊代价减去实际总代价就等于最终势能减去初始势能。

所以要想总平摊代价不低于实际总代价,就需要任何时刻的势能都不低于初始势能。

(1)栈操作

用栈中的元素个数,表示整个栈的势能。

那么,push、pop、multiPop的平摊代价分别为2、0、0

(2)二进制计数器

用位值为1的个数,表示整个计数器的势能,

那么,单次操作的平摊代价就是2

5,动态表

按照平摊性能的思路,考虑如何设计动态表的扩张和收缩。

假设单次插入和删除操作是O(1),只需要考虑扩张和收缩如何设计。

(1)动态表扩张

扩张的设计比较简单,表的元素个数达到预留空间大小时,就分配一个新的空间,大小翻一倍,然后把元素全部copy过去。

这样,单次插入操作的平摊性能是3

(2)动态表扩张和收缩

如果表的收缩采取类似的措施,当装载因子低于1/2的时候,就分配一个新空间,大小为原来的一半,那么就有可能,元素个数在分界线处不断徘徊,就需要不断扩张和收缩,时间复杂度很高。

所以,收缩的阈值必须更低。

以1/4为例,每次当装载因子低于1/4时,就分配一个新空间,大小为原来的一半。

那么,一些列扩张和收缩操作的平摊性能还是3

 

文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nameofcsdn/article/details/115269383

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。