根据每 3 个元素的位置从数组中删除元素

Deleting Elements from an Array based on their Position every 3 Elements

我创建了一个名为 elements_n 的数组,其中包含 0N-1 的元素,其中 N 为 2。下面的数字是名为 elements_n:

0 1 

我有另一个名为 Arr 的数组,它包含以下元素:

0 1 3 1 2 4 

如果数组 Arr 的前 3 个元素中的任何一个等于 elements_n 的第一个元素 0,我想从数组中删除该元素称为 Arr。然后我对数组 Arr 的下 3 个元素重复相同的过程。所以为了更好地解释我自己,我将使用以下示例:

比较数组 Arr 的前 3 个元素(0、1、3)与 elements_n 的第一个元素(0)。因为 Arr[0] == elements_n[0]。我从数组 Arr 中删除 Arr[0]

将数组 Arr 的下 3 个元素(1、2、4)与 elements_n 的第二个元素(1)进行比较。因为 Arr[3] == elements_n[1]。我从数组 Arr 中删除 Arr[3]。所以应该留在数组 Arr 中的元素是:

1 3 2 4

当我用下面的代码在 C 编程中自己实现它时,最终结果如下:

 1       3       3       2       2       4

而不是:

  1       3       2       4

这是我实现的代码:

#include <stdio.h>
#include <stdlib.h>
#define N 2 

int main() {    
    unsigned *elements_n = malloc(N * sizeof(unsigned));

    for (int i = 0; i < N; i++) {
        elements_n[i] = i; //Created an array which has the elements 0 to N-1
    }
    printf("\n");

    unsigned Arr[6] = { 0, 1, 3, 1, 2, 4 };
    unsigned position_indices[2] = { 3, 3 };  //Moving every 3 elements in the Arr array. 

    int count = 0; 
    int index = 0;
    unsigned *ptr_Arr = &Arr[0];

    do {
        for (int i = 0; i < position_indices[count]; i++) {
            if (ptr_Arr[i] == elements_n[count]) {
                index = i + 1; //Index of the Arr element that has the same value as the element in the array elements_n 

                for (int j = index - 1; j < position_indices[count] - 1; j++) {
                    ptr_Arr[j] = ptr_Arr[j + 1];
                }
            }
        }
        printf("\n");
        ptr_Arr += position_indices[count] - 1; 
        count++;
    } while (count < 2);

    for (int i = 0; i < 6; i++) {
        printf("%d\t", Arr[i]);
    }
    printf("\n");

    free(elements_n);

    return 0;
}

您需要跟踪从数组中删除了多少元素。
我的解决方案:

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

size_t fancy_delete_3(const int elems[], size_t elemssize, int arr[], size_t arrsize)
{
    assert(elems != NULL);
    assert(arr != NULL);
    assert(arrsize%3 == 0);
    assert(elemssize*3 == arrsize);
    // we need to count the removed elements, to know how much we need to shift left
    size_t removed = 0;
    // for each element in elems
    for (size_t i = 0; i < elemssize; ++i) {
        // check the three correponding elements in arr
        for (size_t j = i*3; j < (i+1)*3; ++j) {
            assert(j >= removed);
            const size_t pos = j - removed;
            // if elems[i] matches any of the corresponding element in arr
            if (elems[i] == arr[pos]) {
                // remove element at position pos
                assert(arrsize >= pos + 1);
                // I don't think this can ever overflow
                memmove(&arr[pos], &arr[pos + 1], (arrsize - pos - 1) * sizeof(int));
                ++removed;
                // array is one element shorter, so we can just decrease the array size
                assert(arrsize > 0);
                --arrsize;
            }
        }
    }
    // we return the new size of the array
    return arrsize;
}

#define __arraycount(x) sizeof(x)/sizeof(x[0])

int main()
{
    int elements_n[] = {0,1};
    int arr[] = {0,1,3, 1,2,4};
    size_t newsize = fancy_delete_3(elements_n, __arraycount(elements_n), arr, __arraycount(arr));

    printf("arr size=%zu {", newsize);
    for (size_t i = 0; i < newsize; ++i)
        printf("%d,", arr[i]);
    printf("}\n");

    return 0;
}

