在数组中间添加新索引

时间:2016-05-29 19:03:52

标签: c++ arrays

我知道我可以删除数组中间的某些内容,例如

char* cArray = (char*) malloc(sizeof(char) * sizeTracker);

使用memmove功能。通过这种方式,可以从数组中删除某些内容而无需使用临时数组,切换到向量等。这里的问题是我可以在数组中间添加一个新索引(是否有函数)?或者让我们说使用realloc我在最后添加一个新索引,那么如何有效地降低值?

4 个答案:

答案 0 :(得分:1)

没有自定义C函数允许使用C内存函数增加数组并将对象插入中间。基本上,您使用malloc()free()memmove()构建功能(当有足够的空间可用且元素只是在内存中移回时)或memcpy()(如果你需要分配新的内存,你想避免先复制,然后移动尾巴。

在C ++中,对象位置往往很重要,你显然会使用std::copy()std::reverse_copy()和/或std::move()(两种形式),因为可能有相关对象的相关结构。很可能你也会获得不同的内存,例如,使用operator new()和/或分配器,如果你真的在原始内存方面旅行。

实际插入的有趣实现(假设有足够的空间用于另一个元素)是使用std::rotate()构造最后一个元素然后随机播放元素:

 void insert(T* array, std::size_t size, T const& value) {
     // precodition: array points to at least size+1 elements
     new(array + size) T(value);
     std::rotate(array, array + size, array + size + 1);
 }

当然,当数组需要重新定位时,这并不能避免可能不必要的混乱元素。在这种情况下,分配新内存并将初始对象移动到开头更有效,添加新插入的元素,将尾随对象移动到新对象之后的位置。

答案 1 :(得分:1)

备选答案

我一直在考虑这个以及@DietmarKühl开始谈论插入像deque这样的块的评论。这个问题是deque是一个链表的链接,所以你不能从一个数组开始。如果你从一个数组开始,然后想在中间插入一些东西,你必须做一些其他事情,我想我有一个想法 - 它没有充实,所以它可能无法工作,但无论如何我会分享它。请留下评论告诉我你对这个想法的看法。

如果你有一个项目数组,然后想要在中间添加一个项目,你真正想做的就是添加一个块并更新映射。映射是使它全部工作的东西 - 但它减慢了访问速度,因为你需要在每次访问数组之前检查映射。

映射将是二叉树。它将开始为空但节点将包含一个值:如果您想要的索引是<你遍历左指针的值,如果它是> =你遍历右指针。

所以,一个例子:

插入之前:

root -> (array[100000], offset: 0)

插入5000后:

root -> {value: 5000,
         left:  (array[100000], offset: 0),
         right: {value: 5001,
                 left:  (newarray[10], offset: -5000),
                 right: (array[100000], offset: 1),
                }
        }

我在这里使用了10个块 - newarray是10个大小。如果您只是在整个地方随机插入索引,则块大小应为1,但如果插入具有大于1的blovk大小的连续索引组将是好的。这实际上取决于你的使用模式...

当您检查索引7000时,检查根节点:7000是> = 5000,因此您按照右指针:7000是> = 5001,因此您按照右指针:它指向原始数组,偏移量为1所以你访问数组[索引+偏移]。

检查索引700时,检查根节点:700是< 5000,所以你按照左指针:它指向偏移量为0的原始数组,所以你访问数组[索引+偏移]。

检查索引5000时,检查根节点:5000是> = 5000,因此您按照右指针:5000< 5001所以你按照左指针:它指向新数组,偏移量为-5000,所以你访问newarray [index + offset]。

当然,对此进行优化对于使其有用非常重要 - 您必须在每次插入后平衡树,否则右侧比左侧长得多。

这样做的缺点是对数组的访问现在是O(日志插入)而不是O(1)所以如果有很多插入,你将需要经常重新分配以将数据结构压缩回数组但你可以在适当的时候保存它。

就像我说它不是很充实,所以它可能在实践中不起作用,但我希望它值得分享。

原始答案

如果你有一个C风格的数组,并且想要在中间插入一个索引,你需要有一个比你需要的更大的数组(加上一个像sizeTracker这样的变量来跟踪大小)。

然后,如果还有空间,你可以将数组的后半部分记下来,在中间创建一个点。

如果没有剩下任何空间,你可以将另一个包含额外空间的整个阵列进行malloc,然后记住前半部分,然后分别留下下半部分留下空隙。

如果要使malloc摊销的常量时间,每次重新分配时需要将数组的大小加倍。 memmove在x86上成为一台机器指令,但即便如此,由于移动每个值,它仍然是O(n)。

但是性能并没有比你的删除技巧更糟糕 - 如果你可以在整个数组中删除任何地方,那么成本也是O(n),因为你删除时会记住平均值的一半。

答案 2 :(得分:0)

您已将此帖标记为C ++。

  

我可以在数组中间添加一个新索引(是否有一个函数   对于它)

没有。来自cppreference.com,std :: array:

  

std :: array是一个封装固定大小数组的容器。

我认为这意味着您可以更改元素,但不能更改索引。

(叹气)但我怀疑C风格阵列仍然被允许。 而且我注意到Dietmar的回答也说不。

答案 3 :(得分:0)

如果您使用手动分配的内存,则必须reallocate,并且您应该希望此操作不会将内存块移动到新位置。那么最好是使用rotate算法。

顺便说一句,更喜欢向量等stl容器为这类任务手动分配内存。如果你使用矢量,你应该保留记忆。