【问题标题】:Remove an array element and shift the remaining ones移除一个数组元素并移动剩余的元素
【发布时间】:2020-04-24 11:41:18
【问题描述】:

如何删除数组的元素并将剩余元素向下移动。所以,如果我有一个数组,

array[]={1,2,3,4,5} 

并且想删除 3 并转移其余的,所以我有,

array[]={1,2,4,5}

我将如何用最少的代码来解决这个问题?

【问题讨论】:

    标签: c++ arrays


    【解决方案1】:

    您只需用数组中的下一个值覆盖您要删除的内容,传播该更改,然后记住新的结束在哪里:

    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&lt;int&gt; 的使用在这里可能更合适,因为它是一个“真正的”动态分配的大小调整数组。 (从某种意义上说,要求其 size() 反映了已删除的元素。)

    【讨论】:

    • 没有提到copy(iter, iter, iter) 或move(iter, iter, iter)?
    • @MooingDuck:早在 09 年,move(iter, iter,iter) 并不存在。 :P Steve Jessop 在下面提到它,将它放在我的答案中会(一直)偷窃,imo。
    • @GManNickG:偷偷摸摸——尤其是对于老问题,我认为理想的答案是接受好的答案。有时写一个包含其他所有答案的所有最佳部分的答案有点厚颜无耻,但我很确定它仍然是被批准的做法,ISTR a FAQ 某处实际上推荐它。任何我不想让你使用的东西,我不会发布到 SO :-)
    【解决方案2】:

    您可以使用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);
    

    【讨论】:

    • 请注意 memmove() 仅适用于 POD 类型,而 OTOH 几乎任何类型都可以与向量一起使用,即使是那些具有用户定义 operator=() 的类型。
    【解决方案3】:

    就移动元素而言,std::copy 完成了这项工作:

     #include <algorithm>
    
     std::copy(array+3, array+5, array+2);
    

    请注意,复制的前提条件是目标不得在源范围内。范围重叠是允许的。

    此外,由于数组在 C++ 中的工作方式,这不会“缩短”数组。它只是在其中移动元素。无法更改数组的大小,但如果您使用单独的整数来跟踪其“大小”,即您关心的部分的大小,那么您当然可以减少它。

    因此,您最终得到的数组将就好像它被初始化为:

    int array[] = {1,2,4,5,5};
    

    【讨论】:

      【解决方案4】:

      你不能用数组来实现你想要的。请改用向量,并阅读有关 std::remove 算法的信息。比如:

      std::remove(array, array+5, 3)
      

      将在您的阵列上工作,但不会缩短它(为什么 - 因为这是不可能的)。使用向量,它会是这样的

      v.erase(std::remove(v.begin(), v.end(), 3), v.end())
      

      【讨论】:

      • 我想这是不可能的,因为内存已经被分配了,所以初始内存块仍然会包含一个 5 项数组的信息。
      【解决方案5】:

      根据您的要求,您可能希望对这些类型的操作使用 stl 列表。您可以遍历您的列表,直到找到该元素,然后删除该元素。如果您不能使用列表,那么您必须自己移动所有内容,或者通过某种 stl 算法或手动。

      【讨论】:

      • 我支持使用 std::list 的建议。如果您需要从向量中间删除一个元素,则需要移动它后面的所有元素,这非常昂贵(平均为 O(n))。但是,在遍历列表时从列表中间删除一个元素是一个简单的 O(1) 操作。
      【解决方案6】:

      如果您最关心代码大小和/或性能(也用于 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;
      

      【讨论】:

        【解决方案7】:

        请注意:如果放宽了保留元素顺序的要求,则将要删除的元素替换为最后一个元素会更有效。

        【讨论】:

          【解决方案8】:

          Programming Hub 随机提供了一个代码 sn-p,实际上 确实 减少了数组的长度

          for (i = position_to_remove; i < length_of_array; ++i) {
                  inputarray[i] = inputarray[i + 1];
          }
          

          不确定是不是后来才添加的行为。不过,它确实有用。

          【讨论】:

            【解决方案9】:

            确实减少了长度。但是,如果我们谈论 int 数组,则 length 和 size 之间是有区别的。 大小告诉我们给定数组的容量,我们可以在其中存储多少。 数组的长度告诉我们实际有多少项。

            【讨论】:

              【解决方案10】:

              这个问题有点老了。 尝试使用标准库提供的容器。这些是由专家设计的,并且经过了很好的测试。此外,标准库算法的未来发展旨在适应这些标准库容器。

              如果由于某种原因您必须坚持使用数组,请尝试使用 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));
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-01-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-12-14
                相关资源
                最近更新 更多