「數(shù)據(jù)結(jié)構(gòu) 四」C 語言實(shí)現(xiàn)棧

棧(stack)是限定在表尾進(jìn)行插入或刪除操作的線性表。因此,棧的表尾端具有特殊的含義,稱為棧頂(top),相對(duì)應(yīng),表頭端的稱為棧底(bottom)。

為什么稱之為特殊的線性表,它的特殊之處在于只能允許在棧的頂端加入數(shù)據(jù)(push)和輸出數(shù)據(jù)(pop)。由于它是特殊的線性表,所以我們可以實(shí)現(xiàn)順序結(jié)構(gòu)的棧和鏈?zhǔn)浇Y(jié)構(gòu)的棧。

順序棧

順序棧是指利用順序存儲(chǔ)結(jié)構(gòu)實(shí)現(xiàn)的棧,即利用一組地址連續(xù)的存儲(chǔ)單元一次存放自棧底到棧頂?shù)臄?shù)據(jù)元素,同時(shí)設(shè)置 top 指針指向棧頂元素。

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

#define STACK_INIT_SIZE 100
#define STACK_INCREMENT 2

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE 0

typedef int Status;
typedef int SElemType;

typedef struct {
    SElemType *base;  //棧底指針
    SElemType *top;  //棧頂指針
    int stackSize;
}SqStack;

Status InitStack(SqStack *S);
Status DestroyStack(SqStack *S);
Status ClearStack(SqStack *S);
Status StackEmpty(SqStack S);
int StackLength(SqStack S);
Status GetTop(SqStack S, SElemType *e);
Status Push(SqStack *S, SElemType e);
Status Pop(SqStack *S, SElemType *e);
Status StackTraverse(SqStack S, void(*vi)(SElemType));

/**
 * 操作結(jié)果:構(gòu)造一個(gè)空棧 S。
 * @param S
 * @return
 */
Status InitStack(SqStack *S) {
    S->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SqStack));  //開辟內(nèi)存空間
    if (!S->base) {
        exit(OVERFLOW);  //開辟失敗
    }
    S->top = S->base;
    S->stackSize = STACK_INIT_SIZE;
    return OK;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:棧 S 被銷毀
 * @param S
 * @return
 */
