Java实现均摊_Java均摊复杂度和防止复杂度的震荡原理分析

本文实例讲述了Java均摊复杂度和防止复杂度的震荡。分享给大家供大家参考,具体如下:

关于上一节封装数组的简单复杂度分析方法中我们对添加操作的时间复杂度归结为O(n)是考虑了扩容操作(resize)在内的。就addLast(e)操作而言,时间复杂度为O(1),在考虑最坏情况下,每次添加均会触发扩容操作,需要移动n个元素,因此此时addLast操作的时间复杂度为O(n)。

(1)addLast(e)均摊时间复杂度分析

565713c663b7066c636d93bea6caa36c.png

resize(n)   O(n)

假设当前capacity=8,并且每一次添加操作都使用addLast方法

1ce5c401953ae95343f8757b1320615c.png

17次基本操作包括:9次添加操作,8次转移操作。均摊每次addLast操作进行大约两次基本操作:

平均值为:17/9≈ 2。

假设capacity=n,n+1次addLast操作,触发resize,总共进行了2n+1=(n+1)+ n次基本操作;

均摊每次addLast操作进行大约两次基本操作:

平均值为: 2n+1 / n+1 ≈ 2

结论:因此addLast均摊时间复杂度为O(1),均摊时间复杂度会比最坏情况有意义,因为一般情况下resize不会每一次都会触发,因此可以分摊到其他上面。

同理,removeLast操作均摊时间复杂度也是O(1)

(1)addLast(e)和removeLast(e)复杂度震荡分析

设数组的容量为n,此时数组中的个数为n个,此时我们向数组中添加一个元素,则会触发扩容操作;然后在从数组中删除一个元素时又会重新触发缩容操作,这样反复执行都会耗费O(n)的复杂度,导致复杂度震荡。

演示如下:

第一次执行addLast(e)时间复杂度:O(n)

86a43070945b7a222c45147d4b137f3d.png

第二次执行removeLast(e)时间复杂度:O(n)

f6afbd2975dfc7f94cb430e8a85dc01e.png

第三次执行addLast(e)时间复杂度:O(n)

1737d1a8213d9f9a6da4b3f8300aeeaa.png

第四次执行removeLast(e)时间复杂度:O(n)

be1a98d12253020697db6dec39371ca6.png

产生复杂度震荡的原因为:removeLast时resize过于着急(Eager)。

解决办法为:Lazy(remove延迟执行resize)

容量2n,size=n+1时:

941688ee18d99f8a2d1326ce07614507.png

容量2n,size=n时,进行缩容1/2:

fea6e265fca60be9e75b87f477d97254.png

容量2n,size=1/4*2n,进行缩容1/2  :

2ca7b953c7f2ed421f4230d0d8509d39.png

ed46473c8df9b0ea367cb1bd4700a88b.png

当size==capacity/4时,才将capacity减半。

现在我们来进一步改进我们的程序代码:

06a8406971604a744a0bc74576ac9cca.png

//从数组中删除index位置的元素,返回删除的元素

public E remove(int index) {

//1.判断索引的选择是否合法

if (index < 0 || index > size)

throw new IllegalArgumentException("您选择的位置不合法");

//2.先存储需要删除的索引对应的值

E ret = data[index];

//将索引为index之后(index)的元素依次向前移动

for (int i = index + 1; i < size; i++) {

//3.执行删除--实质为索引为index之后(index)的元素依次向前移动,将元素覆盖

data[i - 1] = data[i];

}

//4.维护size变量

size--;

// loitering objects != memory leak 手动释放内存空间

data[size] = null;

//缩容操作

if (size == data.length / 4 && data.length != 0) {

resize(data.length / 2);

}

//5.返回被删除的元素

return ret;

}

到此我们完成了一个比较完善的动态数组的封装。

希望本文所述对大家java程序设计有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值