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

來源:互聯網
上載者:User

  基本的抽象資料類型(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];static int 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原始碼如下:

/*** 動態分配數組實現的堆棧程式 d_stack.c** 堆棧的長度在建立堆棧的函數被調用時候給出,該函數必須在任何其他動作堆棧的函數被調用之前條用。*/#include"stack.h"#include<stdio.h>#include<malloc.h>#include<assert.h>/*** 用於儲存堆棧元素的數組和指向堆棧頂部元素的指標*/static STACK_TYPE *stack;static int    stack_size;static int  top_element = -1;/* create_stack */void create_stack(size_t size){assert(stack_size == 0);stack_size = size;stack = (STACK_TYPE *)malloc(stack_size * sizeof(STACK_TYPE));if(stack == NULL)perror("malloc分配失敗");}/* destroy */void destroy_stack(void){assert(stack_size > 0);stack_size = 0;free(stack);stack = NULL;}/* 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){assert(stack_size > 0);return top_element == -1;}/* is_full */int is_full(void){assert(stack_size > 0);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){create_stack(50);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());destroy_stack();return 1;}

  結果如:

  三、鏈式堆棧

  由於只有堆棧頂部元素才可以被訪問,因此適用單鏈表可以很好實現鏈式堆棧,而且無長度限制。把一個元素壓入堆棧是通過在鏈表頭部添加一個元素實現。彈出一個元素是通過刪除鏈表頭部第一個元素實現。由於沒有長度限制,故不需要create_stack函數,需要destroy_stack進行釋放記憶體以避免記憶體流失。

  標頭檔stack.h 不變,l_stack.c 原始碼如下:

/*** 單鏈表實現堆棧,沒有長度限制*/#include"stack.h"#include<stdio.h>#include<malloc.h>#include<assert.h>#define FALSE 0/*** 定義一個結構以儲存堆棧元素。*/typedef struct STACK_NODE{STACK_TYPE value;struct STACK_NODE *next;} StackNode;/* 指向堆棧中第一個節點的指標 */static StackNode *stack;/* create_stack */void create_stack(size_t size){}/* destroy_stack */void destroy_stack(void){while(!is_empty())pop();/* 逐個彈出元素,逐個釋放節點記憶體 */}/* push */void push(STACK_TYPE value){StackNode *new_node;new_node = (StackNode *)malloc(sizeof(StackNode));if(new_node == NULL)perror("malloc fail");new_node->value = value;new_node->next = stack;/* 新元素插入鏈表頭部 */stack = new_node;/* stack 重新指向鏈表頭部 */}/* pop */void pop(void){StackNode *first_node;assert(!is_empty());first_node = stack;stack = first_node->next;free(first_node);}/* top */STACK_TYPE top(void){assert(!is_empty());return stack->value;}/* is_empty */int is_empty(void){return stack == NULL;}/* is_full */int is_full(void){return FALSE;}/*** 定義一個print函數,用來列印堆棧裡面的元素。*/void print(void){StackNode *p_node;p_node = stack;printf("列印出鏈式堆棧裡面的值: ");if(p_node == NULL)printf("堆棧為空白\n");while(p_node != NULL){printf("%d ", p_node->value);p_node = p_node->next;}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());destroy_stack();return 1;}

  結果如:

註:本文部分程式參考《C與指標》這本書

原創文章,歡迎轉載,轉載請註明:blog.csdn.net/jjzhoujun2010

作者:Dream Fly

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.