请教一下这段代码的时间复杂度

2020-12-02 11:01:51 +08:00
 Helsing
// 全局变量,大小为 10 的数组 array,长度 len,下标 i 。
int array[] = new int[10]; 
int len = 10;
int i = 0;

// 往数组中添加一个元素
void add(int element) {
   if (i >= len) { // 数组空间不够了
     // 重新申请一个 2 倍大小的数组空间
     int new_array[] = new int[len * 2];
     // 把原来 array 数组中的数据依次 copy 到 new_array
     for (int j = 0; j < len; ++j) {
       new_array[j] = array[j];
     }
     // new_array 复制给 array,array 现在大小就是 2 倍 len 了
     array = new_array;
     len = 2 * len;
   }
   // 将 element 放到下标为 i 的位置,下标 i 加一
   array[i] = element;
   ++i;
}

这是我在一个课程里看到的例子,假如说调用 n 次 add 方法,最好时间复杂度最坏时间复杂度平均时间复杂度分别是多少?


下面这个是课程评论中的一个答案,讲师也说是对的:

  1. 最好情况时间复杂度为 O(1)

  2. 最坏情况分析:

    最坏情况代码执行的次数跟每次数组的长度有关

    第 1 次调用 add 的执行的次数为 n ,

    第 2 次调用 add 的执行的次数为 2n ,

    第 3 次调用 add 的执行的次数为 2^2 * n

    第 k 次调用 add 的执行的次数为 2^(k-1) * n

    最坏时间复杂度为 O(n)

  3. 平均情况分析 当每次遇到最坏情况时数组会进行 2 倍扩容,原数组被导入新数组,虽然数组的长度变大了,但是插入操作落在的区间的长度是一样的,分别是 0~len-1, len~(2len-1), ....;

    插入的情况仍是 len+1 种:0~len-1 和插满之后的 O(len)

    所以每次插入的概率是:p= 1/len+1

    最后求出加权平均时间复杂度为 1*p + 2*p+ ▪▪▪ + len * p + len * p = O(1) ;

  4. 均摊时间复杂度 O(1)

  5. 而均摊复杂度由于每次 O(len) 的出现都跟着 lenO(1),是前后连贯的,因而将 O(len) 平摊到前 len 次上,得出平摊复杂度是 O(1)


但是按我的理解:

我看课程评论里面都把数组的长度假设为 n,但是数组的初始长度明明是 10,这样假设的话跟上面的代码根本就不是一个意思了。我觉得 n 应该是调用 add 的次数才对。

大家怎么看?

1274 次点击
所在节点    算法
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/731268

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX