栈是一种重要的数据结构,它有两种主要类型:
1. 静态栈(Static Stack):静态栈是指栈的大小在创建时已经确定,不能再更改。这种栈通常使用数组或类似数组的结构来实现。当栈满了之后,再往栈中插入元素会导致栈溢出错误。
2. 动态栈(Dynamic Stack):动态栈是指栈的大小可以在运行时更改。这种栈通常使用链表等动态数据结构来实现。当栈满了之后,可以通过分配更多内存来扩展栈的空间,避免了栈溢出错误。
需要注意的是,栈的数据结构还有一些变体,例如循环栈、双端栈等,但这些都是基于上述两种基本类型的扩展。
下面是使用C语言实现栈的顺序表和链表两种数据结构的基本操作代码示例:
1. 栈的顺序表实现:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
typedef struct {
int stack[MAX_SIZE];
int top;
} Stack;
// 初始化栈
void init(Stack *s) {
s->top = -1;
}
// 判断栈是否为空
int is_empty(Stack *s) {
return s->top == -1;
}
// 判断栈是否已满
int is_full(Stack *s) {
return s->top == MAX_SIZE - 1;
}
// 元素入栈
void push(Stack *s, int item) {
if (is_full(s)) {
printf("Stack overflow\n");
return;
}
s->stack[++s->top] = item;
}
// 元素出栈
int pop(Stack *s) {
if (is_empty(s)) {
printf("Stack underflow\n");
return -1;
}
return s->stack[s->top--];
}
// 获取栈顶元素
int peek(Stack *s) {
if (is_empty(s)) {
printf("Stack is empty\n");
return -1;
}
return s->stack[s->top];
}
// 获取栈的大小
int size(Stack *s) {
return s->top + 1;
}
2. 栈的链表实现:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
typedef struct {
Node *top;
} Stack;
// 初始化栈
void init(Stack *s) {
s->top = NULL;
}
// 判断栈是否为空
int is_empty(Stack *s) {
return s->top == NULL;
}
// 元素入栈
void push(Stack *s, int item) {
Node *newNode = (Node *)malloc(sizeof(Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
return;
}
newNode->data = item;
newNode->next = s->top;
s->top = newNode;
}
// 元素出栈
int pop(Stack *s) {
if (is_empty(s)) {
printf("Stack underflow\n");
return -1;
}
Node *temp = s->top;
int item = temp->data;
s->top = temp->next;
free(temp);
return item;
}
// 获取栈顶元素
int peek(Stack *s) {
if (is_empty(s)) {
printf("Stack is empty\n");
return -1;
}
return s->top->data;
}
// 获取栈的大小
int size(Stack *s) {
int count = 0;
Node *current = s->top;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
上述代码实现了栈的基本操作,包括:
- `init`: 初始化栈。
- `is_empty`: 判断栈是否为空,返回整数值。
- `push`: 将元素压入栈顶。
- `pop`: 弹出栈顶元素,并返回该元素。
- `peek`: 返回栈顶元素,但不弹出。
- `size`: 返回栈的大小。
栈的顺序表实现使用数组来存储栈元素,栈顶指针指向数组的最后一个元素。栈的链表实现使用链表来存储栈元素,栈顶指针指向链表的第一个节点。
你可以根据需要选择使用栈的顺序表实现或链表实现来适应不同的场景。
下面是一个使用栈进行简单计算的实例,计算后缀表达式的值:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int evaluate_postfix(char *expression) {
Stack stack;
init(&stack);
while (*expression) {
if (isdigit(*expression)) {
push(&stack, *expression - '0');
} else {
int operand2 = pop(&stack);
int operand1 = pop(&stack);
int result;
switch (*expression) {
case '+':
result = operand1 + operand2;
break;
case '-':
result = operand1 - operand2;
break;
case '*':
result = operand1 * operand2;
break;
case '/':
result = operand1 / operand2;
break;
default:
printf("Invalid expression\n");
return -1;
}
push(&stack, result);
}
expression++;
}
return pop(&stack);
}
int main() {
char expression[] = "23*5+-";
int result = evaluate_postfix(expression);
printf("计算结果: %d\n", result);
return 0;
}
上述代码通过栈来计算后缀表达式的值。栈中存储操作数,当遇到操作符时,从栈中弹出操作数进行相应的计算,并将结果压入栈中,最后栈中剩下的元素即为计算结果。在示例中,后缀表达式为`23*5+-`,计算结果为3。