數據結構(8)棧結構之鏈棧

前言

前面說過,棧的本質是操作受限的線性表,也就是說,當我們在實現鏈棧時,其實需要實現的是一個鏈表,只是相比一般的鏈表少了許多操作而已。既然它本質是鏈表,我們在設計結構的時候,就需要考慮是否設置頭結點的問題,假如不設頭結點,那麼頭指針指向的位置就是棧頂;假如設了頭結點,那麼頭指針的next指針指向的結點(即首元結點)就是棧頂。本次採用的是無頭結點的結構。

在這裏插入圖片描述

鏈棧的指針指向問題

鏈式存儲離不開對地址的控制,因此想要掌握好鏈棧,需要對涉及的指針很瞭解。在鏈棧中(鏈表中也是一樣),一般涉及到二重指針,如圖所示。

在這裏插入圖片描述

C語言中有形參和實參的區別,假如我們想在函數裏真正改變某個參數的值,就要傳入該參數的地址。同理,假如想在函數中修改某個結點的值,那麼就不能僅僅傳入(StackNode)這個類型的值,而是需要傳入這個值的地址(StackNode *)。假如在函數中想修改這個地址(StackNode *),那麼就要再傳入這個地址的地址,它是(StackNode **)類型的。

在鏈表中只需要一個頭指針就可以找到整個鏈表,當鏈表爲空時,頭指針的指向爲空,當鏈表非空時,它指向首元結點的地址。因此頭指針設置爲結點的指針類型(StackNode *),爲了方便記錄,又給(StackNode *)取名爲(LinkStack),用來表示整個鏈表。這樣,(StackNode **)又可以寫成(LinkStack *)。

鏈棧的初始化

在主函數中,我們使用(LinkStack st)生成一個鏈棧,也就是生成了一個結點類型的指針變量。但是執行完該條語句之後,st的指向是混亂的。鏈棧的初始化就是將它的指向設置爲空,表示當前是空棧。

在這裏插入圖片描述

//初始化鏈棧
void initStack(LinkStack *s){
    //將這個鏈棧初始化爲空棧
    *s = NULL;
}

這時候,因爲要修改的是頭指針的指向(也就是值),而頭指針是(LinkStack)類型的,因此需要傳入的是頭指針的地址(LInkStack *)。

鏈棧的入棧

鏈棧的入棧也就是鏈表的頭部插入操作,它的操作可以大致分成兩步:

1.申請一個結點並賦值
在這裏插入圖片描述
2.進行頭部插入

在這裏插入圖片描述

鏈棧的出棧

鏈棧的出棧,也就是鏈表的頭部刪除,它的操作大致可以分成三步:

1.獲取棧頂元素的值

2.棧頂指針指向棧頂元素的下一個結點

3.釋放掉棧頂元素

在這裏插入圖片描述

全部代碼

LinkStack.h

#ifndef LinkStack_h
#define LinkStack_h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define ElemType int

//結點的類型
typedef struct StackNode{
    ElemType data;
    struct StackNode *next;
}StackNode;

//棧的頭指針
typedef StackNode* LinkStack;

//初始化鏈棧
void initStack(LinkStack *s);
//入棧
void push(LinkStack *s,ElemType x);
//出棧
void pop(LinkStack *s);

//展示
void show(LinkStack *s);
//void show2(LinkStack s);

#endif /* LinkStack_h */

LinkStack.c

#include "LinkStack.h"

//初始化鏈棧
void initStack(LinkStack *s){
    //將這個鏈棧初始化爲空棧
    *s = NULL;
}

//入棧->本質就是鏈表的頭部插入
void push(LinkStack *s,ElemType x){
    //申請一個結點空間
    StackNode *t = (StackNode *)malloc(sizeof(StackNode));
    //如果t爲空則警告
    assert(t != NULL);
    
    //賦值
    t->data = x;
    
    //頭部插入
    t->next = *s;
    *s = t;
    
}

//出棧
void pop(LinkStack *s){
    //獲取首元結點(即棧頂元素
    StackNode *p = *s;
    
    if (p == NULL) {
        printf("棧已空\n");
        return;
    }
    
    //棧頂指針指向棧頂元素的下一個結點
    *s = p->next;
    
    //釋放掉棧頂元素
    free(p);
}


//展示
void show(LinkStack *s){
    StackNode *p = *s;
    while (p != NULL) {
        printf("%d\n",p->data);
        p = p->next;
    }
    printf("\n");
}

//void show2(LinkStack s){
//    StackNode *p = s;
//    while (p != NULL) {
//        printf("%d\n",p->data);
//        p = p->next;
//    }
//    printf("\n");
//}

main.c

#include "LinkStack.h"

int main(int argc, const char * argv[]) {
    
    LinkStack st;
    initStack(&st);
    
    for (int i = 1; i < 6; i ++) {
        push(&st, i);
    }
    show(&st);
    
    pop(&st);
    show(&st);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章