在C中删除数组中的元素

我只是对C中的数组有一个简单的问题

从数组中删除元素的最佳方法是什么,并且在此过程中使数组变小。

即数组是n大小,然后我从数组中取出元素,然后数组变小,我删除它的数量。

基本上我把arrays视为一副牌,一旦我从牌组的顶部拿出一张牌就不应该了。

编辑:我会在一天结束前让自己疯狂,感谢所有帮助我正在尝试价值交换的事情,但它不能正常工作。

#include  #include  #include  enum faces{Ace = 0, Jack = 10, Queen, King}; char * facecheck(int d); int draw(int deck, int i); int main() { int deck[52], i, n; char suits[4][9] = { "Hearts", "Diamonds", "Clubs", "Spades"}; n = 0; for(i = 0; i<52; i++) { deck[i] = n; n++; }; for(i=0; i<52; i++) { if(i%13 == 0 || i%13 == 10 || i%13 == 11 || i%13 == 12) printf("%s ", facecheck(i%13) ); else printf("%d ", i%13+1); printf("of %s \n", suits[i/13]); } draw(deck, i); return 0; } char * facecheck(int d) { static char * face[] = { "Ace", "Jack", "Queen", "King" }; if(d == Ace) return face[0]; else { if(d == Jack) return face[1]; else { if(d == Queen) return face[2]; else { if(d == King) return face[3]; } } } } int draw(int deck,int i ) { int hand[5], j, temp[j]; for(i=0; i<52; i++) { j = i }; for(i = 0; i < 5; i++) { deck[i] = hand[]; printf("A card has been drawn \n"); deck[i] = temp[j-1]; temp[j] = deck[i]; }; return deck; } 

实际上有两个不同的问题。 第一个是保持数组元素的正确顺序,以便在删除元素后没有“漏洞”。 第二个实际上是调整数组本身的大小。

C中的数组被分配为固定数量的连续元素。 没有办法实际删除数组中单个元素使用的内存,但可以移动元素以填充通过删除元素而形成的孔。 例如:

 void remove_element(array_type *array, int index, int array_length) { int i; for(i = index; i < array_length - 1; i++) array[i] = array[i + 1]; } 

静态分配的数组无法resize。 可以使用realloc()调整动态分配的数组的大小。 这可能会将整个数组移动到内存中的另一个位置,因此必须更新指向数组或其元素的所有指针。 例如:

 remove_element(array, index, array_length); /* First shift the elements, then reallocate */ array_type *tmp = realloc(array, (array_length - 1) * sizeof(array_type) ); if (tmp == NULL && array_length > 1) { /* No memory available */ exit(EXIT_FAILURE); } array_length = array_length - 1; array = tmp; 

如果请求的大小为0,或者如果有错误,realloc将返回NULL指针。 否则,它返回一个指向重新分配的数组的指针。 临时指针用于在调用realloc时检测错误,因为不是退出它也可以保留原始数组。 当realloc无法重新分配数组时,它不会改变原始数组。

请注意,如果数组很大或者删除了很多元素,这两个操作都会相当慢。 如果有效插入和删除是优先考虑的事项,还可以使用其他数据结构,如链接列表和哈希。

每次删除内容时,您都不希望重新分配内存。 如果你知道你的套牌的粗略大小,那么为你的数组选择合适的大小,并保持指向列表当前末尾的指针。 这是一个堆栈 。

如果你不知道你的套牌的大小,并认为它可以变得非常大并且不断改变大小,那么你将不得不做一些更复杂的事情并实现一个链表 。

在C中,您有两种简单的方法来声明数组。

  1. 在堆栈上,作为静态数组

     int myArray[16]; // Static array of 16 integers 
  2. 在堆上,作为动态分配的数组

     // Dynamically allocated array of 16 integers int* myArray = calloc(16, sizeof(int)); 

标准C不允许调整这些类型的数组的大小。 您可以创建一个特定大小的新数组,然后将旧数组的内容复制到新数组,或者您可以按照上面的建议之一获取不同的抽象数据类型(即:链表,堆栈,队列,等等)。

有趣的是,索引可以随机访问数组。 并且随机删除元素也可能影响其他元素的索引。

  int remove_element(int*from, int total, int index) { if((total - index - 1) > 0) { memmove(from+i, from+i+1, sizeof(int)*(total-index-1)); } return total-1; // return the new array size } 

请注意,由于内存重叠, memcpy在这种情况下不起作用。

删除一个随机元素的有效方法之一(比内存移动更好)是使用最后一个元素进行交换。

  int remove_element(int*from, int total, int index) { if(index != (total-1)) from[index] = from[total-1]; return total; // **DO NOT DECREASE** the total here } 

但删除后订单会发生变化。

再次,如果在循环操作中完成移除,则重新排序可能影响处理。 内存移动是在删除数组元素时保持顺序的一种昂贵的替代方法。 在循环中保持顺序的另一种方法是推迟删除。 它可以通过相同大小的有效数组来完成。

  int remove_element(int*from, int total, int*is_valid, int index) { is_valid[index] = 0; return total-1; // return the number of elements } 

它将创建一个稀疏数组。 最后,通过进行一些重新排序,可以使稀疏数组变得紧凑(不包含两个在它们之间包含无效元素的有效元素)。

  int sparse_to_compact(int*arr, int total, int*is_valid) { int i = 0; int last = total - 1; // trim the last invalid elements for(; last >= 0 && !is_valid[last]; last--); // trim invalid elements from last // now we keep swapping the invalid with last valid element for(i=0; i < last; i++) { if(is_valid[i]) continue; arr[i] = arr[last]; // swap invalid with the last valid last--; for(; last >= 0 && !is_valid[last]; last--); // trim invalid elements } return last+1; // return the compact length of the array }