目前,我正在为我的大学做一个项目,在那里我实现了已知的数据结构(数组,链表,BST等),我必须测量一些操作所需的时间。例如,我的第一个是数组。我已经测量了在数组中间添加元素的时间(移动了更多的值c,所以n = n + 1
。它当然给了我O(n)
,其中n是一些元素现在我必须检查是否有一个元素添加到数组的开头并向其添加一个元素(添加到结尾)。我有2个简单的算法(我不能使用STL
或{{1 }}):
添加到开头:
boost::
追加到最后:
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
和table
是此类的成员。现在那些差别不大,我认为他们的时间会相同,而且他们(我用n
检查了大量的元素,比如QueryPerformanceCounter
,它给了我{{1}复杂性,但我的讲师说,添加到开头会有500000
计算复杂性,但是从末尾添加或删除元素将具有O(n)
的复杂性,所以它将是const,无论是元素的数量。所以我想问你们,如果我的算法不好,我的意思是他们做了不必要的事情,这就是为什么他们依赖于多少元素,或者我的讲师是错的
答案 0 :(得分:3)
两种复杂性都是:
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?
Hunch:realloc()
的聪明实现应该比粗体memcpy()
更快地执行到新数组。原因是,如果realloc()
能够增长/缩小数组而不必将整个事物复制到一个新位置(当没有足够的连续空间时可能会发生这种情况),那么它会更快。 realloc()
并不总是指O(1)。
答案 1 :(得分:1)
当缓冲区大到足以容纳新元素时,可以在O(1)
中实现添加到最后。通常,在重新分配时,内存大小会增加到目前所需的大小,而不必经常重新分配。
在这种情况下,重新分配时,平均复杂度为O(1)
,最差时间复杂度为O(n)
。