栈与队列的实现
栈
后进先出:插入与删除操作都在栈顶
数组实现栈
核心思想
-
使用一数组存储栈元素(例如 A ),栈顶指针 top 记录栈顶元素的索引。
-
将 top 初始化为 -1 ,表示栈为空。

-
通过对索引的加减等操作,实现入栈、出栈等操作
核心操作
-
push(x) : 入栈
push(x){ top = top + 1; //栈顶指针+1 A[top] = x; } -
pop() : 出栈
pop(){ if(top == -1) { // 栈空判断 printf("No element to pop \n"); return; } top = top - 1; /*栈顶指针减 1,直接将索引向前移一位,不用清除此处的数据,因为下次给此处赋值时会覆盖掉上次的数据*/ } -
top() : 获取栈顶元素的值(不删除)
Top(){ return A[top]; //直接返回栈顶元素的值 } -
IsEmpty() : 判断栈是否为空
int IsEmpty(){ if(top == -1){ return true; }else{ return false; } }
溢出问题及解决
-
当数组已满(top == 数组长度 - 1)时,继续入栈则会触发栈溢出
-
解决方案:创建更大的数组,将原来数组内所有元素复制到新数组( 新数组 一般为 原数组 的两倍)
代码实现
#include<stdio.h>
#define MAX_SIZE 101 // 定义栈的最大容量
int A[MAX_SIZE]; // 用数组A存储栈元素
int top = -1; // 栈顶指针,初始为-1表示栈空
// 入栈操作:将元素x压入栈顶
void Push(int x) {
if(top == MAX_SIZE - 1) { // 栈满判断
printf(" stack overflow \n");
return;
}
A[++top] = x; // 栈顶指针先加1,再存入元素
}
// 出栈操作:从栈顶弹出一个元素
void Pop() {
if(top == -1) { // 栈空判断
printf("No element to pop \n");
return;
}
top--; //栈顶指针减1
}
// 获取栈顶元素
int Top() {
if(top == -1) {
printf("栈为空\n");
return -1;
}
return A[top];
}
// 使用示例(可根据需求调用上述操作)
int main() {
Push(10);
Push(20);
printf("栈顶元素:%d\n", Top());
Pop();
printf("出栈后栈顶元素:%d\n", Top());
return 0;
}
上述实现简单直观,但也存在一些 缺点:
-
不能在一个程序中创建多个栈
-
大小固定,无法动态调整
因此更好的方法是通过 结构体 来实现:
-
可将栈的状态封装在结构体中
-
为什么要封装:
-
将相关的数据组织在一起
-
隐藏内部实现细节
-
提供统一的接口操作
-
-
-
可创建多个独立的栈
-
可根据需要自动调整大小
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define INIT_CAPACITY 10 typedef struct { int *data; //动态数组指针 int top; //栈顶指针 int capacity; //当前容量 }ArrayStack; //创建栈:在堆上分配内存 ArrayStack* creat_ArrayStack() { ArrayStack* stack = (ArrayStack*)malloc(sizeof(Arraystack)); //分配栈结构体本身的内存 stack->data = (int*)malloc(sizeof(int) * INIT_CAPACITY); //分配数据数组的内存 //初始化其他 stack->top = -1; stack->capacity = INIT_CAPACITY; return stack; } //判断栈是否为空 bool IsEmpty(Arraystack* stack) { return stack->top == -1; } //判断栈是否已满 bool IsFull(ArrayStack* stack) { return stack->top == stack->capacity - 1; } //扩容 void resize_ArrayStack(ArrayStack* stack) { int newCapacity = stack->capacity * 2; int* newData = (int*)malloc(sizeof(int) * newCapacity); for(int i = 0; i <= stack->top; i++) { //将原数组复制到新数组 newData[i] = stack->data[i]; } free(stack->data); stack->data = newData; stack->capacity = newCapacity; printf("已扩容,新容量:%d\n", newCacity); } //入栈 void push(ArrayStack* stack, int val) { if (IsFull(stack)) { resize_ArrayStack(stack); } stack->data[++stack->top] = val; } //出栈 int pop(ArrayStack* stack) { if (IsEmpty(stack)) { printf("栈为空,无法出栈\n"); return -1; } return stack->data[stack->top--]; //返回被弹出的数,并将栈顶指针减 1 } //查看栈顶元素 int Top(ArrayStack* stack){ if (IsEmpty(stack)) { printf("栈为空\n"); return -1; } return stack->data[stack->top]; } //获取栈大小 int Size(ArrayStack *stack) { return stack->top + 1; } //打印栈 void print_ArrayStack(ArrayStack *stack) { if (IsEmpty(stack)) { printf("栈: []\n"); return; } printf("栈: ["); for (int i = 0; i <= stack->top; i++) { printf("%d", stack->data[i]); if (i < stack->top) printf(", "); } printf("]\n"); } //释放栈 void free_ArrayStack(ArrayStack* stack) { free(stack->data); //释放前边为数组分配的内存 free(stack); //释放前边为结构体本身分配的内存 }
链表实现栈
核心思想
-
链表实现栈时,以链表头部作为栈顶,所有操作都在头部进行
-
入栈:创建新节点,指针域指向原栈顶节点,再将栈顶指针指向新节点

-
出栈:将栈顶指针向后移一位,释放原栈顶节点

代码实现
//链表节点的定义
typedef struct ListNode {
int val;
struct ListNode* next;
} ListNode;
// 创建新节点
ListNode* createNode(int value) {
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->val = value;
node->next = NULL;
return node;
}
//链表实现栈
typedef struct {
ListNode* top;
int size;
} LinkedStack;
// 初始化栈
LinkedStack* create_LinkedStack() {
LinkedStack* stack = (LinkedStack*)malloc(sizeof(LinkedStack));
stack->top = NULL;
stack->size = 0;
return stack;
}
// 判断栈是否为空
bool IsEmpty(LinkedStack* stack) {
return stack->top == NULL;
}
// 入栈
void Push(LinkedStack* stack, int value) {
ListNode* newNode = createNode(value);
newNode->next = stack->top;
stack->top = newNode;
stack->size++;
}
// 出栈
int Pop(LinkedStack* stack) {
if (IsEmpty(stack)) {
printf("栈为空,无法出栈\n");
return -1;
}
ListNode* temp = stack->top;
int value = temp->val;
stack->top = stack->top->next;
free(temp);
stack->size--;
return value;
}
// 查看栈顶元素
int Top(LinkedStack* stack) {
if (IsEmpty(stack)) {
printf("栈为空\n");
return -1;
}
return stack->top->val;
}
// 获取栈大小
int Size(LinkedStack* stack) {
return stack->size;
}
// 打印栈
void print_LinkedStack(LinkedStack* stack) {
if (IsEmpty(stack)) {
printf("栈: []\n");
return;
}
printf("栈: [");
ListNode *current = stack->top;
while (current != NULL) {
printf("%d", current->val);
if (current->next != NULL) printf(", ");
current = current->next;
}
printf("]\n");
}
// 释放栈
void free_LinkedStack(LinkedStack* stack) {
while (!IsEmpty(stack)) {
Pop(stack);
}
free(stack);
}
队列
先进先出:队尾进入,队首离开
数组实现队列
核心思想
-
设置两个索引分别代表队首(front)和队尾(rear),二者都为 -1 时表示队列为空

-
队列的长度为 front 和 rear 之间的长度

-
入队:将 rear后移一位,给该处赋值
-
当数组最后填满而前面空间仍有剩余时,可以使用循环数组实现对该空间的利用:
(queue->front + i) % queue->capacity
-
-
出队:将 front 后移一位

代码实现
typedef struct {
int* data;
int front;
int rear;
int size;
int capacity;
} ArrayQueue;
// 初始化队列
ArrayQueue* create_ArrayQueue() {
ArrayQueue* queue = (ArrayQueue*)malloc(sizeof(ArrayQueue));
queue->capacity = INIT_CAPACITY;
queue->data = (int*)malloc(sizeof(int) * queue->capacity);
queue->front = 0;
queue->rear = 0;
queue->size = 0;
return queue;
}
// 判断队列是否为空
bool IsEmpty(ArrayQueue* queue) {
return queue->size == 0;
}
// 判断队列是否已满
bool IsFull(ArrayQueue* queue) {
return queue->size == queue->capacity;
}
// 扩容
void resize_ArrayQueue(ArrayQueue* queue) {
int newCapacity = queue->capacity * 2;
int* newData = (int*)malloc(sizeof(int) * newCapacity);
// 将原队列元素复制到新队列
for (int i = 0; i < queue->size; i++) {
newData[i] = queue->data[(queue->front + i) % queue->capacity];
}
free(queue->data);
queue->data = newData;
queue->front = 0;
queue->rear = queue->size;
queue->capacity = newCapacity;
printf("队列已扩容,新容量: %d\n", newCapacity);
}
// 入队
void Enqueue(ArrayQueue* queue, int value) {
if (IsFull(queue)) {
resizeArrayQueue(queue);
}
queue->data[queue->rear] = value;
queue->rear = (queue->rear + 1) % queue->capacity;
queue->size++;
}
// 出队
int Dequeue(ArrayQueue* queue) {
if (IsEmpty(queue)) {
printf("队列为空,无法出队\n");
return -1;
}
int value = queue->data[queue->front];
queue->front = (queue->front + 1) % queue->capacity;
queue->size--;
return value;
}
// 查看队头元素
int Front(ArrayQueue* queue) {
if (IsEmpty(queue)) {
printf("队列为空\n");
return -1;
}
return queue->data[queue->front];
}
// 获取队列大小
int Size(ArrayQueue* queue) {
return queue->size;
}
// 打印队列
void print_ArrayQueue(ArrayQueue* queue) {
if (IsEmpty(queue)) {
printf("队列: []\n");
return;
}
printf("队列: [");
for (int i = 0; i < queue->size; i++) {
printf("%d", queue->data[(queue->front + i) % queue->capacity]);
if (i < queue->size - 1) printf(", ");
}
printf("]\n");
}
// 释放队列
void free_ArrayQueue(ArrayQueue* queue) {
free(queue->data);
free(queue);
}
链表实现队列
核心思想
-
使用两个指针 front 和 rear 分别指向链表的头部和尾部

-
入队:使原尾节点指向新节点,再使 rear 指向新节点

-
出队:将 front 后移一位,并释放原头节点

代码实现
//定义链表节点
typedef struct ListNode {
int val;
struct ListNode* next;
} ListNode;
// 创建新节点
ListNode* createNode(int value) {
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->val = value;
node->next = NULL;
return node;
}
//链表实现队列
typedef struct {
ListNode* front;
ListNode* rear;
int size;
} LinkedQueue;
// 初始化队列
LinkedQueue* create_LinkedQueue() {
LinkedQueue* queue = (LinkedQueue*)malloc(sizeof(LinkedQueue));
queue->front = NULL;
queue->rear = NULL;
queue->size = 0;
return queue;
}
// 判断队列是否为空
bool IsEmpty(LinkedQueue* queue) {
return queue->front == NULL;
}
// 入队
void Enqueue(LinkedQueue* queue, int value) {
ListNode* newNode = createNode(value);
if (IsEmpty(queue)) {
queue->front = queue->rear = newNode;
} else {
queue->rear->next = newNode;
queue->rear = newNode;
}
queue->size++;
}
// 出队
int Dequeue(LinkedQueue* queue) {
if (IsEmpty(queue)) {
printf("队列为空,无法出队\n");
return -1;
}
ListNode* temp = queue->front;
int value = temp->val;
queue->front = queue->front->next;
// 如果出队后队列为空,需要更新rear指针
if (queue->front == NULL) {
queue->rear = NULL;
}
free(temp);
queue->size--;
return value;
}
// 查看队头元素
int Front(LinkedQueue* queue) {
if (IsEmpty(queue)) {
printf("队列为空\n");
return -1;
}
return queue->front->val;
}
// 获取队列大小
int Size(LinkedQueue* queue) {
return queue->size;
}
// 打印队列
void print_LinkedQueue(LinkedQueue* queue) {
if (IsEmpty(queue)) {
printf("队列: []\n");
return;
}
printf("队列: [");
ListNode *current = queue->front;
while (current != NULL) {
printf("%d", current->val);
if (current->next != NULL) printf(", ");
current = current->next;
}
printf("]\n");
}
// 释放队列
void free_LinkedQueue(LinkedQueue* queue) {
while (!IsEmpty(queue)) {
Dequeue(queue);
}
free(queue);
}

1039

被折叠的 条评论
为什么被折叠?



