代码改变世界

C语言 线性表 顺序表结构 实现

2013-10-21 12:04  wid  阅读(8724)  评论(4编辑  收藏  举报

一个能够自动扩容的顺序表 ArrList (GCC编译)。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define TRUE 1
  6 #define FALSE 0
  7 
  8 typedef struct
  9 {
 10     int x;
 11     int y;
 12 }Point2D;   // Point2D 结构
 13 
 14 typedef struct
 15 {
 16     Point2D *pt;   //线性表的数据项
 17     int length;    //线性表当前长度
 18     int size;      //线性表总容量
 19 }ArrList;   // ArrList 结构
 20 
 21 
 22 //声明线性表所具有的方法
 23 ArrList *CreateArrList( int nLength );       //创建长为 nArrLength 的线性表
 24 void DestroyArrList( ArrList *pArrList );    //销毁线性表 pArrList
 25 void ClearArrList( ArrList *pArrList );      //置空线性表 pArrList
 26 int IsEmptyArrList( ArrList *pArrList );     //检测线性表是否为空
 27 int GetArrListLength( ArrList *pArrList );   //获取线性表长度
 28 int GetArrListSize( ArrList *pArrList );     //获取线性表总容量
 29 int GetArrListElement( ArrList *pArrList, int n, Point2D *pt );   //获取线性表中第n个元素
 30 int FindElement( ArrList *pArrList, int nPos, Point2D *pt );      //从 nPos 起查找 pt 第一次出现的位置
 31 int GetPriorElement( ArrList *pArrList, Point2D *pt, Point2D *prior_pt );   //获取 pt 的前驱节点到 prior_pt
 32 int GetNextElement( ArrList *pArrList, Point2D *pt, Point2D *next_pt );     //获取 pt 的后继节点到 next_pt
 33 int AppendToArrList( ArrList *pArrList, Point2D *pt );            //将 pt 添加到线性表末尾处
 34 int InsertToArrList( ArrList *pArrList, int nPos, Point2D *pt );  //将 pt 插入到 nPos 处
 35 int DeleteFromArrList( ArrList *pArrList, int nPos );             //删除线性表上位置为 nPos 的元素
 36 void ForEachArrList( ArrList *pArrList, void (*func)(Point2D *pt) );              //对线性表中每个元素执行 func 函数
 37 int ArrListCpy( ArrList *pArrListDest, ArrList *pArrListSrc );    //将线性表 pArrListSrc 复制到 pArrListDest
 38 int ArrListCat( ArrList *pArrListDest, ArrList *pArrListSrc );    //将线性表 pArrListSrc 连接到 pArrListDest 的末尾
 39 
 40 
 41 //线性表方法实现
 42 /**
 43 * @brief 创建长度为 nLength 的线性表 ArrList
 44 *
 45 * @param nLength 所要构建的线性表长度
 46 *
 47 * @return 指向所创建的线性表的指针
 48 */
 49 ArrList *CreateArrList( int nLength )
 50 {
 51     ArrList *pl = (ArrList *)malloc( sizeof(ArrList) );
 52 
 53     pl->pt = (Point2D *)calloc( nLength, sizeof(Point2D) );
 54     pl->length = 0;
 55     pl->size = nLength;
 56 
 57     return pl;
 58 }
 59 
 60 /**
 61 * @brief 销毁一条线性表
 62 *
 63 * @param pArrList 指向待销毁线性表的指针
 64 *
 65 * @return void
 66 */
 67 void DestroyArrList( ArrList *pArrList )
 68 {
 69     free( pArrList->pt );   ///先释放线性表pt
 70     free( pArrList );       ///销毁线性表pArrList
 71 }
 72 
 73 /**
 74 * @brief 置空一条线性表
 75 *
 76 * @param pArrList 指向待置空线性表的指针
 77 *
 78 * @return void
 79 */
 80 void ClearArrList( ArrList *pArrList )
 81 {
 82     pArrList->length = 0;
 83 }
 84 
 85 /**
 86 * @brief 检测线性表是否为空
 87 *
 88 * @param pArrList 指向待检测线性表的指针
 89 *
 90 * @return 为空则返回 TRUE, 否则返回 FALSE
 91 */
 92 int IsEmptyArrList( ArrList *pArrList )
 93 {
 94     return pArrList->length == 0 ? TRUE : FALSE;
 95 }
 96 
 97 /**
 98 * @brief 获取线性表长度
 99 *
100 * @param pArrList 指向待获取长度的线性表的指针
101 *
102 * @return 返回获取到的线性表长度
103 */
104 int GetArrListLength( ArrList *pArrList )
105 {
106     return pArrList->length;
107 }
108 
109 /**
110 * @brief 获取线性表总容量
111 *
112 * @param pArrList 指向待获取容量的线性表的指针
113 *
114 * @return 返回获取到的线性表的总容量
115 */
116 int GetArrListSize( ArrList *pArrList )
117 {
118     return pArrList->size;
119 }
120 
121 /**
122 * @brief 获取线性表中第 n 个元素
123 *
124 * @param pArrList 指向待获取其中的元素的线性表的指针
125 * @param n 要获取的第 n 个元素
126 * @param pt 用于存放获取到的元素的值的 Point2D 类型指针
127 *
128 * @return 获取成功返回 TRUE, 否则返回 FALSE
129 *
130 * @note 元素n, n 从 0 起
131 */
132 int GetArrListElement( ArrList *pArrList, int n, Point2D *pt )
133 {
134     if( n < 0 || n > pArrList->length-1 )
135         return FALSE;
136 
137     pt->x = pArrList->pt[n].x;
138     pt->y = pArrList->pt[n].y;
139 
140     return TRUE;
141 }
142 
143 /**
144 * @brief 从 nPos 处查找元素 pt 第一次出现的位置
145 *
146 * @param pArrList 指向待查找其中的元素的线性表的指针
147 * @param nPos 查找起始位置
148 * @param pt 指向待查找元素的指针
149 *
150 * @return 若找到, 返回元素 pt 在线性表中的位置(下标), 否则返回 -1
151 *
152 * @note 位置从 0 计起
153 */
154 int FindElement( ArrList *pArrList, int nPos, Point2D *pt )
155 {
156     int n = nPos;
157     for( n; n < pArrList->length; ++n )
158     {
159         if( (pArrList->pt[n].x == pt->x) && (pArrList->pt[n].y == pt->y) )
160             return n;
161     }
162 
163     return -1;
164 }
165 
166 /**
167 * @brief 获取线性表中 pt 元素的前驱节点到 prior_pt
168 *
169 * @param pArrList 指向待获取其中的元素的线性表的指针
170 * @param pt 指向目标节点的指针
171 * @param prior_pt 存放查找到的目标节点的前驱节点
172 *
173 * @return 若获取到前驱节点, 返回目标节点的前驱节点在线性表中的位置(下标),  否则返回 -1
174 *
175 * @note 位置从 0 计起
176 */
177 int GetPriorElement( ArrList *pArrList, Point2D *pt, Point2D *prior_pt )
178 {
179     int n = 0;
180     for( n = 0; n < pArrList->length; ++n )
181     {
182         if( (pArrList->pt[n].x == pt->x) && (pArrList->pt[n].y == pt->y) )
183         {
184             if( n <= 0 )        ///目标节点是头节点, 无前驱节点
185                 return -1;
186             else                ///存在并找到前驱节点
187             {
188                 prior_pt->x = pArrList->pt[n-1].x;
189                 prior_pt->y = pArrList->pt[n-1].y;
190 
191                 return n-1;
192             }
193         }
194     }
195 
196     return -1;
197 }
198 
199 /**
200 * @brief 获取线性表中 pt 元素的后继节点到 next_pt
201 *
202 * @param pArrList 指向待获取其中的元素的线性表的指针
203 * @param pt 指向目标节点的指针
204 * @param next_pt 存放查找到的目标节点的后继节点
205 *
206 * @return 若获取到后继节点, 返回目标节点的后继节点在线性表中的位置(下标),  否则返回 -1
207 *
208 * @note 位置从 0 计起
209 */
210 int GetNextElement( ArrList *pArrList, Point2D *pt, Point2D *next_pt )
211 {
212     int n = 0;
213     for( n = 0; n < pArrList->length; ++n )
214     {
215         if( (pArrList->pt[n].x == pt->x) && (pArrList->pt[n].y == pt->y) )
216         {
217             if( n >= pArrList->length-1 )        ///目标节点是尾节点, 无后继节点
218                 return -1;
219             else                ///存在并找到后继节点
220             {
221                 next_pt->x = pArrList->pt[n+1].x;
222                 next_pt->y = pArrList->pt[n+1].y;
223 
224                 return n+1;
225             }
226         }
227     }
228 
229     return -1;
230 }
231 
232 /**
233 * @brief 添加一个元素至线性表末尾
234 *
235 * @param pArrList 指向待添加元素的线性表的指针
236 * @param pt 指向待添加的元素的指针
237 *
238 * @return 成功添加则返回当前线性表长度, 否则返回 -1
239 */
240 int AppendToArrList( ArrList *pArrList, Point2D *pt )
241 {
242     if( pArrList->size - pArrList->length < 1 ) ///检测是否需要扩容
243     {
244         Point2D *p = (Point2D *)calloc(pArrList->length * 2, sizeof(Point2D));
245         memcpy( p, pArrList->pt, pArrList->length*sizeof(Point2D) );
246         pArrList->size = pArrList->length * 2;
247         free( pArrList->pt );
248         pArrList->pt = p;
249     }
250 
251     pArrList->pt[pArrList->length].x = pt->x;
252     pArrList->pt[pArrList->length].y = pt->y;
253 
254     return ++pArrList->length;
255 }
256 
257 /**
258 * @brief 插入一个元素 pt 到线性表 nPos 处
259 *
260 * @param pArrList 指向待插入元素的线性表指针
261 * @param nPos 插入的位置(下标)
262 * @param pt 指向待插入的元素的指针
263 *
264 * @return 插入成功则返回当前线性表长度, 否则返回 -1
265 *
266 * @note 插入位置 nPos 从 0 计起
267 */
268 int InsertToArrList( ArrList *pArrList, int nPos, Point2D *pt )
269 {
270     if( (nPos < 0) || (nPos > pArrList->length-1) )
271         return -1;
272 
273     if( pArrList->size - pArrList->length < 1 ) ///检测是否需要扩容
274     {
275         Point2D *p = (Point2D *)calloc(pArrList->length*2, sizeof(Point2D));
276         memcpy( p, pArrList->pt, pArrList->length * sizeof(Point2D) );
277         pArrList->size = pArrList->length * 2;
278         free( pArrList->pt );
279         pArrList->pt = p;
280     }
281 
282     int nMax = pArrList->length;                ///获取线性表插入1元素后的长度
283     for( nMax; nMax > nPos; --nMax )
284     {
285         pArrList->pt[nMax].x = pArrList->pt[nMax-1].x;
286         pArrList->pt[nMax].y = pArrList->pt[nMax-1].y;
287     }
288     pArrList->pt[nPos].x = pt->x;
289     pArrList->pt[nPos].y = pt->y;
290 
291     return ++pArrList->length;
292 }
293 
294 /**
295 * @brief 从线性表上删除一个元素
296 *
297 * @param pArrList 指向待处理线性表的指针
298 * @param nPos 需要删除的元素位置(下标)
299 *
300 * @return 成功删除返回删除后线性表长度, 否则返回 -1
301 *
302 * @note 删除位置 nPos 从 0 计起
303 */
304 int DeleteFromArrList( ArrList *pArrList, int nPos )
305 {
306     if( (nPos < 0) || (nPos > pArrList->length - 1) )
307         return -1;
308 
309     if( nPos == pArrList->length - 1 )
310         return --pArrList->length;
311 
312     for( nPos; nPos < pArrList->length; ++nPos )
313     {
314         pArrList->pt[nPos].x = pArrList->pt[nPos+1].x;
315         pArrList->pt[nPos].y = pArrList->pt[nPos+1].y;
316     }
317 
318     return --pArrList->length;
319 }
320 
321 /**
322 * @brief 对线性表中的元素依次执行传入的函数
323 *
324 * @param pArrList 指向待处理的线性表的指针
325 * @param func 传入的函数指针
326 *
327 * @return void
328 *
329 * @note 传入的函数的参数为线性表元素类型的指针
330 */
331 void ForEachArrList( ArrList *pArrList, void (*func)(Point2D *pt) )
332 {
333     int i = 0;
334     for( i = 0; i < pArrList->length; ++i )
335     {
336         func( &pArrList->pt[i] );
337     }
338 }
339 
340 /**
341 * @brief 将线性表 pArrListSrc 复制到目标线性表 pArrListDest
342 *
343 * @param pArrListDest 目标线性表
344 * @param pArrListSrc 源线性表
345 *
346 * @return 成功则返回复制后的目标线性表的长度, 否则返回 -1
347 */
348 int ArrListCpy( ArrList *pArrListDest, ArrList *pArrListSrc )
349 {
350     if( pArrListDest->size - pArrListSrc->length < 0 )  ///目标线性表是否需要扩容
351     {
352         free(pArrListDest->pt);
353         Point2D *p = (Point2D *)calloc(pArrListSrc->length, sizeof(Point2D));
354         pArrListDest->pt = p;
355         pArrListDest->size = pArrListSrc->length;
356     }
357 
358     memcpy( pArrListDest->pt, pArrListSrc->pt, pArrListSrc->length * sizeof(Point2D) );
359     pArrListDest->length = pArrListSrc->length;
360 
361     return pArrListDest->length;
362 }
363 
364 /**
365 * @brief 将线性表 pArrListSrc 连接到目标线性表 pArrListDest
366 *
367 * @param pArrListDest 目标线性表
368 * @param pArrListSrc 源线性表
369 *
370 * @return 成功则返回连接后的目标线性表的长度, 否则返回 -1
371 */
372 int ArrListCat( ArrList *pArrListDest, ArrList *pArrListSrc )
373 {
374     if( pArrListDest->size - pArrListDest->length < pArrListSrc->length )   ///目标线性表是否需要扩容
375     {
376         Point2D *p = (Point2D *)calloc(pArrListDest->length + pArrListSrc->length, sizeof(Point2D));
377         memcpy( p, pArrListDest->pt, pArrListDest->length * sizeof(Point2D) );
378         free(pArrListDest->pt);
379         pArrListDest->pt = p;
380         pArrListDest->size = pArrListDest->length + pArrListSrc->length;
381     }
382 
383     int pos = 0;
384     for(pos; pos < pArrListSrc->length; ++pos )
385     {
386         pArrListDest->pt[pArrListDest->length + pos].x = pArrListSrc->pt[pos].x;
387         pArrListDest->pt[pArrListDest->length + pos].y = pArrListSrc->pt[pos].y;
388     }
389 
390     pArrListDest->length += pArrListSrc->length;
391 
392     return pArrListDest->length;
393 }
394 
395 //测试线性表 ArrList
396 
397 //回调函数
398 void display( Point2D *pt )
399 {
400     printf( "(%d,%d) ", pt->x, pt->y );
401 }
402 
403 int main()
404 {
405     Point2D pt1, pt2;
406     ArrList *plstA = CreateArrList( 10 );        //创建一个长度为 10 的线性表 plstA
407 
408     ///
409     printf("测试添加元素..\n");
410     int i = 0;
411     for( i; i < 10; ++i )
412     {
413         pt1.x = i; pt1.y = i;
414         AppendToArrList( plstA, &pt1 );         //测试添加
415     }
416     ForEachArrList( plstA, display );           //对每个元素执行 display
417     printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
418 
419     ///
420     printf("\n测试被动扩容添加..\n");
421     for( i = 10; i < 35; ++i )
422     {
423         pt1.x = i; pt1.y = i;
424         AppendToArrList( plstA, &pt1 );         //测试被动扩容
425     }
426     ForEachArrList( plstA, display );
427     printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
428 
429     ///
430     printf("\n测试插入到头部、尾部..\n");
431     pt1.x = 100; pt1.y = 100;
432     InsertToArrList( plstA, 0, &pt1 );             //测试插入到首部
433     InsertToArrList( plstA, GetArrListLength(plstA)-1, &pt1 );             //测试插入到尾部
434     ForEachArrList( plstA, display );
435     printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
436 
437     ///
438     printf("\n测试获取节点元素..\n");
439     GetArrListElement( plstA, 5, &pt2 );           //获取节点位置为5的元素
440     printf("节点坐标为5的元素pt2: (%d,%d)\n", pt2.x, pt2.y);
441 
442     ///
443     printf("\n测试获取某元素的前驱节点..\n");
444     Point2D pri_pt, next_pt;
445     GetPriorElement( plstA, &pt2, &pri_pt );       //获取 pt2 的前驱节点
446     printf("pt2的前驱节点: (%d, %d)\n", pri_pt.x, pri_pt.y);
447     GetNextElement( plstA, &pt2, &next_pt );       //获取 pt2 的后继节点
448     printf("pt2的后继节点: (%d, %d)\n", next_pt.x, next_pt.y);
449 
450     ///
451     printf("\n测试查找元素..\n");
452     printf("元素 next_pt 在线性表中第一次出现的位置: %d\n", FindElement(plstA, 0, &next_pt));  //从 0 起查找元素 next_pt
453 
454     ///
455     printf("\n测试删除某元素..\n");
456     printf("删除位置为0的元素: ");
457     DeleteFromArrList( plstA, 0 );      //删除节点位置为0的元素
458     ForEachArrList( plstA, display );
459     printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
460 
461     ///
462     printf("\n测试复制线性表..\n");
463     printf("创建线性表 plstB : ");
464     ArrList *plstB = CreateArrList( 50 );
465     for( i = 50; i < 60; ++i )
466     {
467         pt2.x = i; pt2.y = i;
468         AppendToArrList( plstB, &pt2 );
469     }
470     ForEachArrList( plstB, display );
471     printf( "\nplstB len = %d, size = %d\n", GetArrListLength(plstB), GetArrListSize(plstB) );
472     printf("将 plstB 复制到 plstA: \n");
473     ArrListCpy( plstA, plstB );             //将线性表 plstB 复制到 plstA
474     ForEachArrList( plstA, display );
475     printf( "plstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
476 
477     ///
478     printf("\n测试连接线性表..\n");
479     printf("将 plstB 连接到 plstA: ");
480     ArrListCat( plstA, plstB );             //将线性表 plstB 连接到 plstA
481     ForEachArrList( plstA, display );
482     printf( "\nplstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
483 
484     ///
485     printf("\n测试清空线性表..\n");
486     ClearArrList( plstA );                  //清空线性表 plstA
487     ForEachArrList( plstA, display );
488     printf( "plstA len = %d, size = %d\n", GetArrListLength(plstA), GetArrListSize(plstA) );
489     printf( "IsEmpty = %d\n", IsEmptyArrList(plstA) );
490 
491     ///
492     printf("\n销毁线性表..\n");
493     DestroyArrList( plstA );        //销毁线性表, 释放资源
494     DestroyArrList( plstB );
495 
496     return 0;
497 }

 

若存在 bug 或程序缺陷, 请留言反馈, 谢谢。