复制操作的大O表示法

时间:2011-10-18 16:19:54

标签: c# optimization big-o time-complexity

我遇到了一些肯定可以改进的代码,但我想知道我改进的Big-O符号。

他们的原始代码为数组添加了一个元素,每次执行此操作时,它会创建一个新的n + 1数组,并像这样复制旧数组:

public MyType GetNewType()
{
    MyType[] tempTypes = new MyType[_types.Count + 1];
    _types.CopyTo(tempTypes, 0);
    _types = tempTypes;

   _types[types.Count - 1] = new MyType();
   return _types[types.Count - 1];
}

据我所知,这将是一个O(n)操作。因此,我将其改写如下:

private int _currentIndex; //initialized in the constructor

public MyType GetNewType()
{
    if (_types.Length == _currentIndex)
    {
        MyType[] tempTypes = new MyType[_types.Length + 10];
        _types.CopyTo(tempTypes, 0);
        _types = tempTypes;
    }

   _types[_currentIndex] = new MyType();
   _currentIndex++;

   return _types[_currentIndex - 1];
}

这些更改的结果是否意味着该函数现在将以O(n / 10)运行,因为它每10次调用只需要一次复制操作?或者它不是那么好用吗?

3 个答案:

答案 0 :(得分:2)

这是一种常见且优秀的优化。它通常被称为“摊销的恒定时间”,这意味着大多数时候,添加单个元素是O(1),除非它不是。实现者通常会将数组的大小加倍,或者至少乘以1.5,而不是仅添加10个元素。

也就是说,C#有一些非常可爱的内置列表类,它们可以自动完成这一切,并且只要有可能,使用它们就比使用裸阵列更受欢迎。

答案 1 :(得分:2)

就Big-O表示法而言,(n/10)的复杂性将是O(n),因为它并不关心这么小的常量。

答案 2 :(得分:1)

分摊常数时间仅在每次用完免费物品时双倍数组大小时才有效! 如果不是,平均大O符号将始终为O(n)。

每次列表计数等于容量时,C#List实现将数组的大小加倍。

要使插入方法的平均值为O(1),您需要这样的内容:

MyType[] tempTypes = new MyType[Math.Max(8, _types.Length * 2)];