【发布时间】:2020-04-24 11:41:18
【问题描述】:
如何删除数组的元素并将剩余元素向下移动。所以,如果我有一个数组,
array[]={1,2,3,4,5}
并且想删除 3 并转移其余的,所以我有,
array[]={1,2,4,5}
我将如何用最少的代码来解决这个问题?
【问题讨论】:
如何删除数组的元素并将剩余元素向下移动。所以,如果我有一个数组,
array[]={1,2,3,4,5}
并且想删除 3 并转移其余的,所以我有,
array[]={1,2,4,5}
我将如何用最少的代码来解决这个问题?
【问题讨论】:
您只需用数组中的下一个值覆盖您要删除的内容,传播该更改,然后记住新的结束在哪里:
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// delete 3 (index 2)
for (int i = 2; i < 8; ++i)
array[i] = array[i + 1]; // copy next element left
现在你的数组是{1, 2, 4, 5, 6, 7, 8, 9, 9}。你不能删除多余的9,因为这是一个静态大小的数组,你只需要忽略它。这可以通过std::copy 来完成:
std::copy(array + 3, // copy everything starting here
array + 9, // and ending here, not including it,
array + 2) // to this destination
在 C++11 中,使用可以使用std::move(算法重载,而不是实用程序重载)。
更一般地说,使用std::remove 删除匹配值的元素:
// remove *all* 3's, return new ending (remaining elements unspecified)
auto arrayEnd = std::remove(std::begin(array), std::end(array), 3);
更普遍的是,std::remove_if。
注意std::vector<int> 的使用在这里可能更合适,因为它是一个“真正的”动态分配的大小调整数组。 (从某种意义上说,要求其 size() 反映了已删除的元素。)
【讨论】:
copy(iter, iter, iter) 或move(iter, iter, iter)?
move(iter, iter,iter) 并不存在。 :P Steve Jessop 在下面提到它,将它放在我的答案中会(一直)偷窃,imo。
您可以使用memmove(),但您必须自己跟踪数组大小:
size_t array_size = 5;
int array[5] = {1, 2, 3, 4, 5};
// delete element at index 2
memmove(array + 2, array + 3, (array_size - 2 - 1) * sizeof(int));
array_size--;
不过,在 C++ 中,最好使用 std::vector:
std::vector<int> array;
// initialize array...
// delete element at index 2
array.erase(array.begin() + 2);
【讨论】:
就移动元素而言,std::copy 完成了这项工作:
#include <algorithm>
std::copy(array+3, array+5, array+2);
请注意,复制的前提条件是目标不得在源范围内。范围重叠是允许的。
此外,由于数组在 C++ 中的工作方式,这不会“缩短”数组。它只是在其中移动元素。无法更改数组的大小,但如果您使用单独的整数来跟踪其“大小”,即您关心的部分的大小,那么您当然可以减少它。
因此,您最终得到的数组将就好像它被初始化为:
int array[] = {1,2,4,5,5};
【讨论】:
你不能用数组来实现你想要的。请改用向量,并阅读有关 std::remove 算法的信息。比如:
std::remove(array, array+5, 3)
将在您的阵列上工作,但不会缩短它(为什么 - 因为这是不可能的)。使用向量,它会是这样的
v.erase(std::remove(v.begin(), v.end(), 3), v.end())
【讨论】:
根据您的要求,您可能希望对这些类型的操作使用 stl 列表。您可以遍历您的列表,直到找到该元素,然后删除该元素。如果您不能使用列表,那么您必须自己移动所有内容,或者通过某种 stl 算法或手动。
【讨论】:
如果您最关心代码大小和/或性能(也用于 WCET 分析,如果您需要),我认为这可能是更透明的解决方案之一(用于查找和删除元素):
unsigned int l=0, removed=0;
for( unsigned int i=0; i<count; i++ ) {
if( array[i] != to_remove )
array[l++] = array[i];
else
removed++;
}
count -= removed;
【讨论】:
请注意:如果放宽了保留元素顺序的要求,则将要删除的元素替换为最后一个元素会更有效。
【讨论】:
Programming Hub 随机提供了一个代码 sn-p,实际上 确实 减少了数组的长度
for (i = position_to_remove; i < length_of_array; ++i) {
inputarray[i] = inputarray[i + 1];
}
不确定是不是后来才添加的行为。不过,它确实有用。
【讨论】:
确实减少了长度。但是,如果我们谈论 int 数组,则 length 和 size 之间是有区别的。 大小告诉我们给定数组的容量,我们可以在其中存储多少。 数组的长度告诉我们实际有多少项。
【讨论】:
这个问题有点老了。 尝试使用标准库提供的容器。这些是由专家设计的,并且经过了很好的测试。此外,标准库算法的未来发展旨在适应这些标准库容器。
如果由于某种原因您必须坚持使用数组,请尝试使用 std::array
std::array<int, 5> array = { 1,2,3,4,5 };
//std::remove - The elements that are not deleted are moved to the front of the array,
//and returns the iterator of the element from where it can be completely erased.
auto itr = std::remove(array.begin(), array.end(), 3);
//New array with new size
std::array<int,4> newArray;
std::copy(array.begin(), itr, newArray.begin());
不用也可以使用std::array 来完成同样的事情。但正如前面所说,许多其他好处更喜欢使用std::array
int array[] = { 1,2,3,4,5 };
auto itr = std::remove(std::begin(array), std::end(array), 3);
int newArray[4];
std::copy(std::begin(array), itr, std::begin(newArray));
【讨论】: