堆栈是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。
简单地说,堆栈可以看作一个箱子,只能在一端放和取,所以其主要操作有:
- 插入数据:入栈(Push)
- 删除数据:出栈(Pop)
而只能一端存取,也形成了其最主要的特性:
- 后入先出:Last In First Out(LIFO)
类型名称:堆栈(Stack)
数据对象集:一个有0个或多个元素的有穷线性表
操作集:长度为 MaxSize
的堆栈 S
属于 Stack
, 堆栈元素 item
属于 ElementType
1 2 3 4 5
| 1. Stack CreateStack () 生成空堆栈 2. int IsFull (Stack S) 判断堆栈S是否已满 3. void Push (Stack PtrS, ElementType item) 将元素item压入堆栈 4. int IsEmpty (Stack S) 判断堆栈S是否为空 5. ElementType Pop (Stack PtrS) 删除堆栈并返回栈顶元素
|
栈的顺序储存实现
所谓顺序存储,也就是利用数组来实现栈的相关操作,那么根据之前的叙述,我们可以写出栈库的头文件 Stack.h
C语言代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #ifndef DATA_STRUCTURE_STACK_H #define DATA_STRUCTURE_STACK_H
#include <stdio.h> #include <stdlib.h> #include <stdbool.h>
typedef int elementType; typedef struct SNode* stack; struct SNode{ int* stack; int allocLength; int top; };
stack createStack(); void push (stack s, int val); elementType pop (stack s); bool isFull(stack s); bool isEmpty(stack s);
#endif
|
- 说明: 栈所在结构体,为了使其大小可扩展,所以将
stack[]
数组以指针的方式替换,同时增加了一个用于保存栈大小的元素,即 allocLength
接下来在 Stack.c
中实现所定义的函数。
C语言代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
#include <assert.h> #include "Stack.h"
stack createStack() { stack s = (stack) malloc(sizeof(struct SNode)); s->allocLength = 8; s->top = 0; s->stack = (elementType*) malloc(sizeof(elementType) * s->allocLength); return s; }
void push (stack s, int val) { if (isFull(s)) { s->allocLength *= 2; s->stack = (elementType*) realloc(s->stack, sizeof(elementType) * s->allocLength); } s->stack[s->top++] = val; }
elementType pop (stack s) { assert(s->top >= 0); return s->stack[s->top--]; }
bool isFull(stack s) { return s->top == s->allocLength-1; }
bool isEmpty(stack s) { return s->top < 0; }
|
思考
问:一个数组实现两个堆栈
数组对半分之后分别从左向右储存
缺点:对半分之后,如果右边的数组放满之后左边却未放满,即有空间却无法再储存,就会造成空间浪费
一个从左向右,一个从右向左(改进方法)
对应栈的结构体如下:
1 2 3 4 5 6 7 8
| typedef struct SNode *Stack; struct DStack{ ElementType Data[MaxSize]; int Top1; int Top2; }S; S.Top1 = -1; S.Top2 = MaxSize;
|
压栈
1 2 3 4 5 6 7 8 9 10 11
| void Push(struct DStack *ParS, ElementType item, int Tag){ if (PtrS->Top2 - PtrS->Top1 == 1){ printf("堆栈满"); return; } if (Tag == 1) PtrS->Data[++(PtrS->Top1)] = item; else PtrS->Data[--(PtrS->Top1)] = item; }
|
弹栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ElementType Pop(struct DStack *ParS, int Tag){ if (Tag == 1){ if (PtrS->Top1 == -1){ printf("堆栈1为空"); return; } else return PtrS-Data[(PtrS->Top1)--]; } else { if (PtrS->Top2 == MaxSize){ printf("堆栈2为空"); return NULL; } else return PtrS->Data[(PtrS->Top2)++]; } }
|
堆栈的链式储存实现
链式存储其实我认为就栈而言,并不占什么优势,所以一般顺序实现即可,链式存储的 Stack.h
如下:
C语言代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #ifndef DATA_STRUCTURE_STACK_H #define DATA_STRUCTURE_STACK_H
#include <stdio.h> #include <stdlib.h> #include <stdbool.h>
typedef struct LNode* lStack; struct LNode{ elementType data; struct LNode* next; };
lStack createLStack(); void pushL (lStack s, int val); int popL (lStack s); bool isLEmpty(lStack s);
#endif
|
函数实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| lStack createLStack(){ lStack s = (lStack) malloc(sizeof(struct LNode)); s->next = NULL; return s; }
void pushL (lStack s, int val) { struct LNode* tmp = (lStack) malloc(sizeof(struct LNode)); tmp->data = val; tmp->next = s->next; s->next = tmp; }
elementType popL (lStack s) { assert(s->next != NULL); int tmp = s->next->data; s->next = s->next->next; return tmp; }
bool isLEmpty(lStack s) { return s->next == NULL; }
|
说明: 链式存储的栈,为方便操作,是带有头指针的。
学习的数据结构就是拿来用的,而如今的许多高级语言,已经将绝大多数数据结构以库的形式封装起来,在使用的时候,我们只需要直接调用即可,而不需要自己再写一个栈。例如 Java
中的 Stack
类,我们在使用的时候如果不熟,则可以查看文档,然后直接调用即可。
在熟悉构成之后,便可以进行应用,比如刷LeetCode