Status DestroyStack(SqStack *S) {
    if (S->base) {
        free(S->base);  //釋放棧底指針內(nèi)存空間
    }
    S->top = S->base = NULL;  //棧底棧頂指針置為 NULL
    S->stackSize = 0;
    return OK;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:將棧 S 清為空棧
 * @param S
 * @return
 */
Status ClearStack(SqStack *S) {
    S->top = S->base;
    return OK;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:若 S 為空棧,返回 true,否則返回 false
 * @param S
 * @return
 */
Status StackEmpty(SqStack S) {
    if (S.top == S.base) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:返回 S 中元素的個(gè)數(shù),即棧的長(zhǎng)度
 * @param S
 * @return
 */
int StackLength(SqStack S) {
    return (int) (S.top - S.base);
}

/**
 * 初始條件:棧 S 存在且非空
 * 操作結(jié)果:返回棧頂元素,不修改棧頂指針
 * @param S
 * @return
 */
Status GetTop(SqStack S, SElemType *e) {
    if (S.top != S.base) {
        *e = *(S.top - 1);
        return OK;
    }
    return ERROR;

}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:插入元素 e 為新的棧頂元素
 * @param S
 * @param e
 * @return
 */
Status Push(SqStack *S, SElemType e) {
    if ((S->top - S->base) >= S->stackSize) { //判讀棧是否滿
        S->base = (SElemType *)realloc(S->base, (S->stackSize + STACK_INCREMENT) * sizeof(SqStack));
        if (!S->base) {
            return ERROR;
        }
        S->top = S->base + S->stackSize;
        S->stackSize += STACK_INCREMENT;
    }
    *S->top++ = e;
    return OK;
}

/**
 * 初始條件:棧 S 存在且非空
 * 操作結(jié)果:刪除 S 的棧頂元素,并用 e 返回其值
 * @param S
 * @param e
 * @return
 */
Status Pop(SqStack *S, SElemType *e) {
    if (S->top == S->base) {  //棧為空
        return ERROR;
    }
    *e = *--S->top;
    return OK;
}

/**
 * 初始條件:棧 S 存在且非空
 * 操作結(jié)果:從棧底到棧頂依次對(duì) S 的每個(gè)元素進(jìn)行訪問
 * @param S
 * @param vi
 */
Status StackTraverse(SqStack S, void(*vi)(SElemType)) {
    while (S.top > S.base) {  //遍歷棧中元素
        vi(*S.base++);
    }
    printf("\n");
    return OK;
}

/**
 * 遍歷函數(shù)
 * @param e
 */
void vi(SElemType e) {
    printf("%d ", e);
}

/**
 * 主函數(shù),測(cè)試程序
 * @return
 */
int main() {
    SqStack s;
    SElemType e;

    InitStack(&s);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    printf("棧是否為空:%d\n", StackEmpty(s));
    Push(&s, 3);
    Push(&s, 4);
    Push(&s, 5);
    Push(&s, 6);
    StackTraverse(s,vi);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    printf("棧是否為空:%d\n", StackEmpty(s));
    GetTop(s, &e);
    printf("棧頂元素:%d\n", e);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    Pop(&s, &e);
    StackTraverse(s, vi);
    ClearStack(&s);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    printf("棧是否為空:%d\n", StackEmpty(s));

    DestroyStack(&s);
}

上面測(cè)試代碼在 Clion 下的執(zhí)行結(jié)果如下圖所示。

鏈?zhǔn)綏?/h2>

鏈棧是采用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)現(xiàn)的棧。

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

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE 0

typedef int Status;
typedef int SElemType;

typedef struct StackNode {
    SElemType data;  //數(shù)據(jù)域
    struct StackNode *next;  //指針域
}StackNode, *LinkStack;

Status InitStack(LinkStack *S);
Status DestroyStack(LinkStack *S);
Status ClearStack(LinkStack *S);
Status StackEmpty(LinkStack S);
int StackLength(LinkStack S);
Status GetTop(LinkStack S, SElemType *e);
Status Push(LinkStack *S, SElemType e);
Status Pop(LinkStack *S, SElemType *e);
void StackTraverse(LinkStack S, void(*vi)(SElemType));

/**
 * 操作結(jié)果:構(gòu)造一個(gè)空棧 S
 * @param L
 * @return
 */
Status InitStack(LinkStack *S) {
    S = NULL;  //構(gòu)造一個(gè)空棧,棧頂指針置空
    return OK;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:棧 S 被銷毀
 * @param S
 * @return
 */
Status DestroyStack(LinkStack *S) {
    LinkStack p;
    while (*S) {  //未到棧底
        p = (*S)->next;
        free(*S);  //釋放棧頂空間
        *S = p;
    }
    return OK;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:將棧 S 清空
 * @param S
 */
Status ClearStack(LinkStack *S) {
    LinkStack q, p = (*S)->next;  // p 指向棧頂元素
    while (p) {  //未到棧底
        q = p->next;
        free(p);
        p = q;
    }
    (*S) = NULL;
    return OK;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:若 S 是空棧,返回 true,否則返回 false
 * @param S
 * @return
 */
Status StackEmpty(LinkStack S) {
    if (S == NULL) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:返回棧 S 長(zhǎng)度
 * @param S
 * @return
 */
int StackLength(LinkStack S) {
    int i = 0;  //計(jì)數(shù)器
    LinkStack p = S;  //p指向棧頂元素
    while (p) {  //未到棧底
        i++;
        p = p->next;
    }
    return i;
}

/**
 * 初始條件:棧 S 存在且非空
 * 操作結(jié)果;用 e 返回棧 S 的棧頂元素,不修改棧頂指針
 * @param S
 * @return
 */
Status GetTop(LinkStack S, SElemType *e) {
    if (S) {  //S 非空
        *e = S->data;
        return OK;
    }
    return ERROR;
}

/**
 * 初始條件:棧 S 存在
 * 操作結(jié)果:插入元素 e 為新的棧頂元素
 * @param L
 * @param e
 * @return
 */
Status Push(LinkStack *S, SElemType e) {
    LinkStack p;
    p = (LinkStack)malloc(sizeof(struct StackNode));  //生成新結(jié)點(diǎn)
    p->data = e;
    p->next = *S;  //將新結(jié)點(diǎn)插入棧頂
    *S = p;  //修改棧頂指針
    return OK;
}

/**
 * 初始條件:棧 S 存在且非空
 * 操作結(jié)果:刪除棧頂元素,并用 e 返回且值
 * @param S
 * @param e
 * @return
 */
Status Pop(LinkStack *S, SElemType *e) {
    LinkStack p;
    if (!S) {
        return ERROR;
    }
    *e = (*S)->data;  //返回棧頂元素
    p = *S;  //p 臨時(shí)保存棧頂空間,以備釋放
    *S = (*S)->next;  //修改棧頂指針
    free(p);  //釋放原棧棧頂空間
    return OK;
}

/**
 * 初始條件:棧 S 存在且非空
 * 操作結(jié)果:從棧底到棧頂依次對(duì) S 中的每個(gè)元素進(jìn)行訪問
 * @param S
 * @param vi
 */
void StackTraverse(LinkStack S, void(*vi)(SElemType)) {
    LinkStack p = S;  //p 指向棧頂
    while (p) {
        vi(p->data);
        p = p->next;
    }
    printf("\n");
}

void vi(SElemType e) {
    printf("%d ", e);
}

/**
 * 主函數(shù),測(cè)試程序
 * @return
 */
int main() {
    LinkStack s = NULL;
    SElemType e;

    InitStack(&s);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    printf("棧是否為空:%d\n", StackEmpty(s));
    Push(&s, 3);
    Push(&s, 4);
    Push(&s, 5);
    Push(&s, 6);
    StackTraverse(s,vi);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    printf("棧是否為空:%d\n", StackEmpty(s));
    GetTop(s, &e);
    printf("棧頂元素:%d\n", e);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    Pop(&s, &e);
    StackTraverse(s, vi);
    ClearStack(&s);
    printf("棧的長(zhǎng)度:%d\n", StackLength(s));
    printf("棧是否為空:%d\n", StackEmpty(s));

    DestroyStack(&s);
}

具體運(yùn)行效果和順序棧運(yùn)行效果一樣。

想要查看源碼可以訪問下面 github 鏈接,如果覺得不錯(cuò),請(qǐng)給個(gè) Star。

順序棧
鏈?zhǔn)綏?/a>

本文屬數(shù)據(jù)結(jié)構(gòu)系列持續(xù)更新中。

推薦閱讀更多精彩內(nèi)容