【问题标题】:Delete duplicates from array C++从数组 C++ 中删除重复项
【发布时间】:2019-03-15 10:03:42
【问题描述】:

我正在尝试创建一个调用 2 个函数的简单程序。第一个函数接受一个部分填充的数组,循环遍历它并删除任何重复的值。当从数组中删除一个值时,剩余的数字将向后移动以填补空白,即当函数完成时,数组的所有空值将在最后一起。

第二个函数打印更新后的数组。

我当前的代码如下。目前,当我运行我的代码时,控制台显示: 2 6 0 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460。如果它工作正常,它应该显示:1 2 5 6。

另外,我不知道如何将数组的剩余元素向后移动,以便空值在最后一起出现。

#include "pch.h"
#include <iostream>
using namespace std;
void deleteRepeats(int *arr, int arraySize, int& posUsed);
void printArray(int *arr, int arraySize);

int main()
{
int arr[10] = { 1, 2, 2, 5, 6, 1};
int posUsed = 6;
int arraySize = 10;


deleteRepeats(arr, arraySize, posUsed);
printArray(arr, arraySize);

return 0;
}

void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
{
    for (int i = 0; i < arraySize; i++)
    {
        for (int j = i; j < arraySize; j++)
        {
            if (arr[i] == arr[j])
            {
                for (int k = j; k < arraySize; k++)
                {
                    arr[k] = arr[k + 1];

                }
                posUsed--;

            }
            else
                j++;
        }
    }
}
}

void printArray(int *arr, int arraySize)
{
for (int i = 0; i < arraySize; i++)
{
    cout << arr[i] << "  ";
}
}

【问题讨论】:

  • arr 只能容纳 6 个元素,但您设置了 arraySize = 10。你可以改成int arr[10] = { 1, 2, 2, 5, 6, 1 };
  • 是否有可能使用std::vectorstd::array
  • 谢谢@JohnnyMopp 我已经更正了。尽管我在控制台显示没有输出时遇到了同样的问题。 Micha,我的讲师不希望我们使用向量,因为我们还没有介绍它们
  • 另外,arr[k] = arr[k + 1]; 将在k = arraySize - 1 时读取数组末尾。
  • for 循环中,您需要使用posUsed 而不是arraySize

标签: c++ arrays duplicates


【解决方案1】:

我会让 std 容器随心所欲。

  • 对向量进行排序
  • 使用eraseunique 删除重复项。

这里是代码

#include <vector>
#include <iostream>
#include <algorithm>

void print(const std::vector<int> &arr){
    for (const auto & i : arr){
        std::cout << i <<" ";
    }
    std::cout <<"\n";
}

int main() {
    std::vector<int> arr{1, 2, 2, 5, 6, 1};    
    print(arr);

    std::sort( arr.begin(), arr.end() );
    arr.erase( std::unique( arr.begin(), arr.end() ), arr.end() );

    print(arr);
}

附言。使用 int *arr, int arraySize 不是很像 C++。请始终尝试使用合适的容器(几乎总是std::vector)。

编辑: 我稍微改变了答案,因为我发现了这个速度比较(实际上整个问题都得到了回答)。 What's the most efficient way to erase duplicates and sort a vector?

【讨论】:

  • cmets 中的 OP 状态:我的讲师不希望我们使用向量
  • OP 不能为该分配使用标准库算法。此外,在您的解决方案中,结果数组将被排序,这可能是不需要的。此外,您不需要使用for_each 从向量构造集合。
  • @Ptaq666 好点。我替换了for_each。这增强了 const 的正确性。
  • @JohnnyMopp 在发布我的答案之前我没有阅读此评论。然而,在没有适当容器的情况下教授 C++ 并不是正确的方法。如果可以使用std::vector,那么仍然使用指针和大小是没有意义的。 C++ 应该按照 Stroustrup 的A Tour of C++ 所示进行教学。
  • OP在哪里声明不能使用算法函数?我看到他们不能使用vector,但是vector不是算法函数。
【解决方案2】:

想象算法具有单独的输入和输出数组可能更容易。然后,在伪代码中:

for i = 0 to input_array_size-1
    Is input[i] equal to input[j] for any j between 0 and i-1?
    Yes - do nothing
    No - copy input[i] to output

要使用共享输入和输出来实现这一点,您需要有两个数组大小,input_array_sizeoutput_array_size。那么,伪代码就变成了

output_array_size = 0
for i = 0 to input_array_size-1
    Is array[i] equal to array[j] for any j between 0 and output_array_size-1?
    Yes - do nothing
    No:
        copy array[i] to array[output_array_size]
        Increase output_array_size

注意:它将输出写入曾经输入的位置,因此检查重复项应该查看所有输出的元素。例如,如果您的数组是1, 2, 1, 3, 5, 6, 3,那么对于最后一个3,累积输出是1, 2, 3, 5, 6,代码应该将所有这些与当前元素进行比较。


