【问题标题】:Deleting Elements from an Array based on their Position every 3 Elements根据每 3 个元素的位置从数组中删除元素
【发布时间】:2018-06-21 13:32:02
【问题描述】:

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

0 1 

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

0 1 3 1 2 4 

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

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

比较数组Arr 的下三个元素(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;
}

【问题讨论】:

  • @Gerhardh 我必须这样做,因为代码是另一个项目的一部分,其中每 3 个元素进行一次比较。抱歉,不清楚。
  • “从数组中删除元素”是什么意思?数组具有固定数量的元素;您不能向其中添加元素或从中删除元素。您可以做的是将有用元素的数量存储在某处并操作数组中有用的部分。
  • position_indices 在您的代码中扮演什么角色。
  • for (int i = 0; i &lt; 6; i++) 你总是打印所有 6 个元素。您需要跟踪删除了多少元素。
  • 将其视为复制整个数组但跳过您不想要的条目。

标签: c arrays if-statement indices array-difference


【解决方案1】:

您可以尝试这样的事情(未测试)。

#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;
}

【讨论】:

    【解决方案2】:

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

    #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;
    }
    

    【讨论】:

    • 使用 memmove() 使得这个 O(n^2)。最好在检查时移动元素。
    • 谢谢!非常感谢您的帮助:)
    【解决方案3】:

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

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

    最后,您似乎在这里遇到了一个错误:

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

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

    建议,然后:

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

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

    【讨论】:

      【解决方案4】:

      您从未真正“删除”任何元素,您只是将 每个 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;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多