首页 > 解决方案 > 我们如何在 C 中删除数组中的重复元素?

问题描述

我正在尝试删除数组中的重复元素。我可以过滤掉元素,但最后那个元素的位置只会被替换0,不会消失

这是代码:

#include <stdio.h>

int main()
{
    int arr[6] = {1,2,3,3,8,5};
    int newArr[6] = {};
    int temp,i,j;

    for(i = 0; i < 6; i++){
        for(j = i+1; j <= 6; j++){
            if(arr[i] != arr[j]){
                newArr[i] = arr[i]; 
                break;
            }else{
                continue;
            }
        }
        temp = j;
        i = temp-1;
    }

    for(int k = 0; k < 6; k++){
        printf("%d,", newArr[k]);
    }

    return 0;
}

结果是:1,2,3,0,8,5

预期结果:1,2,3,8,5

标签: carraysmemory-management

解决方案


由于数组的大小是固定的,因此您只需更改数组的两个方面,(1)数组的内容;(2) 你对它包含的元素数量的计数。在您删除重复值的情况下,您可以用数组的剩余内容覆盖重复地址,从而有效地将每个元素向下移动一个(这会更改内容)。要完成该过程,您必须从数组中的元素计数中减去 1,以表明它包含的存储元素比它少一个。

您可以循环向下移动所有元素,或string.h提供memmove()可以处理移动剩余元素的函数。(你不能使用memcpy()源和目标重叠的地方——如果在同一个数组中复制——它们会这样做)。memmove()可以在源和目标重叠时使用。对于较大的数组,使用memmove()而不是逐个元素循环会更快(一次移动多个元素)

如果您只是模拟从数组中删除元素,则实际上不需要 a newArray,只需在arr. 把它放在一起,你可以这样做:

#include <stdio.h>
#include <string.h>

int main (void)
{
    int arr[] = { 1, 1, 2, 2, 2, 3, 3, 4, 8, 8 },   /* array */
        n = sizeof arr / sizeof *arr;               /* number of elements */

    for (int i = 1; i < n; i++) {               /* loop over elements */
        int j = i;                              /* initialize j = i */
        while (j < n && arr[j] == arr[j-1])     /* scan forward while current == prev */
            j++;                                /* increment until difference or end */
        if (j != i) {                           /* if duplicates found */
            if (j + 1 < n) {                        /* if not last elem */
                memmove (&arr[i], &arr[j],          /* move rest to current */
                        (n - j - 1) * sizeof *arr); /* (move total bytes) */
                n -= j - i;                         /* subtract removed elem from n */
            }
            else    /* last element */
                n = i;                              /* set n to current index */
        }
    }

    for (int k = 0; k < n; k++) {               /* loop over modified array */
        printf (k ? ",%d" : "%d", arr[k]);      /* output elements */
    }
    putchar ('\n');     /* tidy up with newline */
}

注意:数组已更新为包含多个相邻的重复项(和三次重复),并且数组必须按排序顺序或重复的元素必须彼此相邻以用于上述例程)

用于memmove()移动元素时,您必须移动构成该元素数量的字节总数。例如,要移动数组中的两个整数元素,您必须移动2 * sizeof *arr字节。

示例使用/输出

{ 1, 1, 2, 2, 2, 3, 3, 4, 8, 8 }从结果中删除重复元素:

$ ./bin/arr_del_elem
1,2,3,4,8

或者更有趣的删除,使用:

    int arr[] = { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 
                5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9 },   /* array */

结果

$ 0,1,2,3,4,5,6,7,8,9

有很多方法可以处理这个过程,这只是其中一种。


推荐阅读