Algs4-1.4.32均摊分析

论坛 期权论坛 脚本     
已经匿名di用户   2022-7-2 21:58   1813   0
1.4.32均摊分析。请证明,对一个基于大小可变的数组实现的空栈的M次操作访问数组的次数和M成正比。
答: 设N为2的幂

1)连续N次的push操作均摊后每次push操作访问数组的次数

设数组长度为L,一次延长需要的数组访问次数为:初始化2L长度的数组需要将数组元素置初值,需要2L次写操作。将原数组中L个元素读出,然后写入到新数组各需L次读、L次写操作。那么数组一次延长需要4L次数组元素的访问,也就是上一次数组长度的4倍。

数组开始长度为1,之后每次延长都是上一次长度的2倍,数组长度最后一次延长是从N/2至N。连续N次push延长数组需要访问数组元素次数为:

图片

N次push操作需要对数组元素进行N次写访问,那么最终的数组访问次数=4N-4+N=5N-4,连续N次push操作均摊后每次push操作对数组访问次数=(5N-4)/N。

2)最坏的连续push操作均摊后每次push操作访问数组的次数

设栈长度达到N/2+1时数组长度从N/2延长至N。连续的push操作使数组从长度N延长至2N是最坏的连续push情况。栈长度在N/2+2至N区间进行的N/2-1次push操作不会促使数组延长,此区间每次push对应一次数组元素的写访问。栈长度从N变为N+1时需要一次push操作和一次数组延长,一次push操作对应一次数组写操作,一次数组延长对应4N次数组访问。那么栈长度从N/2+1变为N+1需要进行的数组访问次数为N/2+4N,push操作次数为N/2,均摊后每次push操作对应的数组访问次数为(N/2+4N)/(N/2)=9

3)连续的N次pop操作均摊后每次pop操作访问数组的次数,不考虑pop之前的push

设数组长度为L,一次收缩需要的数组访问次数为:初始化L/2长度的数组需要将数组元素置初值,需要L/2次写操作。将原数组中L/4个元素读出,然后写入到新的数组各需L/4次读、L/4次写,总的次数为L。那么数组一次收缩需要L次数组访问,也就是收缩后长度的2倍。

数组开始长度为N,之后每次收缩后新的长度都是原有长度的1/2,每一次收缩需要访问的数组次数为收缩后长度的2,因为在栈长度/数组长度=1/4时才收缩,所以最后一次收缩是在数组长度为4时。连续Npop收缩数组需要访问数组元素次数为:
图片

N次pop操作需要对数组元素进行N次读访问,那么最终的数组访问次数=2N-4+N=3N-4,连续N次pop操作均摊后每次pop操作对数组访问次数=(3N-4)/N

4)最坏的连续pop操作均摊后每次pop操作访问数组的次数,不考虑pop之前的push

设数组完成最近一次的收缩后数组长度为4N,栈长度为2N,数组长度收缩至2N需要访问的次数为:连续进行N次pop,每次pop需要一次数组元素读访问,经过N次pop后栈长度个数减至N,触发数组收缩至2N的操作,数组收缩至2N时需要初始化新的数组,为数组元素置空操作需要2N次写访问,将原数组中的N个元素读出需要N次读访问,再将N个元素写入新数组需要N次写访问,那么总的访问次数为: N+2N+N+N=5N,pop操作次数为N,均摊成本=数组访问次数/操作次数=5N/N=5

5)连续N次push操作后连续N次pop操作均摊访问数组的次数

依据上述1)得出连续N次push需要5N-4次访问,依据上述3)连续N次pop需要3N-4次访问,共需要((5N-4)+(3N-4))=8N-8,操作次数N+N=2N,均摊成本=(8N-8)/2N

6)最坏情况下连续的push与pop均摊访问数组的成本

设数组完成最近一次延长后数组的长度是2N,栈长度是N+1。连续进行N次push后数组延长至4N,栈长度为2N+1,push操作对数组访问的次数为4N次的数组初始化,2N次对旧数组元素读,2N次对新数组写,N次push对应N次写,一共9N次访问。数组长度从4N,栈长度从2N+1使数组收缩一次需要N+1次pop,需要对数组访问的次数为2N次数组初始化,N次对旧数组元素读,N次对新数组写,N+1次pop对应N+1次读,一共4N+1次访问。N次push与N+1次pop的对数组均摊访问次数=(9N+4N+1)/(2N+1)=(13N+1)/(2N+1)

根据以上6种情况的分析,混合操作均摊后对数组访问的次数都是常数,那么M次混合操作在任何情况下对数组的访问次数成正比。

附1:基于可变数组的栈代码
import java.util.Iterator;
public class ResizingArrayStack<Item> implements Iterable<Item>
{
private Item[] a=(Item[]) new Object[1];
private int N=0;
public boolean isEmpty(){return N==0;}
public int size(){return N;}
private void resize(int max)
{
Item[] temp=(Item[]) new Object[max];
for(int i=0;i<N;i++)
temp[i]=a[i];
a=temp;
}//end resize
public void push(Item item)
{
if(N==a.length) resize(2*a.length);
a[N++]=item;
}//end push
public Item pop()
{
Item item=a[--N];
a[N]=null;
if(N>0 && N==a.length/4) resize(a.length/2);
return item;
}//end pop
public Iterator<Item> iterator()
{return new ReverseArrayIterator();}

private class ReverseArrayIterator implements Iterator<Item>
{
private int i=N;
public boolean hasNext(){return i>0;}
public Item next(){return a[--i];}
public void remove(){}
}
}
附2:求和公式
图片

转载于:https://www.cnblogs.com/longjin2018/p/9854502.html

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP