基本資料結構 -- 棧詳解

來源:互聯網
上載者:User

標籤:i++   動態   動態棧   free   pen   時間   容量   技術分享   因此   

  棧是一種後進先出的線性表,是最基本的一種資料結構,在許多地方都有應用。 

一、什麼是棧

  棧是限制插入和刪除只能在一個位置上進行的線性表。其中,允許插入和刪除的一端位於表的末端,叫做棧頂(top),不允許插入和刪除的另一端叫做棧底(bottom)。對棧的基本操作有 PUSH(壓棧)POP (出棧),前者相當於表的插入操作(向棧頂插入一個元素),後者則是刪除操作(刪除一個棧頂元素)。棧是一種後進先出(LIFO)的資料結構,最先被刪除的是最近壓棧的元素。棧就像是一個箱子,往裡面放入一個小盒子就相當於壓棧操作,往裡面取出一個小盒子就是出棧操作,取盒子的時候,最後放進去的盒子會最先被取出來,最先放進去的盒子會最後被取出來,這即是後入先出。下面是一個棧的:

 

  

 

二、棧的實現

  由於棧是一個表,因此任何實現表的方法都可以用來實現棧。主要有兩種方式,鏈表實現和數組實現。

2.1 棧的鏈表實現

  可以使用單鏈表來實現棧。通過在表頂端插入一個元素來實現 PUSH,通過刪除表頂端元素來實現 POP。使用鏈表方式實現的棧又叫動態棧。動態棧有鏈表的部分特性,即元素與元素之間在實體儲存體上可以不連續,但是功能有些受限制,動態棧只能在棧頂處進行插入和刪除操作,不能在棧尾或棧中間進行插入和刪除操作。

  棧的鏈表實現代碼如下,編譯環境是 win10,vs2015:

#include "stdio.h"#include "stdlib.h"#include "string.h"#include "windows.h"struct stack_node {    int data;    struct stack_node *next;};typedef struct stack_node *PtrToNode;typedef PtrToNode Stack;Stack create_stack();void push_stack(Stack s, int data);void pop_stack(Stack s);int top_stack(Stack s);int stack_is_empty(Stack s);int main() {    Stack stack = create_stack();        // 建立一個空棧    int top_data,i;    // 壓棧操作,執行10次    for (i = 0;i < 10;i++) {        push_stack(stack, i);    }    // 出棧操作,執行1次    pop_stack(stack);    // 返回棧頂元素的值    top_data = top_stack(stack);    printf("%d\n", top_data);    system("pause");}/* 建立一個空棧 */Stack create_stack(){    Stack S;    S = (Stack)malloc(sizeof(struct stack_node));    if (S == NULL)        printf("malloc fair!\n");    S->next = NULL;    return S;}/* PUSH 操作 */void push_stack(Stack s,int data) {    // 建立一個結點,用於存放壓入棧內的元素,即新的棧頂    PtrToNode head_node = (PtrToNode)malloc(sizeof(struct stack_node));    if (head_node == NULL)        printf("malloc fair!\n");    head_node->data = data;            // 添加資料    head_node->next = s->next;        // 新的棧頂 head_node 的 next 指標指向原來的棧頂 s->next    s->next = head_node;            // s->next 現在指向新的棧頂}/* POP 操作 */void pop_stack(Stack s) {    PtrToNode head_node = (PtrToNode)malloc(sizeof(struct stack_node));    if (head_node == NULL)        printf("malloc fair!\n");    // 先判斷棧是否為空白,若棧為空白,則不能再進行出棧操作,報錯    if (stack_is_empty(s)) {        printf("Error! Stack is empty!\n");    }    else {        head_node = s->next;            // head_node 為棧頂        s->next = head_node->next;        // s->next 指向 head_node->next ,即新的棧頂        free(head_node);                // 釋放原來棧頂元素所佔的記憶體    }}/* 查看棧頂元素 */int top_stack(Stack s) {    if (stack_is_empty(s)) {        printf("Error! Stack is empty!\n");        return 0;    }    else {        return s->next->data;    }}/* 判斷棧是否為空白 */int stack_is_empty(Stack s) {    return s->next == NULL;}
View Code

   該程式將數字 1-9 分別壓棧,然後執行一次出棧操作,最後列印棧頂元素,結果為8。

 

2.2 棧的數組實現

  同樣,棧也可以用數組來實現。使用數組方式實現的棧叫靜態棧

  用數組實現棧很簡單,每個棧都有一個 TopOfStack,用來表示棧頂在數組中的下標,對於空棧,該值為 -1(這就是空棧的初始化)。當需要壓棧時,只需要將 TopOfStack 加 1,然後將數組中該下標處的值置為壓入棧的值即可;出棧操作更簡單,只需要將 TopOfStack 減 1 即可。需要注意的是,對空棧的 POP 操作和對滿棧的 PUSH 操作都會產生數組越界並引起程式崩潰。

  棧的數組實現方法如下,編譯環境是 win10,vs2015:

#include "stdio.h"#include "stdlib.h"#include "string.h"#include "windows.h"#define MinStackSize 5#define EmptyTOS -1struct stack_array {    int capacity;            // 棧的容量    int top_of_stack;        // 棧頂的下標    int *array;                // 用於存放棧的數組};typedef struct stack_array *ArrayRecord;typedef ArrayRecord Stack;Stack create_stack(int stack_capacity);void make_empty(Stack s);void push_stack(Stack s, int data);int top_stack(Stack s);void pop_stack(Stack s);int stack_is_empty(Stack s);int stack_is_full(Stack s);int main(){    Stack stack = create_stack(100);    int topdata, i;    for (i = 0;i < 10;i++) {        push_stack(stack, i);    }    pop_stack(stack);    pop_stack(stack);    topdata = top_stack(stack);    printf("%d\n", topdata);    system("pause");}/* 建立一個棧 */Stack create_stack(int stack_capacity){    Stack S;    if (stack_capacity < MinStackSize)        printf("Error! Stack size is too small!\n");    S = (Stack)malloc(sizeof(struct stack_array));    if (S == NULL)        printf("malloc error!\n");    S->array = (int *)malloc(sizeof(struct stack_array) * stack_capacity);    if (S->array == NULL)        printf("malloc error!\n");    S->capacity = stack_capacity;    make_empty(S);    return S;}/* 建立一個空棧 */void make_empty(Stack s){    // 棧頂的下標為 -1 表示棧為空白    s->top_of_stack = EmptyTOS;}/* PUSH 操作 */void push_stack(Stack s, int data){    if (stack_is_full(s)) {        printf("Error! Stack is full!\n");    }    else {        s->top_of_stack++;        s->array[s->top_of_stack] = data;    }}/* POP 操作 */void pop_stack(Stack s){    if (stack_is_empty(s)) {        printf("Error! Stack is empty!\n");    }    else {        s->top_of_stack--;    }}/* 返回棧頂元素 */int top_stack(Stack s){    if (stack_is_empty(s)) {        printf("Error! Stack is empty!\n");        return 0;    }    else {        return s->array[s->top_of_stack];    }}/* 檢測棧是否為空白棧 */int stack_is_empty(Stack s){        // 棧頂的下標為 -1 表示棧為空白    return s->top_of_stack == EmptyTOS;}/* 檢測棧是否為滿棧 */int stack_is_full(Stack s){    // 棧頂的下標為 capacity - 1 表示棧滿了(數組下標從 0 開始)    return s->top_of_stack == --s->capacity;}
View Code

  該程式將數字 1-9 分別壓棧,然後執行兩次出棧操作,最後列印棧頂元素,結果為7。

 

2.3 棧的鏈表實現和數組實現的優缺點

  使用鏈表來實現棧,記憶體動態分配,可以不必擔心記憶體配置的問題,但是 malloc 和 free 的調用開銷會比較大。

  使用數組實現的棧,需要提前聲明一個數組的大小,如果數組大小不夠,則可能會發生數組越界,如果數組太大,則會浪費一定的空間。一般而言,會給數組聲明一個足夠大而不至於浪費太多空間的大小。除了這個問題,用數組實現的棧執行效率會比用鏈表來實現的高。

  這兩種實現方式中,棧的操作如 PUSH、POP 均是以常數時間啟動並執行,執行速度很快,因此,棧的執行效率通常很高。

 

三、棧的應用

  棧的應用十分廣泛 ,在函數調用、中斷處理、運算式求值、記憶體配置等操作中都需要用到棧。本文接下來描述一下棧在函數調用中的應用:

  假設有一個函數 f(),現在函數 f() 要調用函數 g() ,而函數 g() 又需要調用函數 h() 。當函數 f() 開始調用函數 g() 時,函數 f() 的所有局部變數需要由系統儲存起來,否則被調用的新函數 g() 將會覆蓋調用函數 f() 的變數;不僅如此,主調函數當前的位置也是需要儲存的,以便被調函數執行完後知道回到哪裡接著執行調用函數。同樣的,函數 g() 調用函數 h() 時,g() 的相關資訊也需要儲存起來。在函數 h() 執行完成後,再從系統中取出函數 g()  的相關資訊接著執行函數 g();當函數 g() 執行完成後,從系統中取出函數 f() 的相關資訊然後接著執行函數 f()。從這裡的描述中可以看到,函數調用時,調用函數的資訊是存放在一個後進先出結構中的,顯然,用棧來存放再好不過,用一幅圖示範一下:

 

 

 

參考資料:

《演算法導論 第三版》

《資料結構與演算法分析--C語言描述》

基本資料結構 -- 棧詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.