在数组的中间添加新索引
Add new index in the middle of an array
我知道我可以移除数组中间的一些东西,比如
char* cArray = (char*) malloc(sizeof(char) * sizeTracker);
使用CCD_ 1函数。通过这种方式,将从数组中删除某些内容,而无需使用临时数组、切换到向量等。这里的问题是,我可以在数组的中间添加一个新索引吗(是否有函数)?或者假设使用realloc
在末尾添加一个新索引,那么如何有效地向下移动值?
备选答案
我一直在思考这个问题,以及@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,但如果你插入blovk大小大于1的连续索引组,那就好了。这真的取决于你的使用模式。。。
当您检查索引7000时,您会检查根节点:7000是>=5000,所以你跟随右指针:7000是>=5001,所以你跟随右指针:它指向偏移量为1的原始数组,所以你访问数组[index+offset]。
当您检查索引700时,您检查根节点:700是<5000,所以你跟随左指针:它指向偏移量为0的原始数组,所以你访问数组[index+offset]。
当您检查索引5000时,您会检查根节点:5000是>=5000,所以你跟随右指针:5000是<5001,所以你跟随左指针:它指向偏移量为-5000的新数组,所以你可以访问newarray[index+offset]。
当然,对这一点的优化对于使其有用非常重要——您必须在每次插入后平衡树,否则右侧将比左侧长得多。
这样做的缺点是,现在对数组的访问是O(日志插入)而不是O(1),所以如果有很多插入,您会希望每隔一段时间重新分配一次,以将数据结构压缩回数组,但您可以将其保存到合适的时间。
就像我说的,它不是很充实,所以在实践中可能不起作用,但我希望它无论如何都值得分享。
原始答案
如果你有一个C风格的数组,并且想在中间插入一个索引,你需要一个比你需要的大的数组(加上一个像sizeTracker这样的变量来跟踪大小)。
然后,如果有剩余的空间,你可以将数组的最后一半移动到一个位置,在在中间创建一个点。
如果没有任何空间,您可以malloc另一个包含额外空间的整个阵列,然后分别移动前半部分和后半部分,留下一个间隙。
如果你想让malloc摊销的时间恒定,每次重新分配它时,你需要将数组的大小增加一倍。memmove在x86上变成一条机器指令,但即使这样,由于移动了每个值,它仍然是O(n)。
但性能并不比删除技巧差——如果你可以在整个数组中的任何地方删除,那么成本也是O(n),因为你在删除时平均移动了一半的值。
没有自定义的C函数可以使用C内存函数增加数组并在中间插入对象。从本质上讲,您应该使用malloc()
、free()
、memmove()
(当有足够的空间并且元素刚刚在内存中移回时)或memcpy()
(如果您需要分配新内存,并且希望避免先复制然后移动尾部)来构建功能。
在对象位置往往很重要的C++中,您显然会使用std::copy()
、std::reverse_copy()
和/或std::move()
(两者都是),因为可能存在相关对象的结构体。很可能您也会获得不同的内存,例如,如果您真的在原始内存方面旅行,则使用memmove
0和/或分配器。
实际插入的有趣实现(假设有足够的空间容纳另一个元素)是使用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);
}
当然,这并不能避免在需要重新定位数组时可能不必要地打乱元素。在这种情况下,更有效的方法是分配新内存,将初始对象移动到起点,添加新插入的元素,将尾部对象移动到新对象旁边的位置。
如果使用手动分配的内存,则必须重新分配,并且希望此操作不会将内存块移动到新位置。那么最好是使用旋转算法。
顺便说一句,比起为这类任务手动分配内存,更喜欢向量等stl容器。如果您正在使用向量,则应该保留内存。
您已经将这篇文章标记为C++。
我可以在数组的中间添加一个新索引吗(是否有函数对它来说)
否。来自cppreference.com,std::array:
std::array是一个封装固定大小数组的容器。
我认为这意味着您可以更改元素,但不能更改索引。
(叹气)但我怀疑C风格的数组仍然是允许的。我注意到Dietmar的回答也说不。
- 如何将 std::vector 的某些元素移动到向量中的新索引?
- 为什么无法将字符串的元素按索引号附加到 C++ 中的新字符串?
- 提升多索引 将索引转换为标记并在索引上循环
- 有没有办法创建一个花哨的迭代器和相应的新数组,以便检查每个索引的索引值的条件?
- 从 1 中创建新的字符 * 作为参数,元素位于 2 个索引之间
- 在具有重复索引的索引数组处更改 ArrayFire 数组
- 尝试在字符串中索引字符并创建新字符串
- 为对象指针数组的每个空索引创建新对象
- 什么是qfuture :: recultreadyat(int索引)索引的索引
- 如何获取wxGrid中移动列的新索引
- 程序必须将奇数索引元素放在新的向量 C 中,将偶数索引元素放在另一个向量 T 中
- 在数组的中间添加新索引
- 使用带有新 API 的编号索引的转换无效
- C++文本文档中写入新行并按索引读取
- 如何将未排序数组的排序索引放入新数组中
- 即使在将新字符串复制到现有字符串之后,旧包含也可用(在某些索引中)
- boost多索引排序索引中插入的匹配函数
- c++索引到索引映射
- 为什么数组索引在索引和名称上是对称的?
- 如何创建一个新的文件夹,如果它已经存在于c++中,则增加其索引