C语言如何进栈出栈:使用数组、使用链表
C语言中实现进栈和出栈操作的方法主要有两种:使用数组和使用链表。在本文中,我们将详细探讨这两种方法,并介绍如何在实际编程中实现它们。
一、使用数组
使用数组实现栈是一种常见的方法,因为数组在内存中是连续的,这使得访问和操作都非常高效。然而,使用数组实现栈有一个缺点,那就是栈的大小是固定的,不能动态调整。
1.1、定义栈结构
首先,我们需要定义一个结构体来表示栈。这个结构体包含一个数组用于存储栈中的元素,以及一个整数变量用于跟踪栈顶的位置。
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100 // 定义栈的最大容量
typedef struct {
int data[MAX_SIZE];
int top;
} Stack;
1.2、初始化栈
在使用栈之前,我们需要初始化栈。初始化的过程主要是将栈顶位置设置为-1,表示栈是空的。
void initStack(Stack *s) {
s->top = -1;
}
1.3、进栈操作
进栈操作是指将一个元素压入栈中。在数组实现的栈中,我们需要先检查栈是否已满,如果未满则将元素放入栈顶,并更新栈顶位置。
int push(Stack *s, int value) {
if (s->top >= MAX_SIZE - 1) {
printf("Stack Overflown");
return -1;
}
s->data[++(s->top)] = value;
return 0;
}
1.4、出栈操作
出栈操作是指将栈顶的元素移出栈。在数组实现的栈中,我们需要先检查栈是否为空,如果不为空则返回栈顶元素,并更新栈顶位置。
int pop(Stack *s) {
if (s->top == -1) {
printf("Stack Underflown");
return -1;
}
return s->data[(s->top)--];
}
1.5、查看栈顶元素
有时我们需要查看栈顶的元素而不将其移出栈,这时我们可以使用peek操作。
int peek(Stack *s) {
if (s->top == -1) {
printf("Stack is emptyn");
return -1;
}
return s->data[s->top];
}
二、使用链表
使用链表实现栈可以克服数组实现的栈的固定大小限制。链表实现的栈可以根据需要动态调整大小,但是链表的节点在内存中不是连续的,这可能会影响访问速度。
2.1、定义栈节点结构
首先,我们需要定义一个结构体来表示栈的节点。每个节点包含一个数据域和一个指向下一个节点的指针。
typedef struct Node {
int data;
struct Node *next;
} Node;
2.2、初始化栈
在使用链表实现的栈之前,我们需要初始化栈。初始化的过程主要是将栈顶指针设置为NULL,表示栈是空的。
void initStack(Node top) {
*top = NULL;
}
2.3、进栈操作
进栈操作是指将一个元素压入栈中。在链表实现的栈中,我们需要创建一个新节点,将新节点的next指针指向当前的栈顶,然后将栈顶指针更新为新节点。
void push(Node top, int value) {
Node *newNode = (Node *)malloc(sizeof(Node));
if (!newNode) {
printf("Heap Overflown");
return;
}
newNode->data = value;
newNode->next = *top;
*top = newNode;
}
2.4、出栈操作
出栈操作是指将栈顶的元素移出栈。在链表实现的栈中,我们需要先检查栈是否为空,如果不为空则返回栈顶元素,并更新栈顶指针。
int pop(Node top) {
if (*top == NULL) {
printf("Stack Underflown");
return -1;
}
Node *temp = *top;
int poppedValue = temp->data;
*top = (*top)->next;
free(temp);
return poppedValue;
}
2.5、查看栈顶元素
有时我们需要查看栈顶的元素而不将其移出栈,这时我们可以使用peek操作。
int peek(Node *top) {
if (top == NULL) {
printf("Stack is emptyn");
return -1;
}
return top->data;
}
三、栈的应用场景
栈是一种非常常用的数据结构,广泛应用于各种计算机科学和工程问题中。以下是一些常见的应用场景:
3.1、括号匹配
在编译器和解释器中,栈常用于检查括号是否匹配。通过遍历表达式中的每一个字符,将左括号压入栈中,当遇到右括号时,从栈中弹出一个左括号,如果匹配失败,则表示括号不匹配。
int isBalanced(char *exp) {
Stack s;
initStack(&s);
for (int i = 0; exp[i] != '