【问题标题】:Efficiently Resizing a Dynamic Array有效地调整动态数组的大小
【发布时间】:2014-05-10 22:31:30
【问题描述】:

我有一个动态数组作为我班级的成员。我正在尝试找到一种有效的方法来调整它的大小并保留其中的所有信息。我知道向量可以很好地解决这个问题,但我想用动态数组来代替。

我的班级有一个名为 data 的 unsigned _int8 类型的动态数组。

以下是否可以接受?

unsigned _int8 * temp = data;
data = new unsigned _int8[NewSize]();

if(OldSize >= NewSize)
{
    for(int i = 0; i < NewSize; i++)
        data[i] = temp[i];
}
else
{
    for(int i = 0; i < OldSize; i++)
        data[i] = temp[i];
}

delete [] temp;

或者我应该以不同的方式来做这件事吗?有什么建议吗?

编辑

修复了我的示例中的一个错误并将 char 更改为 unsigned _int8。

编辑 2

如果有的话,我不会经常重新分配。我希望该功能能够避免必须编写代码来创建新对象并在需要时复制所有内容。

我正在编写的类是用于创建和保存位图 (.bmp) 图像。该数组仅保存文件字节。创建对象时(应该)知道图像大小。

【问题讨论】:

  • 您似乎正在尝试重新实现std::vector。只需使用std::vector。
  • 附带说明...std::copy
  • 您在第二个循环中缺少; ++i ;)
  • 如果您真的不想使用 std::vector 或等价物,那么也许您可以退回到 C,尤其是考虑到这是一个简单的 char 数组。对原始 char 数组使用 malloc(),然后在需要调整其大小时使用 realloc()。

标签: c++ dynamic-arrays


【解决方案1】:

由于数组使用POD (plain old data) 类型,您可以将循环替换为memcpy():

unsigned _int8 *temp = new unsigned _int8[NewSize];

if (OldSize >= NewSize)
    memcpy(temp, data, NewSize * sizeof(unsigned _int8));
else
{
    memcpy(temp, data, OldSize);
    memset(&temp[OldSize], 0, (NewSize-OldSize) * sizeof(unsigned _int8));
}

delete[] data;
data = temp;

或者至少使用std::copy()(对于 POD 类型,std::copy() 类似于 memcpy(),但对于非 POD 类型,它使用循环,因此保留了对象分配语义):

unsigned _int8 *temp = new unsigned _int8[NewSize];

if (OldSize >= NewSize)
    std::copy(data, &data[NewSize], temp);
else
{
    std::copy(data, &data[OldSize], temp);
    std::memset(&temp[OldSize], 0, (NewSize-OldSize) * sizeof(unsigned _int8));
}

delete[] data;
data = temp;

话虽如此,您确实应该改用std::vector&lt;unsigned _int8&gt;。它为您处理这些细节。这种类型的数组管理是你必须在 C 中使用的,但如果可以避免的话,真的不应该在 C++ 中使用,而是使用原生 C++ 功能。

【讨论】:

  • 数组实际上是无符号的_int8。这有什么改变吗?
  • 不,它没有。我所说的一切也适用于该类型,只需根据需要将char 替换为uint8。
  • 我不知道除此之外向量是否还有我需要的任何功能。我想避免添加任何我不需要的东西。此外,这对我来说是一次学习经历。我对库的依赖越多,我对 C++ 的了解就越少。感谢您的帮助。
  • 这个练习是教你 C,而不是 C++。如果你真的想学习 C++,那就学习 C++,包括 C++ 提供的 C 没有的东西(比如 STL 库,它是 C++ 的原生部分)。
  • 您个人是否总是使用向量来代替动态数组?只是好奇。我从来没有在专业环境中使用过 C++,所以我不知道什么是标准的。
【解决方案2】:

通过这种方式,每次将新元素添加到数组中时,都必须调整其大小。 而resize操作是Θ(n),所以插入操作也变成Θ(n)。

常见的过程是每次必须调整数组大小时都复制(或三次等)数组大小,这样,调整大小操作仍然是 Θ(n),但摊销的插入成本是 Θ(1)。

另外,通常容量和大小是分开的,因为容量是一个实现细节,而大小是数组接口的一部分。

并且你可能想验证,当元素被移除时,容量是否太大,如果是,则减少它,否则一旦它变大,这个空间永远不会被释放。

您可以在此处查看更多信息: http://en.wikipedia.org/wiki/Dynamic_array

【讨论】:

  • 对不起,我应该在我的问题中提供更多信息。你所说的一切都是真实和好的建议,但对于我的特殊问题,我认为 Remy Lebeau 有一个更好的答案。
【解决方案3】:

这种方法的问题在于您将大小调整为所需的大小。这意味着当您插入一个新元素时,执行它所需的时间变化很大。

因此,例如,如果您继续执行类似“push_back”的操作,那么您将一直重新分配。

另一种想法是分配额外的大小以避免频繁的重新分配,这会导致性能损失

例如,向量分配额外的大小以具有摊销的重新维度常数。

这是一个详细解释它的链接

stl中的vector使用这种方法效率更高。

Amortized analysis of std::vector insertion

【讨论】:

  • 对不起,我应该在我的问题中提供更多信息。你所说的一切都是真实和好的建议,但对于我的特殊问题,我认为 Remy Lebeau 有一个更好的答案。此外,向量很棒,我之前实际上已经使用过好几次了。我不认为他们有任何我需要的功能,但我想避免在我的项目中添加任何我不需要的东西。
  • 好的,所以你也应该投票给他的答案,给他加分。只需单击您在他的答案附近看到的 0 旁边的向上箭头
猜你喜欢
  • 2021-04-03
  • 2012-10-02
  • 1970-01-01
  • 2017-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-06
相关资源
最近更新 更多