1. 程式人生 > >詳解堆疊的幾種實現方法——C語言版

詳解堆疊的幾種實現方法——C語言版

基本的抽象資料型別(ADT)是編寫C程式必要的過程,這類ADT有連結串列、堆疊、佇列和樹等,本文主要講解下堆疊的幾種實現方法以及他們的優缺點。

  堆疊(stack)的顯著特點是後進先出(Last-In First-Out, LIFO),其實現的方法有三種可選方案:靜態陣列、動態分配的陣列、動態分配的鏈式結構。

  靜態陣列:特點是要求結構的長度固定,而且長度在編譯時候就得確定。其優點是結構簡單,實現起來方便而不容易出錯。而缺點就是不夠靈活以及固定長度不容易控制,適用於知道明確長度的場合。

  動態陣列:特點是長度可以在執行時候才確定以及可以更改原來陣列的長度。優點是靈活,缺點是由此會增加程式的複雜性。

  鏈式結構:特點是無長度上線,需要的時候再申請分配記憶體空間,可最大程度上實現靈活性。缺點是鏈式結構的連結欄位需要消耗一定的記憶體,在鏈式結構中訪問一個特定元素的效率不如陣列。

  首先先確定一個堆疊介面的標頭檔案,裡面包含了各個方案下的函式原型,放在一起是為了實現程式的模組化以及便於修改。然後再接著分別介紹各個方案的具體實施方法。

  堆疊介面stack.h檔案程式碼:

  1. /* 
  2. ** 堆疊模組的介面 stack.h 
  3. */
  4. #include<stdlib.h>
  5. #define STACK_TYPE int /* 堆疊所儲存的值的資料型別 */
  6. /* 
  7. ** 函式原型:create_stack 
  8. ** 建立堆疊,引數指定堆疊可以儲存多少個元素。 
  9. ** 注意:此函式只適用於動態分配陣列形式的堆疊。 
  10. */
  11. void create_stack(size_t size);  
  12. /* 
  13. ** 函式原型:destroy_stack 
  14. ** 銷燬一個堆疊,釋放堆疊所適用的記憶體。 
  15. ** 注意:此函式只適用於動態分配陣列和鏈式結構的堆疊。 
  16. */
  17. void destroy_stack(void);  
  18. /* 
  19. ** 函式原型:push 
  20. ** 將一個新值壓入堆疊中,引數是被壓入的值。 
  21. */
  22. void push(STACK_TYPE value);  
  23. /* 
  24. ** 函式原型:pop 
  25. ** 彈出堆疊中棧頂的一個值,並丟棄。 
  26. */
  27. void pop(void);  
  28. /* 
  29. ** 函式原型:top 
  30. ** 返回堆疊頂部元素的值,但不改變堆疊結構。 
  31. */
  32. STACK_TYPE top(void);  
  33. /* 
  34. ** 函式原型:is_empty 
  35. ** 如果堆疊為空,返回TRUE,否則返回FALSE。 
  36. */
  37. int is_empty(void);  
  38. /* 
  39. ** 函式原型:is_full 
  40. ** 如果堆疊為滿,返回TRUE,否則返回FALSE。 
  41. */
  42. int is_full(void);  

  一、靜態陣列堆疊

在靜態陣列堆疊中,STACK_SIZE表示堆疊所能儲存的元素的最大值,用top_element作為陣列下標來表示堆疊裡面的元素,當top_element == -1的時候表示堆疊為空;當top_element == STACK_SIZE - 1的時候表示堆疊為滿。push的時候top_element加1,top_element == 0時表示第一個堆疊元素;pop的時候top_element減1。

  a_stack.c 原始碼如下:

  1. /* 
  2. **  
  3. ** 靜態陣列實現堆疊程式 a_stack.c ,陣列長度由#define確定 
  4. */
  5. #include"stack.h"
  6. #include<assert.h>
  7. #include<stdio.h>
  8. #define STACK_SIZE 100 /* 堆疊最大容納元素數量 */
  9. /* 
  10. ** 儲存堆疊中的陣列和一個指向堆疊頂部元素的指標 
  11. */
  12. static STACK_TYPE stack[STACK_SIZE];  
  13. staticint top_element = -1;  
  14. /* push */
  15. void push(STACK_TYPE value)  
  16. {  
  17.     assert(!is_full()); /* 壓入堆疊之前先判斷是否堆疊已滿*/
  18.     top_element += 1;  
  19.     stack[top_element] = value;  
  20. }  
  21. /* pop */
  22. void pop(void)  
  23. {  
  24.     assert(!is_empty()); /* 彈出堆疊之前先判斷是否堆疊已空 */
  25.     top_element -= 1;  
  26. }  
  27. /* top */
  28. STACK_TYPE top(void)  
  29. {  
  30.     assert(!is_empty());  
  31.     return stack[top_element];  
  32. }  
  33. /* is_empty */
  34. int is_empty(void)  
  35. {  
  36.     return top_element == -1;  
  37. }  
  38. /* is_full */
  39. int is_full(void)  
  40. {  
  41.     return top_element == STACK_SIZE - 1;  
  42. }  
  43. /* 
  44. ** 定義一個print函式,用來列印堆疊裡面的元素。 
  45. */
  46. void print(void)  
  47. {  
  48.     int i;  
  49.     i = top_element;  
  50.     printf("打印出靜態陣列堆疊裡面的值: ");  
  51.     if(i == -1)  
  52.         printf("這是個空堆疊\n");  
  53.     while(i!= -1)  
  54.         printf("%d ",stack[i--]);  
  55.     printf("\n");  
  56. }  
  57. int main(void)  
  58. {  
  59.     print();  
  60.     push(10); push(9); push(7); push(6); push(5);  
  61.     push(4);  push(3); push(2); push(1); push(0);  
  62.     printf("push壓入數值後:\n");  
  63.     print();  
  64.     printf("\n");  
  65.     pop();  
  66.     pop();  
  67.     printf("經過pop彈出幾個元素後的堆疊元素:\n");  
  68.     print();  
  69.     printf("\n");  
  70.     printf("top()調用出來的值: %d\n",top());  
  71.     return 1;  
  72. }  
  結果如下圖:



  二、動態陣列堆疊

標頭檔案還是用stack.h,改動的並不是很多,增加了stack_size變數取代STACK_SIZE來儲存堆疊的長度,陣列由一個指標來代替,在全域性變數下預設為0。

  create_stack函式首先檢查堆疊是否已經建立,然後才分配所需數量的記憶體並檢查分配是否成功。destroy_stack函式首先檢查堆疊是否存在,已經釋放記憶體之後把長度和指標變數重新設定為零。is_empty 和 is_full 函式中添加了一條斷言,防止任何堆疊函式在堆疊被建立之前就被呼叫。

  d_stack.c原始碼如下: