簡單數據結構之棧

——引子

棧是系統軟件必不可少的數據結構,其應用十分的廣泛,例如:儲存管理、函數調用以及表達式求值等,都離不開棧這個數據結構。

另外,深度優先搜索算法也需要藉助棧來完成。

那麼,棧到底是一種怎樣的結構呢?

棧的特點

棧其實也是線性表中的一種,不過,它是作爲線性表中比較特例的存在。

這種結構,只允許在棧的一端進行操作,這個位置,也被稱爲棧頂!

對於棧的一切操作,例如增、刪、查等,都只能在棧頂進行,對於棧其他位置的元素,沒有影響。

所以,這也就造成了棧最大的特點:後進先出!

對於棧的理解

對於棧,我們可以將其想象成一個瓶子,而元素,就是瓶子中的水,瓶口就相當於是棧頂,瓶底相當於棧底。

當一個元素進入棧時,就像水一樣,直接進入瓶子的最底層,而想要倒水出來,那最先出來的只能是上層的水。

所以,將棧這個結構,當作一個水瓶,是在好不過的了~

還有,關於棧元素的出棧順序,利用的就是我們的卡特蘭數,對於卡特蘭數,在這裏我就不做過多的解釋,想要了解的小夥伴們,可以自己找找相關的書籍~

在爲大家大概的講明棧的邏輯意義之後,就是我們的重頭戲了,下面就讓我們一起,看看棧結構,到底是如何實現的~

棧的實現

既然棧也是一種特別的線性表,那麼在之前的瞭解之中,我們已經知道,線性表分爲兩種,一種是順序的,一種是鏈式的。

那麼,既然棧作爲一個線性表,那肯定也有兩種實現的形式,接下來,就讓我們一起看看,這兩種形式的棧,有何不同之處!

順序棧

使用順序存儲的方式實現棧結構與實現順序表的結構類似,不同的是,對於棧內元素的操作,我們只能從棧頂進行。

由於順序表中,在尾部插入和刪除元素比較容易,所以,在下面的代碼中,我們將表的尾部當作棧頂,具體實現如下:

類型定義
typedef int data;

typedef struct{
    int top;
    int capacity;
    data * array;
}stack;
//這裏利用typedef關鍵字,可以將代碼的可重用性提高一點,想要轉變數據類型時,直接改變就行,數據類型可以時結構體!
初始化
stack * init_stack(stack * p, int d){
    p->top = 0;
    p->capacity = d?d:8;
    p->array = (data *)malloc(sizeof(data) * p->capacity);
    return p;
}//初始化棧
銷燬
void destory_stack(stack * p){
    free(p->array);
}//銷燬棧
判斷棧是否爲空
_Bool isEmpty_stack(stack * p){
    return p->top == 0;
}//判斷棧是否爲空
擴展空間
stack * extend_stack(stack * p){
    int i = 0;
    data * new_array = (data *)malloc(sizeof(data) * p->capacity * 2);
    for(i = 0; i < p->top; i++){
        new_array[i] = p->array[i];
    }
    free(p->array);
    p->array = new_array;
    return p;
}//空間擴展
入棧
stack * push_stack(stack * p, data d){
    if(p->top == p->capacity){
        extend_stack(p);
    }
    p->array[p->top++] = d;
    return p;
}//入棧
彈棧
stack * pop_stack(stack * p){
    if(p->top == 0){
        return (void *)0;
    }
    p->top--;
    return p;
}//彈棧
讀取棧頂元素
stack * read_stack(stack * p, data * da){
    if(p->top == 0){
        return (void *)0;
    }
    * da = p->array[p->top - 1];
    return p;
}//讀取棧頂元素
測試數據
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    stack s;
    init_stack(&s,4);
    if(isEmpty_stack(&s)){
        printf("棧爲空!\n");
    }
    printf("開始入棧操作:1,2,3,4,5\n");
    push_stack(&s,1);
    push_stack(&s,2);
    push_stack(&s,3);
    push_stack(&s,4);
    push_stack(&s,5);
    printf("入棧操作完成!\n");
    while(!isEmpty_stack(&s)){
        data d;
        read_stack(&s,&d);
        printf("此時棧頂元素是:%d\n",d);
        printf("彈棧操作執行!\n");
        pop_stack(&s);
    }
    if(isEmpty_stack(&s)){
        printf("棧爲空!\n");
    }
    destory_stack(&s);
    return 0;
}
結果

在這裏插入圖片描述

鏈式棧

使用鏈式存儲的方式實現棧,由於鏈表的頭插和頭刪比較快,所以我們將鏈表的表頭當作是棧頂,具體實現如下:

在這裏插入代碼片

類型定義
typedef int Data;

typedef struct N{
    Data data;
    struct N * next;
}Node;

typedef struct{
    Node * top;
    int size;
}Link_stack;
//這裏將數據域類型起別名的原因和上面的順序棧相同,都是爲了代碼可重用!
創建節點
Node * make_node(Data d){
    Node * new_node = (Node *) malloc(sizeof(Data));
    new_node->data = d;
    new_node->next = (void *)0;
    return new_node;
}//創建節點
初始化
Link_stack * init_stack(Link_stack * p){
    p->size = 0;
    p->top = (void *)0;
    return p;
}//初始化
銷燬
void destory_stack(Link_stack * p){
    while(p->top){
        Node * del = p->top;
        p->top = p->top->next;
        free(del);
    }

}//銷燬棧
判斷棧是否爲空
_Bool isEmpty_stack(Link_stack * p){
    return p->top == (void *)0;
}//判斷棧是否爲空
入棧
Link_stack * push_stack(Link_stack * p, Data d){
    Node * new_node = make_node(d);
    if(!new_node){
        return (void *)0;
    }
    new_node->next = p->top;
    p->top = new_node;
    p->size++;
    return p;
}//入棧
彈棧
Link_stack * pop_stack(Link_stack * p){
    if(p->size == 0){
        return (void *)0;
    }
    Node * del = p->top;
    p->top = p->top->next;
    free(del);
    p->size--;
    return p;
}//彈棧
讀取棧頂元素
Link_stack * read_stack(Link_stack * p, Data * d){
    if(p->size == 0){
        return (void *)0;
    }
    *d = p->top->data;
    return p;
}//讀取棧頂元素
測試數據
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    int a[5] = {1,2,3,4,5};
    int i = 0;
    Link_stack s;
    init_stack(&s);
    if((&s)->size == 0){
        printf("棧創建成功!\n");
    }
    printf("需要入棧的元素有:1,2,3,4,5\n");
    for(i = 0; i < 5; i++){
        printf("此時入棧的元素是:%d\n",a[i]);
        push_stack(&s,a[i]);
        if(!isEmpty_stack(&s)){
            printf("入棧成功!\n");
        }
    }
    while((&s)->top){
        Data d;
        printf("此時棧頂元素是:");
        read_stack(&s,&d);
        printf("%d\n",d);
        Link_stack * x = pop_stack(&s);
        if(x != (void *)0){
            printf("彈棧成功!\n");
        }
    }
    destory_stack(&s);
    return 0;
}
結果

在這裏插入圖片描述

總結

這次給大家帶來的就是這麼多了,下一次窩瓜將給大家帶來隊列的簡單實現~

發佈了11 篇原創文章 · 獲贊 0 · 訪問量 7060
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章