C函数检查排序数组中的重复项[没有任何附加数组]

mkshixfv  于 2023-01-04  发布在  其他
关注(0)|答案(2)|浏览(94)

我正在做一些家庭作业,我卡在一节,我需要移动所有重复的排序数组到数组的末尾。我知道如何用1个额外的数组,但没有额外的数组,我不知道(有点混乱的指针)
我尝试了这个想法:(但它不起作用,不知道为什么)

int main()
{
    int newArr[12] =  {1,2,2,2,3,3,5,6,7,7,9,9 };
    int n = 12;
    int first = 0;
    int last = n - 1;
    int* D = arr + 1;
    int j = 0;
        for (int i = 0; i < n; i++)
    {
        j = i + 1;

        while (j < n)
        {
            if (newArr[i] != *D)
            {
                D++;
            }
            if (newArr[i] == *D)
            {
                swap(&newArr[i], &newArr[last]);
                j++;
                last--;
            }
            j++;
        }
        
            
    }
    for (int i = 0; i < n; i++)
    {
        printf("%d", newArr[i]);
    }
}

工作的2阵列版本:

int moveDuplicatesV1(int* arr, int n)
{
    int* seen_before = (int*)calloc(n * 2 + 1, sizeof(int));
    assert(seen_before);
    int val = 0, count = 0, flag = 1;
    int j = 0;
    for (int i = 0; i < n; i++)
    {
        val = arr[i];
        if (seen_before[arr[i] + n] == 0)
        {
            seen_before[arr[i] + n]++;
            count++;
            continue;

        }
        else if (flag)
        {
            j = i + 1;
            flag = 0;
        }
        while (j < n)
        {
            if (seen_before[arr[j] + n] == 0)
            {
                count++;
                seen_before[arr[j] + n]++;
                swap(&arr[i], &arr[j]);
                j++;
                if (j == n)
                {
                    free(seen_before);
                    return count;
                }
                break;
            }
            /*break;*/
            j++;
            if (j == n)
            {
                free(seen_before);
                return count;
            }
        }
    }
}
d8tt03nd

d8tt03nd1#

考虑您的阵列:

0   1   2   3   4   5   6   7   8   9   10  11
+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 2 | 2 | 3 | 3 | 5 | 6 | 7 | 7 | 9 | 9 |
+---+---+---+---+---+---+---+---+---+---+---+---+

听起来你是想:

0   1   2   3   4   5   6   7   8   9   10  11
+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 5 | 6 | 7 | 9 | 2 | 2 | 3 | 7 | 9 |
+---+---+---+---+---+---+---+---+---+---+---+---+

如果我们从索引0开始并与索引1进行比较,它们是不同的,因此我们继续比较索引1和索引2。

  • 它们是相同的。* 因此,我们将dupes_found变量从0递增到1。我们保存arr[i],并将数组的其余部分向前移动1个位置,然后将arr[i]中的内容复制到数组的最后一个位置。
0   1   2   3   4   5   6   7   8   9   10  11
+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 2 | 3 | 3 | 5 | 6 | 7 | 7 | 9 | 9 | 2 |
+---+---+---+---+---+---+---+---+---+---+---+---+

因为我们已经移动了数组,所以我们没有向前移动,现在我们再次比较索引1和2,它们仍然是相同的,所以我们重复,再次递增dupes_found

0   1   2   3   4   5   6   7   8   9   10  11
+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 3 | 5 | 6 | 7 | 7 | 9 | 9 | 2 | 2 |
+---+---+---+---+---+---+---+---+---+---+---+---+

当数组的长度减去dupes_found时,工作就完成了。
实现可能类似于:

void relocate_duplicates_to_end(int *arr, size_t n) {
    size_t dupes_found = 0;

    for (size_t i = 0; i < n - 1 - dupes_found;) {
        if (arr[i] == arr[i+1]) {
            dupes_found++;
            int temp = arr[i];
            memmove(&arr[i], &arr[i+1], sizeof(int) * (n - i - 1));
            arr[n - 1] = temp;
        }
        else {
            i++;
        }
    }
}
wlp8pajw

wlp8pajw2#

@Chris为你画了一些漂亮的图片,我编写了匹配的实现。从位置1而不是0开始是一个小的重构。我的实现,如下所述,返回一个指针指向第一个重复的值。

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

/*
 [0; i[: unique values
 [i; n - d[: possible duplicates (yet to be processed)
 [n-d; n[: duplicates

 return pointer to first duplicate value.  Note this is
 1 past the end of a if there are no duplicates.  This is
 ok just don't dereference it before checking.
*/
int *partition(size_t n, int a[n]) {
    size_t d = 0;
    for(size_t i = 1; i < n-d;) {
        if(a[i-1] == a[i]) {
            int tmp = a[i];
            memmove(a+i, a+i+1, (n-i-1) * sizeof(*a));
            a[n-1] = tmp;
            d++;
            continue;
        }
        i++;
    }
    return a + n - d;
}

void print_a(const char *prefix, size_t n, const int a[n]) {
    printf("%s", prefix);
    for(size_t i = 0; i < n; i++) {
        printf("%d%s", a[i], i + 1 < n ? ", " : "");
    }
    printf("\n");
}

int main() {
    int a[] = {1,2,2,2,3,3,5,6,7,7,9,9};
    size_t n = sizeof a / sizeof *a;
    int *p = partition(n, a);
    print_a("unique   : ", p - a, a);
    print_a("duplicate: ", n - (p - a), p);
}

输出为:

unique   : 1, 2, 3, 5, 6, 7, 9
duplicate: 2, 2, 3, 7, 9

您可以选择移动n - d - i - 2元素,并在a [d](而不是a [n-1])插入新的重复元素。这将反向排序重复分区。如果您关心,请在返回之前反向排序重复分区。这可能会快一些。
另一种优化是通过如上所述将第一个复制到tmp中来移动(r-1)个重复值的运行,用memmove()创建(r-1)个孔,然后在该孔中写入tmp的(r-1)个副本(在a[d-r-1]a[n-r-1]处)。

相关问题