1

我有一个问题,我需要编写一个函数,该函数从键盘读取整数 X 和 int 类型(大小 N)的数组 A,并消除 A 中所有出现的 X。例如,输入是:

5

1 2 3 4 3

3

它会返回:

答:1 2 3 4 3

新答:1 2 4

到目前为止我的代码是

#include <stdio.h>
#include<stdlib.h>
#define DIM 50
int main() {
    int *A;
    int N, X;
    int *P1, *P2;
    do{
     scanf("%d", &N);
    }while(N<0 || N>DIM);

A= (int*)malloc(N*sizeof(int));

for(P1=A; P1<A+N ; P1++)
 scanf("%d ", P1);
printf("\n");

scanf("%d",&X);

printf("A : ");
for(P1=A; P1<A+N ; P1++)
 printf("%d ", *P1);
printf("\n");

但如果你能帮忙,我不知道如何继续

4

4 回答 4

2

您需要编写一个函数,该函数将擦除等于指定值的元素并重新分配结果数组。

这是一个演示程序,其中显示了这样的功能。

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

size_t erase_remove( int **a, size_t n, int value )
{
    size_t m = 0;

    for (int *p = *a, *q = *a; p != *a + n; ++p)
    {
        if (*p != value)
        {
            if (q != p) *q = *p;
            ++q;
            ++m;
        }
    }

    if (m != n)
    {
        int *tmp = realloc( *a, m * sizeof( int ) );

        if (tmp != NULL)
        {
            *a = tmp;
        }
        else
        {
            m = -1;
        }
    }

    return m;
}

int main( void )
{
    size_t n = 5;
    int *a = malloc( n * sizeof( int ) );

    size_t i = 0;
    a[i++] = 1, a[i++] = 2, a[i++] = 3, a[i++] = 4, a[i++] = 3;

    int value = 3;

    size_t m = erase_remove( &a, n, value );

    if (m != -1) n = m;

    for (const int *p = a; p != a + n; ++p)
    {
        printf( "%d ", *p );
    }
    putchar( '\n' );

    free( a );
}

程序输出为

1 2 4

如果函数内数组的内存重新分配不成功,则函数返回值(size_t)-1

该函数在删除等于目标值的元素后保留元素的顺序。

如果要使函数更通用,不仅可以处理动态分配的数组,那么它看起来会非常简单。

size_t erase_remove( int *a, size_t n, int value )
{
    size_t m = 0;

    for (int *p = a, *q = a; p != a + n; ++p)
    {
        if (*p != value)
        {
            if (q != p) *q = *p;
            ++q;
            ++m;
        }
    }

    return m;
}

在这种情况下,函数的调用者应根据函数的返回值重新分配结果动态分配的数组(如果需要)m

于 2022-01-05T18:18:24.143 回答
0

这是一种方法:


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

void print_arr(int *arr, size_t size);

size_t remove_by_value(int *arr, size_t len, int value)
{
  int count = 0; // maintain how many times we see value
  int k;
  for(k = 0; k < len ; k++) {
      if ( arr[k] == value ) {
          while(arr[count+k] == value) {
              count++;
          } // skip over conscutive values
          if ( count + k >= len )
              break;
          arr[k] = arr[k+count];
          arr[k+count] = value;
          print_arr(arr, len);
      }
  }
  return len-count;
}

void print_arr(int *arr, size_t size)
{
  for(int k = 0; k < size; k++) {
    printf("%02d ", arr[k]);
  }
  printf("---\n");
}

int main()
{
  int test_values[] = { 0, 1, 3, 2, 3, 5, 4, 7, 8 };
  size_t len = sizeof(test_values)/sizeof(int);
  int *arr = malloc(len*sizeof(int));
  memcpy(arr, test_values, len*sizeof(int));
  print_arr(arr, len);
  len = remove_by_value(arr, len, 3);
  print_arr(arr, len);
  arr = realloc(arr, len);
  print_arr(arr, sizeof(int)*len);
  return 0;
}

它将要提取的值冒泡到数组的末尾并将其关闭。好消息是它不使用任何额外的内存来完成它的工作。

第二部分是它不是 O(n^2) 我必须考虑一下它的复杂性(似乎比 O(n) 大)

然而,这是一个简单的解决方案,可以保持数组的顺序,简单地删除不需要的值。

我在print_arr循环的每一步都加入了这个函数,这样你就可以看到发生了什么。

希望代码的目的很明确,如果您有任何问题,请发表评论,我将进一步解释。

笔记

  1. 我明确没有使用sizeof(*arr),因为我希望它更清楚它是什么。在生产代码中,人们会使用sizeof(*arr)而不是sizeof(int)...。但是我将无法创建一个一致的示例(例如,remove_by_value 必须同样具有通用性)所以我没有让示例简单易懂。
于 2022-01-05T23:37:25.157 回答
0
#define N_MAX 50
#define N_MIN 0

int main(void) {
    int n;

    do{
        scanf("%d", &n);
    }while(N<N_MIN  || N>N_MAX);

    int *array = (int*) malloc(sizeof(int) * n);

    int i; // number of elements in array
    for (i = 0; i < n; i++) {
        scanf("%d", array + i);
    }

    int x;
    scanf("%d", &x);

    //remove x from arr
    for (int j = 0; j <= i; j++) {
        if (*(array + j) == x) {
            *(array + j) = *(array + i); // replace removed value by last value in array
            i--; // decremment number of elements in array
        }
    }

    // print
    for (int j = 0; j <= i; j++) {
        print("%d", *(array + j)); 
    }

    free(array)
}


于 2022-01-05T18:09:01.430 回答
0

试试这个!

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

// Required Prototypes
int *get_nums(char *, size_t *);
int *remove_num(int *, size_t *, int);
void display(char *, int *, size_t);

int main(int argc, char *argv[])
{
    size_t size = 0;
    int *arr = get_nums("Enter numbers (seperated by space): ", &size);
    
    int num;
    printf("Enter number to be removed: ");
    scanf("%d", &num);
    display("Old Array: ", arr, size);
    
    arr = remove_num(arr, &size, num);
    display("New Array: ", arr, size);
    
    free(arr);
    return 0;
}

int *get_nums(char *label, size_t *size)
{
  size_t length = 0;
  int *arr = NULL;
  
  printf("%s", label);
    
    int c, num;
    do {
      scanf("%d", &num);
      arr = realloc(arr, (length + 1) * sizeof(int));
      arr[length++] = num;
    } while ( (c = getchar()) != '\n' && c != EOF);
    
    *size = length;
    return arr;
}

int *remove_num(int *arr, size_t *size, int num)
{
  // Copy elements to the new array
  // Return the new array
  size_t new_size = 0;
  int *new_arr = NULL;
  
  for (size_t i = 0; i < *size; ++i) {
    if (arr[i] != num) {
      new_arr = realloc(new_arr, (new_size + 1) * sizeof(int));
      new_arr[new_size++] = arr[i];
    }
  }
  
  *size = new_size;
  free(arr);
  return new_arr;
}

void display(char *label, int *arr, size_t size)
{
  printf("%s", label);
  
  for (size_t i = 0; i < size; ++i)
    printf("%d ", arr[i]);
    
  printf("\n");
}

主要思想是创建一个整数数组。然后将这些元素复制到您不想删除的新数组中。最后显示新数组。就这样。是的,就是这么简单。;-)