为了简化调试,它说“什么都不做”,您可以将当前元素设置为 -1。这样,如果您在执行期间打印数组(用于调试),将更清楚哪些元素被删除。

【讨论】:

    【解决方案3】:

    鉴于您的分配约束(更像 C,而不是惯用的 C++),您可以像这样重写您的函数,以使其工作:

    void deleteRepeats(int *arr, int arraySize, int& posUsed)
    {
        for (int i = 0; i < posUsed; ++i)
        {
            int duplicates = 0;
            int j = i + 1;
            // find the first duplicate, if exists
            for ( ; j < posUsed; ++j)
            {
                if ( arr[i] == arr[j] ) {
                    ++duplicates;
                    break;
                }
            }
            // overwrite the duplicated values moving the rest of the elements...
            for (int k = j + 1; k < posUsed; ++k)
            {
                if (arr[i] != arr[k])
                {
                    arr[j] = arr[k];
                    ++j;
                }
                // ...but skip other duplicates
                else
                {
                    ++duplicates;    
                }
            }
            posUsed -= duplicates;
        }
        // clean up (could be limited to the duplicates only)
        for (int i = posUsed; i < arraySize; ++i)
            arr[i] = 0;
    }
    

    【讨论】:

      【解决方案4】:

      使用两个指针
      如果数组排序了

          int removeDuplicates(vector<int>& nums) {
              if(nums.size() == 0) return 0;
              int i = 0;
      
              for(int j = 1; j < nums.size(); j++)
                  if(nums[j] != nums[i])  nums[++i] = nums[j];
      
              // return new array length
              return i + 1;
          }
      
      //input: [1, 1, 2, 1] (arr1)
      //output: 2 (returned length)
      // print unique element
      for(int i = 0; i < output; i++) cout << arr1[i] << '\n';
      // [1, 2]
      
      time complexity: O(N/2) -> O(N)
      space complexity: O(1)
      

      【讨论】:

        【解决方案5】:

        如您所见,只有两个更改

        1:您正在遍历整个数组,因为您声明了一个 posUsed=6 变量,这是因为只有 6 个元素,所以在循环中您需要遍历数组直到 posUsed 索引,如 i&lt;posUsed j&lt;posUsed k&lt;posUsed

        2:第二个变化是在 j 循环 j=i+1 中,因为您不需要将任何索引的元素与相同索引的元素进行比较,您必须将其与该索引之后的元素进行比较。如果你将它与相同的元素进行比较,它将是相同的,并且程序将删除导致错误的相同元素。

        更重要的是,我们不会在 posUsed 索引之后遍历,因为在那之后数组已经是空/零或 null,无论你怎么称呼它

        如果您只想显示非重复元素而不是数组末尾的零,只需在 printArray 函数循环中的 cout 语句之前添加 if(arr[i]==0) return;

        void deleteRepeats(int *arr, int arraySize, int& posUsed)
        {
        {
            for (int i = 0; i < posUsed; i++)
            {
                for (int j = i+1; j < posUsed; j++)
                {
                    if (arr[i] == arr[j])
                    {
                        for (int k = j; k < posUsed; k++)
                        {
                            arr[k] = arr[k + 1];
                            
                        }
                    }
                
                }
            }
        }
        }
        

        【讨论】:

          【解决方案6】:

          以 O(n^2) 复杂度从未排序的数组中删除重复元素。

              for (i = 1; i < vec.size(); i++)
              {
                  for (j = 0; j < i; j++)
                  {
                      if (vec[i] == vec[j])
                      {
                          vec[i] = -1; //Every duplicate element will replace by -1
                      }
                  }
              }
          
             for (i = 0; i < vec.size(); i++)
              {
                  if (vec[i] != -1)
                  {
                      copy.push_back(vec[i]);
          
               /*if you are using an array then store this value into a new array.
                 first, declare a new array. The new array size will be equal to the 
                 previous array. Like this :
                 int newArr[sizeOfPreviousArrary];
                 int j = 0;
                 newArr[j] = arr[i]; 
                 j++;
               */
          
                  }
              }
          

          【讨论】:

            【解决方案7】:

            以 O(n) 复杂度从排序数组中删除重复元素。

            for (i = 0; i < n; i++)
            {
                if (arr[i] != arr[i+1]){
                        vec.push_back(arr[i]);
                    
                    /*if you are using an array then store this value into a new array.
                    first, declare a new array. The new array size will be equal to the 
                    previous array. Like this :
                        int newArr[sizeOfPreviousArrary];
                        int j = 0;
                        newArr[j] = arr[i]; 
                        j++;
                    */
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2021-02-20
              • 1970-01-01
              • 2012-03-25
              • 2010-09-05
              • 1970-01-01
              • 1970-01-01
              • 2011-06-29
              相关资源
              最近更新 更多