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

 更新时间:2020年03月11日 10:28:51   作者:WFaceBoss  
这篇文章主要介绍了Java均摊复杂度和防止复杂度的震荡,结合实例形式分析了Java均摊复杂度和防止复杂度的震荡相关概念、原理、实现方法与注意事项,需要的朋友可以参考下

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

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

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

resize(n)   O(n)

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

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)

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

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

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

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

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

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

 

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

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

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

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

  //从数组中删除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相关内容感兴趣的读者可查看本站专题:《Java数组操作技巧总结》、《Java字符与字符串操作技巧总结》、《Java数学运算技巧总结》、《Java数据结构与算法教程》及《Java操作DOM节点技巧总结

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

相关文章

  • Java之关于基本数据类型和引用数据类型的存放位置

    Java之关于基本数据类型和引用数据类型的存放位置

    这篇文章主要介绍了Java之关于基本数据类型和引用数据类型的存放位置,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Spring Boot部署到Tomcat过程中遇到的问题汇总

    Spring Boot部署到Tomcat过程中遇到的问题汇总

    这篇文章主要给大家分享了关于Spring Boot部署到Tomcat过程中遇到的一些问题,文中将解决的方法介绍非常详细,对同样遇到这个问题的朋友具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-03-03
  • 基于JavaMail实现简单邮件发送

    基于JavaMail实现简单邮件发送

    这篇文章主要为大家详细介绍了基于JavaMail实现简单邮件发送,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • IntelliJ IDEA中如何构建Spring Boot的项目

    IntelliJ IDEA中如何构建Spring Boot的项目

    这篇文章主要介绍了IntelliJ IDEA中如何构建Spring Boot的项目问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • java:无法访问org.springframework.boot.SpringApplication问题

    java:无法访问org.springframework.boot.SpringApplication问题

    这篇文章主要介绍了java:无法访问org.springframework.boot.SpringApplication问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • springboot整合flowable框架入门步骤

    springboot整合flowable框架入门步骤

    最近工作中有用到工作流的开发,引入了flowable工作流框架,在此记录一下springboot整合flowable工作流框架的过程,感兴趣的朋友一起看看吧
    2022-04-04
  • SpringBoot拦截器的使用

    SpringBoot拦截器的使用

    这篇文章主要给大家分享的是SpringBoot拦截器的使用,拦截器通常通过动态代理的方式来执行。拦截器的生命周期由IoC容器管理,可以通过注入等方式来获取其他Bean的实例,使用更方便,下面文章的详细内容,需要的朋友可以参考一下
    2021-11-11
  • 简单介绍一下什么是microservice微服务

    简单介绍一下什么是microservice微服务

    这篇文章主要介绍了一下什么是microservice微服务微服务的定义,微服务到底是什么意思?什么样的架构可以叫做微服务?这篇文章可以给你答案
    2023-03-03
  • Java8中StringJoiner类的使用详解

    Java8中StringJoiner类的使用详解

    Java在java.util包中添加了一个新的最终类StringJoiner。可以用于构造由定界符分隔的字符序列。本文将通过示例和大家分享一下StringJoiner类的使用,需要的可以参考一下
    2022-10-10
  • SpringBoot优化启动速度的方法实现

    SpringBoot优化启动速度的方法实现

    本篇文章主要介绍了SpringBoot优化启动速度的方法实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01

最新评论