首页 > 解决方案 > 使用指针删除 C 中的重复项时出错

问题描述

我的代码有错误,我试图获取重复项并删除它们。

但是,当我尝试此操作时,它不会删除任何内容,并且仍然在输出中为我提供与原始值相同的值。

下面我展示了这两种方法。

void print_array 只是打印出数组。

void removeDups 我想要的是获取重复项并将它们删除并打印新数组。

让我知道错误发生在哪里。

还建议使用指针表示法。谢谢!

void removeDups(int *array, int *length)
{
        *length = 10;
        int i, j;
        for(i = 0; i < *length; i++)
        {
           for(j = 0; j < *length; j++)
           {
             if(array[i] == array[j])
             {
                array[j] = array[*length-2];
                length++;
              }
            }
        }
        printf("Number of new elements: %d,", *length);
        printf(" new elements: ");
        for(i = 0; i < *length; i++)
        {
                printf("%d " , array[i]);
        }
}

void print_array(int *array, int length)
{
    printf("Number of elements: %d,", length);
    int i;
    printf(" Orginal elements: ");
    for(i = 0; i < length; i++)
    {
            printf("%d " , array[i]);
    }
}
int main()
{
    int array [10];
    int i, number;
    int size = 10;
    int *length;
    length = &size;
    for(i = 0; i < size; i++)
    {
            number = rand() % 10 + 1;
            array[i] = number;
    }
    print_array(array, size);
    printf("\n");
    removeDups(array, length);
    return 0;
}

输出:

元素数量:10,原始元素:4 7 8 6 4 6 7 3 10 2

新元素数量:3,新元素:10 6 8

标签: carraysfunctionpointers

解决方案


请修复代码中的所有警告 - 例如,您可以在 GCC 中启用WallWextra标志。

然后我看到的一个逻辑错误在这里:

array[j] == array[i]

您要分配而不是比较的位置,因此将其更改为:

array[j] = array[i]

此外,当您打印删除了重复值的数组时,您将迭代直到end,但此变量未声明。


我认为您需要退后一步,使用额外的数组进行操作,这将是删除重复元素的旧数组。在这种情况下,您可以将代码修改为以下内容:

#include <stdio.h>
#include <stdlib.h>

void removeDups(int *array, int length)
{
  int array_no_dups[length];
  int unique_n = 0;
  for(int i = 0; i < length; ++i)
  {
    int found = 0; // flag
    //check if element already in the array without duplicates
    for(int j = 0; j < unique_n; j++)
    {
      if(array[i] == array_no_dups[j])
        found = 1;
    }
    // If not found
    if(!found)
      // then append it to the array without duplicates
      array_no_dups[unique_n++] = array[i];
  }
  printf("Number of new elements: %d,", unique_n);
  printf(" new elements: ");
  for(int i = 0; i < unique_n; i++)
  {
    printf("%d ", array_no_dups[i]);
  }
}
void print_array(int *array, int length)
{
    printf("Number of elements: %d,", length);
    printf(" Orginal elements: ");
    for(int i = 0; i < length; i++)
    {
            printf("%d " , array[i]);
    }
}
int main()
{
    int array[10];
    int size = 10;
    for(int i = 0; i < size; i++)
      array[i] = rand() % 10 + 1;
    print_array(array, size);
    printf("\n");
    removeDups(array, size);
    return 0;
}

输出:

Number of elements: 10, Orginal elements: 4 7 8 6 4 6 7 3 10 2 
Number of new elements: 7, new elements: 4 7 8 6 3 10 2 

现在,如果您真的想就地删除重复项,那么每次找到重复值时,您都需要将它的第二次出现与数组的最后一个元素交换(这将由您的计数器索引会保持)。当然,你现在需要小心你的索引。

例如,您可以像这样就地removeDups(array, &size);执行它(调用这样的方法:) :

void removeDups(int *array, int *length)
{
  int original_len = *length;
  for(int i = 0; i < original_len - 1; ++i)
  {
    for(int j = i + 1; j < *length; ++j)
    {
      if(array[i] == array[j])
      {
        array[j] = array[*length - 1];
        (*length)--;
        j--;  // since the new `array[j]` element might be also a duplicate of `array[i]`
      }
    }
  }
  printf("Number of new elements: %d,", *length);
  printf(" new elements: ");
  for(int i = 0; i < *length; i++)
  {
    printf("%d ", array[i]);
  }
}

现在输出将是:

新元素数量:7,新元素:4 7 8 6 2 3 10

其中不保留元素的原始顺序。

如果您想就地执行并保留原始顺序,那么您应该将所有子数组从第 (j+1) 个元素向左移动一个位置,而不是每次找到重复项时都进行交换。

就时间复杂度而言,这是一个更昂贵的操作,但这是一种权衡,你速度较慢,但​​你保持秩序。你应该做你的应用程序要求你做的事情,即如果顺序很重要,请使用移位方法,如果顺序无关紧要,请使用交换方法。


推荐阅读