Chinaunix首页 | 论坛 | 博客
  • 博客访问: 222467
  • 博文数量: 136
  • 博客积分: 2919
  • 博客等级: 少校
  • 技术积分: 1299
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-11 09:08
文章分类

全部博文(136)

文章存档

2013年(1)

2011年(135)

我的朋友

分类: C/C++

2011-03-18 08:51:53

2.6 Growing Arrays

2011-03-18 Fri

Growing a sorted array by inserting n elements one at a time is an O(n2) operation that should be avoided if n is large.

Often, though, we need to keep track of a variable but small number of things, and arrays can still be the method of choice. To minimize the cost of allocation, the array should be resized in chunks, and for cleanliness the array shoud gathered together with the information necessary to maintain it. In C++ or Java, this would be done with classes from standard libraries; in C, we can achieve a similar result with a struct.

The following code defines a growable array of Nameval items; new items are added at the end of the array, which is grown as necessary to make room. Any element can be accessed through its subscript in constant time. This is analogous to the vector classes in the Java and C++ libraries.

  1. typedef struct Nameval Nameval;
  2. struct Nameval {
  3.         char *name;
  4.         int value;
  5. };

  6. struct NVtab {
  7.         int nval; /* current number of values */
  8.         int max; /* allocated number of values */
  9.         Nameval *nameval; /* array of name-value pairs */
  10. } nvtab;

  11. enum { NVINIT = 1, NVGROW = 2};

  12. /* addname: add new name and value to nvtab */
  13. int addname(Nameval newname)
  14. {
  15.         Nameval *nvp;
  16.         if (nvtab.nameval == NULL) {/* first time */
  17.                 nvtab.nameval = (Nameval *)malloc(NVINIT * sizeof(Nameval));
  18.                 if (nvtab.nameval == NULL)
  19.                   return -1;
  20.                 nvtab.max = NVINIT; /* initial 1 to be the array size */
  21.                 nvtab.nval = 0;
  22.         } else if (nvtab.nval >= nvtab.max) { /* grow */
  23.                 nvp = (Nameval *) realloc(nvtab.nameval, (NVGROW*nvtab.max) * sizeof(Nameval));
  24.                 if (nvp == NULL)
  25.                   return -1;
  26.                 nvtab.max *= NVGROW;
  27.                 nvtab.nameval = nvp;
  28.         }
  29.         nvtab.nameval[nvtab.nval] = newname;
  30.         return nvtab.nval++;

  31. }

The function addname returns the index of the item just added, or -1 if some error occurred.

The call to realloc grows the array to the new size, preserving the existing elements, and returns a pointer to it or NULL if there isn't enough memory. Doubling the size in each realloc keeps the expected cost of copying each element constant: if the array grew by just one element on each call, the performance could be O(n2).

The return value of realloc does not need to be cast to its final type because C promotes the void* automatically. But C++ does not; there the cast is required.

Deleting a name can be tricky, because we must decide what to do with the resulting gap in the array. If the order of elements does not matter, it is easiest to swap the last element into the hole. If order is to be preserved, however, we must move the elements beyond the hold down by one position:

  1. /* delname: remove first maching nameval from nvtab */
  2. int delname(char *name)
  3. {
  4.         int i;
  5.         for (i = 0; i < nvtab.nval; i++)
  6.           if (strcmp(nvtab.nameval[i].name, name) == 0) {
  7.                   memmove(nvtab.nameval+i, nvtab.nameval+i+1, (nvtab.nval-(i+1)) * sizeof(Nameval));
  8.                   nvtab.nval--;
  9.                   return 1;
  10.           }
  11.         return 0;
  12. }

The call to memmove squeezes the array by moving the elements down one position; memmove is a standard library routine for copying arbitrary-size blocks of memory.

Rules:

  • Arrays are the simplest way to group data.
  • Arrays are easy to use, provide O(1) access to any item, word well with binary search and quicksort, and haove little space overhead.
  • For fixed-size data sets, which can be even be constructed at compile time, or for guaranteed small collections of data, arrays are unbeatable.
  • But maintaining a changing set of values in an array can be expensive, so if the number of elements is unpredictable and potentially large, it may be better to use another data structure.
阅读(467) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~