您可以尝试这样的操作(未测试)。

#include <stdio.h>
#include <stdlib.h>
#define N 2 

int main()
{ 
  unsigned *elements_n = malloc(N * sizeof(unsigned));
  for (int i = 0; i < N; i++)
  {
    elements_n[i] = i; //Created an array which has the elements 0 to N-1
  }

  unsigned Arr[6] = { 0, 1, 3, 1, 2, 4 };

  int dest_index = 0;
  int src_index = 0;
  int count = sizeof(Arr)/sizeof(Arr[0]); 

  for ( ; src_index < count; src_index++)
  {
    int group = src_index / 3;
    if (Arr[src_index] != elements_n[group])
    {
      Arr[dest_index++] = Arr[src_index];
    }
  }

  for (int i = 0; i < dest_index; i++)
  {
    printf("%d\t", Arr[i]);
  }
  printf("\n");

  free(elements_n);

  return 0;
}

关于如何执行删除,您有几个相关的问题。首先,不清楚您是否了解实际上不能从 C 数组中删除任何内容。最接近的是用其他东西覆盖它。通常,从数组中伪删除是通过将删除的一个位置之后的每个元素向前移动一个位置,并减少数组的逻辑长度来实现的。* 您似乎选择了这个替代方案,但是(问题 1)您错过了维护或更新逻辑数组长度的机会。

由于您在逻辑上将数组细分为多个段,您的问题变得有点复杂,而且您似乎没有意识到您的段是 可变长度 ,如前所述,当您删除元素时,它们会缩小。这是因为从一个组中删除一个元素不会改变元素对其他组的分配。您 position_groups 中有一个机制,显然用于跟踪组的大小,从这个意义上说,它的名字似乎不合适。就像您需要跟踪和更新整个数组的逻辑长度一样,您需要跟踪和更新组的长度。

最后,您这里似乎有一个差一错误:

              for (int j = index - 1; j < position_indices[count]-1; j++)

如果 position_indices 的名称更好(见上文),那会更清楚,但认识到它实际包含的是每个组的 大小,并且 indexj 表示组内的索引,因此迭代的边界条件应该只是 j < position_indices[count]。但是,这没有实际意义,因为无论如何您在这里都需要一种稍微不同的方法。

建议,然后:

  1. 当您从组中删除一个元素时,向上移动整个数组的尾部,而不仅仅是组的尾部。
  2. 为此,在执行删除时更新组大小和逻辑数组大小,记住这也会影响每个后续组 开始的位置
  3. 当您检查或输出结果时,请记住忽略超出数组逻辑末尾的数组元素。

* "Logical array size" 表示包含有意义数据的(前导)元素的数量。在您的情况下,逻辑数组大小最初与物理数组大小相同,但每次删除一个元素(因此向上移动尾部)时,逻辑大小都会减少一个。

你从来没有真正 "deleted" 任何元素,你只是向下移动了 每个 3 组的第二个和第三个元素。然后,当 打印,你迭代了整个数组。

数组只是连续的内存块,所以你需要一个 不同的策略。你可以遍历原始数组 两个索引,一个作为通用索引计数器,另一个作为 移位槽的索引。如果当前元素是 与对应的elements_n项不同,复制到 二级索引并增加它。

如果没有什么等于 elements_n 项,您只需 将数组元素重新分配给它们自己。然而,一旦 一个是相等的,您将利用以下优势移动它们 跟踪新尺寸。

另外,计算对应的elements_n项很简单 将当前索引除以 3 的问题,所以你甚至不需要 一个额外的变量。

#include <stdio.h>
#define N 2

int main()
{
    unsigned elements_n[N] = { 0, 1 };
    unsigned Arr[N*3] = { 0, 1, 3, 1, 2, 4 };
    int i, j;

    for (i = 0, j = 0; i < N*3; i++)
        if (Arr[i] != elements_n[i/3])
            Arr[j++] = Arr[i];

    for (i = 0; i < j; i++)
        printf(" %d", Arr[i]);
    printf("\n");

    return 0;
}