【发布时间】:2020-12-13 10:39:30
【问题描述】:
当我们考虑 Java 或 python (list) 中的动态数组时,附加元素的平均时间复杂度为 O(1),最差时间复杂度为 O(n)强>。假设我们试图追加“m”个元素,那么每次我们达到最大数组大小时,我们将大小加倍,然后复制所有需要 2m+m = 3m 的元素,因此,O(m) 来追加 m 个元素(摊销)。
问题:考虑 C 语言,其中,为了有一个动态数组,我们有一个指向大小为 m 的数组开头的指针。现在,如果指针达到最大大小,那么我们使用 realloc() 来增加大小,然后使用 realloc() 将指针指向新创建的数组的第一个位置。因此,我们不会再次复制所有元素,而是只是移动指针以指向新创建的大小增加的数组。那么这将如何影响时间复杂度呢?
C 示例代码取自:here
enter code here
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr, i , n1, n2;
printf("Enter size: ");
scanf("%d", &n1);
ptr = (int*) malloc(n1 * sizeof(int));
printf("Addresses of previously allocated memory: ");
for(i = 0; i < n1; ++i)
printf("%u\n",ptr + i);
printf("\nEnter the new size: ");
scanf("%d", &n2);
// rellocating the memory
ptr = realloc(ptr, n2 * sizeof(int));
printf("Addresses of newly allocated memory: ");
for(i = 0; i < n2; ++i)
printf("%u\n", ptr + i);
free(ptr);
return 0;
}
Enter size: 2
Addresses of previously allocated memory:26855472
26855476
Enter the new size: 4
Addresses of newly allocated memory:26855472
26855476
26855480
26855484
【问题讨论】:
-
您如何看待
realloc提供了一个与旧数组内容相同的“新创建的数组”? -
realloc的重点在于它隐式分配了一个请求大小的新缓冲区,复制旧大小和新大小之间最小的那个,释放原始缓冲区,然后返回指向新的缓冲区。一个简单的realloc实现的结果实际上是malloc()+memcpy()+free()。实际实现可以检查是否可以简单地扩展现有分配,但没有理由假设不会发生副本。 -
@Gerhardh 如果是这样的话,这是有道理的。让我阅读更多关于 realloc() 的内容。谢谢!
-
@HoneyKhandelwal,虽然
realloc()可能在某些时候能够就地重新分配,但您不能依赖它来做到这一点,也不能轻易预测它何时会做。那么,对于渐近复杂性分析,您必须假设它分配一个单独的块并执行适当的复制,就像您为 Java 和 Python 描述的那样。 -
@Gerhardh:关于“首先,
realloc将检查当前块之后是否有更多可用内存”:这不是realloc规范的一部分,不应依赖在没有实现的规范文档的情况下。有多种内存分配方案。如果在一个上下文中的研究显示许多分配,例如 16 字节或更少,malloc和realloc可能会使用位图来管理固定 16 字节大小的块的大型池和其他大小的其他方案…
标签: arrays c data-structures dynamic