詳解堆疊的幾種實現方法——C語言版
基本的抽象資料型別(ADT)是編寫C程式必要的過程,這類ADT有連結串列、堆疊、佇列和樹等,本文主要講解下堆疊的幾種實現方法以及他們的優缺點。
堆疊(stack)的顯著特點是後進先出(Last-In First-Out, LIFO),其實現的方法有三種可選方案:靜態陣列、動態分配的陣列、動態分配的鏈式結構。
靜態陣列:特點是要求結構的長度固定,而且長度在編譯時候就得確定。其優點是結構簡單,實現起來方便而不容易出錯。而缺點就是不夠靈活以及固定長度不容易控制,適用於知道明確長度的場合。
動態陣列:特點是長度可以在執行時候才確定以及可以更改原來陣列的長度。優點是靈活,缺點是由此會增加程式的複雜性。
鏈式結構:特點是無長度上線,需要的時候再申請分配記憶體空間,可最大程度上實現靈活性。缺點是鏈式結構的連結欄位需要消耗一定的記憶體,在鏈式結構中訪問一個特定元素的效率不如陣列。
首先先確定一個堆疊介面的標頭檔案,裡面包含了各個方案下的函式原型,放在一起是為了實現程式的模組化以及便於修改。然後再接著分別介紹各個方案的具體實施方法。
堆疊介面stack.h檔案程式碼:
- /*
- ** 堆疊模組的介面 stack.h
- */
- #include<stdlib.h>
-
#define STACK_TYPE int /* 堆疊所儲存的值的資料型別 */
- /*
- ** 函式原型:create_stack
- ** 建立堆疊,引數指定堆疊可以儲存多少個元素。
- ** 注意:此函式只適用於動態分配陣列形式的堆疊。
- */
- void create_stack(size_t size);
- /*
- ** 函式原型:destroy_stack
- ** 銷燬一個堆疊,釋放堆疊所適用的記憶體。
- ** 注意:此函式只適用於動態分配陣列和鏈式結構的堆疊。
- */
- void destroy_stack(void);
- /*
- ** 函式原型:push
- ** 將一個新值壓入堆疊中,引數是被壓入的值。
- */
-
void push(STACK_TYPE value);
- /*
- ** 函式原型:pop
- ** 彈出堆疊中棧頂的一個值,並丟棄。
- */
- void pop(void);
- /*
- ** 函式原型:top
- ** 返回堆疊頂部元素的值,但不改變堆疊結構。
- */
- STACK_TYPE top(void);
- /*
- ** 函式原型:is_empty
- ** 如果堆疊為空,返回TRUE,否則返回FALSE。
- */
- int is_empty(void);
- /*
- ** 函式原型:is_full
- ** 如果堆疊為滿,返回TRUE,否則返回FALSE。
- */
- 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 原始碼如下:
- /*
- **
- ** 靜態陣列實現堆疊程式 a_stack.c ,陣列長度由#define確定
- */
- #include"stack.h"
- #include<assert.h>
- #include<stdio.h>
- #define STACK_SIZE 100 /* 堆疊最大容納元素數量 */
- /*
- ** 儲存堆疊中的陣列和一個指向堆疊頂部元素的指標
- */
- static STACK_TYPE stack[STACK_SIZE];
- staticint top_element = -1;
- /* push */
- void push(STACK_TYPE value)
- {
- assert(!is_full()); /* 壓入堆疊之前先判斷是否堆疊已滿*/
- top_element += 1;
- stack[top_element] = value;
- }
- /* pop */
- void pop(void)
- {
- assert(!is_empty()); /* 彈出堆疊之前先判斷是否堆疊已空 */
- top_element -= 1;
- }
- /* top */
- STACK_TYPE top(void)
- {
- assert(!is_empty());
- return stack[top_element];
- }
- /* is_empty */
- int is_empty(void)
- {
- return top_element == -1;
- }
- /* is_full */
- int is_full(void)
- {
- return top_element == STACK_SIZE - 1;
- }
- /*
- ** 定義一個print函式,用來列印堆疊裡面的元素。
- */
- void print(void)
- {
- int i;
- i = top_element;
- printf("打印出靜態陣列堆疊裡面的值: ");
- if(i == -1)
- printf("這是個空堆疊\n");
- while(i!= -1)
- printf("%d ",stack[i--]);
- printf("\n");
- }
- int main(void)
- {
- print();
- push(10); push(9); push(7); push(6); push(5);
- push(4); push(3); push(2); push(1); push(0);
- printf("push壓入數值後:\n");
- print();
- printf("\n");
- pop();
- pop();
- printf("經過pop彈出幾個元素後的堆疊元素:\n");
- print();
- printf("\n");
- printf("top()調用出來的值: %d\n",top());
- return 1;
- }
二、動態陣列堆疊
標頭檔案還是用stack.h,改動的並不是很多,增加了stack_size變數取代STACK_SIZE來儲存堆疊的長度,陣列由一個指標來代替,在全域性變數下預設為0。
create_stack函式首先檢查堆疊是否已經建立,然後才分配所需數量的記憶體並檢查分配是否成功。destroy_stack函式首先檢查堆疊是否存在,已經釋放記憶體之後把長度和指標變數重新設定為零。is_empty 和 is_full 函式中添加了一條斷言,防止任何堆疊函式在堆疊被建立之前就被呼叫。
d_stack.c原始碼如下: