C語言 線性表 順序表結構 實現

一個可以自動擴容的順序表 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 或程序缺陷, 請留言反饋, 謝謝。測試

相關文章
相關標籤/搜索