數據結構(二)棧與隊列---棧的鏈式存儲結構和實現


(一)前提

棧的鏈式存儲結構,簡稱為鏈棧。
通常我們使用棧的順序存儲結構來存儲,棧的鏈式存儲我們了解思想即可,進行擴展
棧因為只是棧頂來做插入和刪除操作,所以比較好的方法就是將棧頂放在單鏈表頭部棧頂指針和單鏈表的頭指針合二為一

(二)鏈式存儲結構

注意:由於棧頂是在開始結點,會一直變化,我們不需要設置頭結點

(三)鏈棧的結構體

//設置鏈棧的結點
typedef struct StackNode
{
    ElemType data;    //存放棧中的數據
    struct StackNode* next;    //單鏈表的指針域
}StackNode,*LinkStackPtr;

//設置棧的結構體
typedef struct
{
    LinkStackPtr top;    //top指針,始終與頭指針保持一致
    int count;    //棧元素計數器
}LinkStack;

(四)鏈棧的代碼實現

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define STACK_INIT_SIZE 100    //定義棧的初始大小
#define STACK_INCR_SIZE 10    //定義棧的增長大小

typedef int ElemType;
typedef int Status;

//設置鏈棧的結點
typedef struct StackNode
{
    ElemType data;    //存放棧中的數據
    struct StackNode* next;    //單鏈表的指針域
}StackNode,*LinkStackPtr;

//設置棧的結構體
typedef struct
{
    LinkStackPtr top;    //top指針,始終與頭指針保持一致
    int count;    //棧元素計數器
}LinkStack;

//四個基礎操作
Status InitStack(LinkStack *s);    //初始化操作,建立一個空棧
Status ClearStack(LinkStack *s);    //將棧清空
Status StackEmpty(LinkStack s);    //若棧存在,返回true,否則返回false
int StackLength(LinkStack s);        //返回棧S的元素個數

Status GetTop(LinkStack s, ElemType *e);    //若是棧存在且非空,用e返回S的棧頂元素
Status Push(LinkStack *s, ElemType e);    // 若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Pop(LinkStack *s, ElemType *e);    //若是棧存在且非空,刪除棧頂元素,並用e返回其值
Status DestroyStack(LinkStack *s);        //若是棧存在,則銷毀他

int main()
{
    LinkStack sk;
    ElemType e;
    int i;
    //初始化空棧,用於存放()[]{}''""這幾個數據,的左半邊進行匹配
    InitStack(&sk);

    printf("2.Push 1-5\n");
    for (i = 1; i <= 5; i++)
        Push(&sk, i);
    printf("3.Pop number for three times\n");
    for (i = 1; i <= 3;i++)
    {
        Pop(&sk, &e);
        printf("Pop %d: %d\n",i, e);
    }
    GetTop(sk, &e);
    printf("4.Get Top:%d\n",e);
    printf("5.Push 6-10\n");
    for (i = 6; i <= 10; i++)
        Push(&sk, i);
    printf("6.Get stack length:%d\n", StackLength(sk));
    printf("7.Pop number for six times\n");
    for (i = 1; i <= 6; i++)
    {
        Pop(&sk, &e);
        printf("Pop %d: %d\n",i, e);
    }
    if (!StackEmpty(sk))
    {
        printf("8.Stack is not Empty\n");
        ClearStack(&sk);
        printf("9.Stack is Clear\n");
    }
    printf("10.Stack Empty:%d\n",StackEmpty(sk));
    printf("11.destroy Stack");
    DestroyStack(&sk);
    system("pause");
    return 0;
}

//初始化操作,建立一個空棧
Status InitStack(LinkStack *s)
{
    if (!s)
        return ERROR;
    s->count = 0;
    s->top = NULL;
    return OK;
}

//將棧清空,循環釋放掉棧中的結點
Status ClearStack(LinkStack *s)
{
    LinkStackPtr p, q;    //結點指針
    if (s == NULL)
        return ERROR;
    p = s->top;
    while (p)
    {
        q = p;
        p = p->next;
        free(q);
    }
    s->count = 0;
    s->top=NULL;
    return OK;
}

//若棧存在,返回true,否則返回false
Status StackEmpty(LinkStack s)
{
    if (s.count==0)
        return TRUE;
    return FALSE;
}

//返回棧S的元素個數
int StackLength(LinkStack s)
{
    return s.count;
}

//若是棧存在且非空,用e返回S的棧頂元素,注意:只是獲取棧頂數據,不出棧
Status GetTop(LinkStack s, ElemType *e)
{
    if (!e || !s.top)
        return ERROR;
    *e = s.top->data;
    return OK;
}

//入棧操作:若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Push(LinkStack *s, ElemType e)
{
    if (!s)
        return ERROR;
    LinkStackPtr ns = (LinkStackPtr)malloc(sizeof(StackNode));    //生成一個結點去存放數據
    ns->data = e;
    ns->next = s->top;
    s->top = ns;
    s->count++;
    return OK;
}

//若是棧存在且非空,刪除棧頂元素(只需要將棧頂指針下移即可),並用e返回其值
Status Pop(LinkStack *s, ElemType *e)
{
    LinkStackPtr p;
    if (!s || !e||StackEmpty(*s))
        return ERROR;
    p = s->top;
    s->top = p->next;
    *e = p->data;
    free(p);
    s->count--;
    return OK;
}

//若是棧存在,則銷毀他(直接將棧底指針釋放即可,置為空)
Status DestroyStack(LinkStack *s)
{
    if (!StackEmpty(*s))    //若是棧存在
        ClearStack(s);
    return OK;
}

(五)總結:和順序棧之間的對比

對於順序棧和鏈棧,其進棧和出棧的時間復雜度都是O(1).
對於空間性能,順序棧需要事先確定一個固定長度(雖然后面可以擴展),若是這個初始長度過大,可能造成內存空間的浪費。但是他的優勢是存取時定位較方便。
而鏈棧則需要每個元素都有指針域,這樣同時也增加了一些內存開銷,但是對於棧的長度無限制。

使用情況選擇

如果棧的使用過程中元素變化不可預料,有時小,有時大變化頻繁,那么最好是使用鏈棧。
若是他的變化在可控范圍內,建議使用順序棧。 注:雖然我們實現順序棧可以擴展空間,但是當擴展后的空間無法被充分利用時,會造成空間浪費

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM