栈(Stack)是一种抽象数据类型(ADT),它体现了后进先出(Last In First Out, LIFO)的操作原则。
栈的基本概念
- 后进先出(LIFO):栈中的元素,最后被放入(push)的,最先被取出(pop)。
- 栈顶与栈底:栈有一个顶部和一个底部。栈顶是元素被插入和删除的那一端;栈底则是最老的元素所在的一端。
栈的物理实现
栈可以用数组或链表来实现:
- 数组实现:使用一个固定大小的数组来存储栈元素,同时维护一个指向栈顶元素的指针。
- 链表实现:使用链表节点来存储栈元素,每个节点包含数据和指向下一个节点的指针。栈顶指针指向链表的第一个节点。
栈的基本操作
以下为栈的主要操作:
- 初始化(Init):创建一个空栈。
- 入栈(Push):在栈顶插入一个新元素。
- 出栈(Pop):移除栈顶元素。
- 查看栈顶元素(Peek/Top):返回栈顶元素的值,但不移除它。
- 判断栈是否为空(IsEmpty):检查栈是否不包含任何元素。
- 判断栈是否满(IsFull):仅在固定大小的栈中需要,检查栈是否达到其容量限制。
栈的操作示例
以下是使用数组实现的栈的操作示例:
初始化
typedef struct Stack {
int data[MAX_SIZE];
int top;
} Stack;
void initStack(Stack *s) {
s->top = -1; // 栈顶指针初始化为-1,表示栈为空
}
入栈
bool push(Stack *s, int value) {
if (s->top == MAX_SIZE - 1) {
// 栈满,无法入栈
return false;
}
s->data[++s->top] = value; // 先移动栈顶指针,再插入元素
return true;
}
出栈
bool pop(Stack *s, int *value) {
if (s->top == -1) {
// 栈空,无法出栈
return false;
}
*value = s->data[s->top--]; // 先获取栈顶元素,再移动栈顶指针
return true;
}
查看栈顶元素
bool peek(Stack *s, int *value) {
if (s->top == -1) {
// 栈空,无法查看栈顶元素
return false;
}
*value = s->data[s->top];
return true;
}
判断栈是否为空
bool isEmpty(Stack *s) {
return s->top == -1;
}
判断栈是否满
bool isFull(Stack *s) {
return s->top == MAX_SIZE - 1;
}
栈的应用
栈在计算机科学中有广泛的应用,以下是一些例子:
- 函数调用:操作系统使用栈来管理函数调用,包括参数传递、返回值、局部变量等。
- 表达式求值:编译器和解释器使用栈来解析和计算算术表达式。
- 括号匹配:检查代码中的括号是否正确匹配。
- 后退/撤销操作:在文本编辑器或其他应用程序中实现撤销操作。
栈的优缺点
优点:
- 插入和删除操作的时间复杂度为O(1),效率高。
- 实现简单。
缺点:
- 栈的大小通常固定,使用数组实现时可能会导致空间浪费或不足。
- 只能在栈顶进行操作,灵活性较低。
代码示例
顺序栈
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
typedef struct seqstack
{
int maxlen; // 数组元素的总个数
data_t *data; // 指向存放数据的数组的指针
int top; // 栈顶:最后一个有效元素的下标
} seqstack_t, *seqstack_p;
// 创建空顺序栈,len代表栈的最大长度
seqstack_p create_seqstack(int len)
{
// 开辟顺序栈的结构体大小空间
seqstack_p p = (seqstack_p)malloc(sizeof(seqstack_t));
if (NULL == p)
{
perror("error");
return NULL;
}
// 初始化结构体空间
p->top = -1;
p->maxlen = len;//保存数组的最大长度
p->data = (data_t *)malloc(sizeof(data_t) * len);//开辟数组大小空间,单个元素大小乘以元素个数
if (NULL == p->data)
{
perror("error");
return NULL;
}
return p;
}
// 判满
int full_seqstack(seqstack_p p)
{
return p->top + 1 == p->maxlen;
}
// 入栈
int push_seqstack(seqstack_p p, int data)
{
if (full_seqstack(p))//判满
{
printf("push error");
return -1;
}
else
{
p->top++;//让top栈顶加一
printf("top:%d\n", p->top);
p->data[p->top] = data;//让数据入栈
}
return 0;
}
// 判空
int empty_stack(seqstack_p p)
{
return p->top == -1;
}
// 出栈
int pop_stack(seqstack_p p)
{
if (empty_stack(p))//判空
{
printf("pop error");
}
while (p->top != -1)//栈顶有值,进入循环
{
printf("%d ", p->data[p->top]);//打印栈顶元素
p->top--;//让栈顶减一
}
printf("\n");
}
// 遍历栈
int show(seqstack_p p)
{
int i = 0;
while (i <= p->top)
{
printf("%d ", p->data[i]);
i++;
}
printf("\n");
}
int main(int argc, char const *argv[])
{
seqstack_p p = create_seqstack(6);
int i = 0, num;
while (i < p->maxlen)
{
scanf("%d", &num);
if (num == -1)
break;
else
{
push_seqstack(p, num);
}
i++;
}
show(p);
pop_stack(p);
return 0;
}
链式栈
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
typedef struct stacknode
{
int data;
struct stacknode *next;
} stacknode_t, *stacknode_p;
// 创建一个空链栈
void create_linkstack(stacknode_p *p) // p=&top *p=top
{
*p = NULL; // top=NULL
}
// 入栈:向栈中插入数据
int push_linkstack(stacknode_p *p, int data)
{
stacknode_p new = (stacknode_p)malloc(sizeof(stacknode_t));//创建新节点
if (NULL == new)
{
perror("error");
return -1;
}
new->data = data;//将data放入新节点的数据域
new->next = *p;//将新结点的插入到栈顶前面
*p = new;//移动栈针到新的栈顶结点
return 0;
}
// 出栈:删除栈中的元素
void pop_linkstack(stacknode_p *p)
{
// 判空
if (*p == NULL)
{
printf("empty");//如果栈中没有元素打印empty
}
else
{
while (*p != NULL)
{
stacknode_p del = *p;//让指针del指向栈顶节点 del=top
*p = (*p)->next;//移动栈顶指针到下一个节点
printf("%d\n", del->data);//打印出栈元素(要被删除的数据)
free(del);//释放被删除节点
del = NULL;
}
}
}
//计算栈的长度
int len_linkstack(stacknode_p p)
{
int i = 0;
while (p != NULL)
{
i++;
p = p->next;
}
return i;
}
// 遍历栈中元素
void show_linkstack(stacknode_p p)
{
if (p == NULL)
{
printf("empty");
}
else
{
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
}
printf("\n");
}
int main(int argc, char const *argv[])
{
stacknode_p top;
create_linkstack(&top);
int i = 0, num;
while (scanf("%d", &num) != EOF)
{
push_linkstack(&top, num);
}
show_linkstack(top);
pop_linkstack(&top);
show_linkstack(top);
printf("len:%d\n",len_linkstack(top));
return 0;
}