Enter numbers (seperated by space): 1 2 3 4 3
Enter number to be removed: 3
Old Array: 1 2 3 4 3
New Array: 1 2 4

正如@Ahmed Masud 在关于太多重新分配的评论中所说,这是我修改后的答案。请注意,下面的代码有点复杂,但比我之前的代码高效得多。

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

typedef struct {
  int *a;
  size_t length;
  size_t capacity;
} Array;

// Required Prototypes
Array *init_Array(void);
void destroy(Array *);

Array *get_nums(char *);
void remove_num(Array *, int);
void display(char *, Array *);

int main(int argc, char *argv[])
{
    Array *arr = get_nums("Enter Numbers (seperated by space): ");
    
    int num;
    printf("Enter number to be removed: ");
    scanf("%d", &num);
    display("Old Array: ", arr);
    
    remove_num(arr, num);
    display("New Array: ", arr);
    
    destroy(arr);
    return 0;
}

Array *init_Array(void)
{
  Array *arr = malloc( sizeof(Array) );
  arr->capacity = 1;
  arr->length = 0;
  arr->a = malloc( sizeof(int) );
  return arr;
}

Array *get_nums(char *label)
{
  printf("%s", label);
  
  Array *arr = init_Array();
  int c, num;
  
  do {
    scanf("%d", &num);
    // check and reallocate
    if (arr->length == arr->capacity) {
      arr->a = realloc(
        arr->a, 
        (2 * arr->capacity) * sizeof(int)
      );
      arr->capacity *= 2;
    }
    
    arr->a[arr->length++] = num;
  } while ((c = getchar()) != '\n' && c != EOF);
  
  return arr;
}

void remove_num(Array *arr, int num)
{
  int remv_idx = -1;
  int *a = arr->a;
  size_t count = 0;
  
  for (size_t i = 0; i < arr->length; ++i) {
    if (a[i] == num) count++;
    
    if (a[i] == num && remv_idx == -1)
      remv_idx = i;
      
    if (remv_idx != -1 && remv_idx < i && a[i] != num)
      a[remv_idx++] = a[i];
  }
  
  arr->length -= count;
  arr->capacity = arr->length;
  arr->a = realloc(a, arr->capacity * sizeof(int));
}

void display(char *label, Array *arr)
{
  printf("%s", label);
  
  for (size_t i = 0; i < arr->length; ++i)
    printf("%d ", arr->a[i]);
    
  printf("\n");
}

void destroy(Array *arr)
{
  free(arr->a);
  free(arr);
}

在这里,我没有考虑任何新数组,而是删除了元素。我保留了我的两个解决方案,因为如果您的输入空间很小,您可能不需要第二个解决方案。还有一件事,因为这个问题没有提到任何重新分配失败,所以我没有在我的代码中检查它。

于 2022-01-05T18:43:00.357 回答