【问题标题】:Computional complexity of sorted array排序数组的计算复杂度
【发布时间】:2017-08-01 18:10:00
【问题描述】:

目前,我正在为我的大学做一个项目,在那里我确实实现了已知的数据结构(数组、链表、BST 等),并且我必须测量对它们进行一些操作所需的时间。例如,对我来说第一个是数组。我已经测量了在数组中间添加一个元素的时间(移动更多的 c 值,所以n = n + 1。它当然给了我O(n),其中 n 是元素的数量。现在我必须检查用于将元素添加到数组的开头并将元素附加到它(添加到末尾)。我有 2 个简单的算法(我不能使用 STLboost::):

添加到开头:

void array::beginning_append(int value)
{   
    int *temp = new int[n + 1];
    memcpy(temp + 1, table, sizeof(int) * n);
    n = n + 1;
    temp[0] = value;
    delete[] table;
    table = new int[n];
    memcpy(table, temp, sizeof(int) * n);
    delete[] temp;
}

追加到末尾:

void array::append(int value)
{
    int *temp = new int[n + 1];
    memcpy(temp, table, sizeof(int) * n);
    temp[n] = value;
    n = n + 1;
    delete[] table;
    table = new int[n];
    memcpy(table, temp, sizeof(int) * n);
    delete[] temp;
}

这些是方法或array 类,其中tablen 是该类的成员。现在那些差别不大,我认为他们的时间会一样,而且他们是(我检查了QueryPerformanceCounter 的大量元素,比如500000,它给了我O(n) 的复杂性),但我的讲师说添加到开头会有O(n)的计算复杂度,但是从末尾添加或删除一个元素会有O(1)的复杂度,所以无论元素的数量如何,它都是const。所以我想问你们我的算法是否不好,我的意思是他们做了不必要的事情,这就是他们依赖元素数量的原因,或者我的讲师错了

【问题讨论】:

  • 前置而不是乞求追加? :)
  • 我应该这样做 :D 当我编码时,我说或写正确英语的能力会下降,所以我写 beggining 而不是 beginning
  • 时间没有区别,因为在这两种情况下,您都在重新分配和复制整个数组。如果您想了解为什么附加到末尾是恒定的,请阅读amortized constant time
  • 欢迎编程。

标签: c++ arrays algorithm data-structures time-complexity


【解决方案1】:

这两种复杂性是:

O(n)

因为你正在复制整个数组。

详细了解 memcpy() here 的复杂性。


提示:您可以轻松跳过第二个副本,方法是释放 table 指向的内存,然后将其指向 temp。这样你只会复制一次,而不是两次。但是,整体时间复杂度不会改变。

例子:

void array::prepend(int value)
{   
    int *temp = new int[n + 1];
    memcpy(temp + 1, table, sizeof(int) * n);
    n = n + 1;
    temp[0] = value;
    delete[] table;
    table = temp;
}

专业提示:How do you detect/avoid Memory leaks in your (Unmanaged) code?

预感:realloc() 的巧妙实现应该比对新数组的粗暴memcpy() 执行得更快。原因是如果realloc() 能够扩大/缩小您的阵列,而不必将整个东西复制到一个新位置(当没有足够的连续空间时可能会发生这种情况),那么它会更快。 realloc() 并不总是意味着 O(1)。

【讨论】:

  • 有这一行:n = n+1
  • 重点是:为什么要复制数组两次?只需使表点温度
  • 是的,我知道,没错。我很长一段时间没有使用cpp,我很好奇如果我让表指向temp,那么我必须删除[] temp,但现在我想我没有:D我是对的吗?
  • @Frynio 已动态分配的内存必须由您解除分配,请参阅我的更新答案。
  • 我知道,我做了delete[] table 然后table = temp,我想没关系,对吧?
【解决方案2】:

当缓冲区大到足以容纳新元素时,可以在O(1) 中实现添加到末尾。通常,当重新分配完成时,内存大小会增加超过当前所需的大小,因此不必经常进行重新分配。

在这种情况下,当发生重新分配时,平均复杂度为 O(1),最差时间复杂度为 O(n)

【讨论】:

  • 我必须动态分配表格,并且大小必须与元素数量一样大
  • stl vector 例如有一个sizecapacity 成员,size 当然总是准确的。
  • 如果可以使用C风格的内存管理,使用realloc()可以加快分配速度,让append为O(1)。
  • @paddy (s)他不能使用 STL。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多