均摊复杂度和防止复杂度的震荡

resize的复杂度分析

    // 数组扩容

    private void resize(int newCapacity){

        E[] newData = (E[]) new Object[newCapacity];

        for (int i = 0; i < size; i++) {

            newData[i] = data[i];

        }

        data = newData;

    }

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

均摊复杂度和防止复杂度的震荡

      resize(n)   O(n)

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

均摊复杂度和防止复杂度的震荡

      17基本操作 = 9次addLast操作 + 8次元素转移操作

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

      Average = 17 / 9 ≈ 2

 

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

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

      Average = 2n+1 / n+1 ≈ 2

      结论:因此addLast均摊时间复杂度为O(1),均摊时间复杂度会比最坏情况有意义。
      同理,removeLast操作均摊时间复杂度也是O(1)

 

(2)addLast(e)和remove(e)复杂度震荡分析

addLast(e)程序:

    // 在数组末尾添加元素(复用add方法)

    public void addLast(E e) {

        add(size, e);

}

 

    // 数组指定位置添加元素

    public void add(int index, E e) {

        if (index < 0 || index > size)

            throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");

        if (size == data.length)

            resize(2 * data.length);

        for (int i = size - 1; i >= index; i--)

            data[i + 1] = data[i];

        data[index] = e;

        size++;

}

 

       // 删除数组最后一个元素

    public E removeLast() {

        return remove(size - 1);

}

 

remove(e):

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

    public E remove(int index) {

        if (index < 0 || index >= size) {

            throw new IllegalArgumentException("Remove failed.Index is illegal");

        }

        E ret = data[index];

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

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

        }

        size--;

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

        data[size] = null;

        if(size == data.length / 2) {

            resize(data.length / 2);

        }

        return ret;

}

 

       当我们同时看到addLast(e)和removeLast(e)操作:那么add和remove每次操作的时间复杂度都是O(n)。
      
addLast(e)和remove(e)复杂度震荡演示:

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

均摊复杂度和防止复杂度的震荡

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

均摊复杂度和防止复杂度的震荡

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

均摊复杂度和防止复杂度的震荡

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

均摊复杂度和防止复杂度的震荡

       出现addLast(e)和remove(e)复杂度震荡原因:removeLast时resize过于着急(Eager)

       解决方案:Lazy(remove延迟执行resize)

       容量2n,size=n+1:

      均摊复杂度和防止复杂度的震荡

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

      均摊复杂度和防止复杂度的震荡

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

       均摊复杂度和防止复杂度的震荡

程序优化方案:

均摊复杂度和防止复杂度的震荡

 

如果感兴趣的童鞋,可以观看我下一篇博客:栈和栈的应用:撤销操作和系统栈​​​​​​​

 

 

相关文章:

  • 2022-12-23
  • 2021-11-29
  • 2021-06-20
  • 2021-11-28
猜你喜欢
  • 2021-05-22
  • 2021-11-03
  • 2021-05-28
  • 2021-07-09
  • 2022-03-01
  • 2021-08-11
相关资源
相似解决方案