首页 > 大数据 > 数据分析 > 栈与队列基础:核心操作实现与算法应用解析
## 栈与队列基础:核心操作实现与算法应用解析
栈和队列作为两种基础而重要的线性数据结构,在计算机科学中扮演着关键角色。栈采用后进先出的访问模式,而队列遵循先进先出的处理原则,这两种不同的数据组织方式分别适用于特定的算法场景。
### 栈的基本定义与实现
栈是一种只能在一端进行插入和删除操作的线性表,该端称为栈顶。栈的核心特性是后进先出,最后入栈的元素最 先出栈。
**数组实现栈**
```c
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int top; // 栈顶指针
} ArrayStack;
// 初始化栈
void initStack(ArrayStack *stack) {
stack->top = -1; // 空栈时top为-1
}
// 检查栈是否为空
int isEmpty(ArrayStack *stack) {
return stack->top == -1;
}
// 检查栈是否已满
int isFull(ArrayStack *stack) {
return stack->top == MAX_SIZE - 1;
}
// 入栈操作
int push(ArrayStack *stack, int value) {
if (isFull(stack)) {
printf("栈已满,无法入栈\n");
return 0;
}
stack->data[++stack->top] = value;
return 1;
}
// 出栈操作
int pop(ArrayStack *stack, int *value) {
if (isEmpty(stack)) {
printf("栈为空,无法出栈\n");
return 0;
}
*value = stack->data[stack->top--];
return 1;
}
// 获取栈顶元素
int peek(ArrayStack *stack, int *value) {
if (isEmpty(stack)) {
printf("栈为空\n");
return 0;
}
*value = stack->data[stack->top];
return 1;
}
```
**链表实现栈**
```c
typedef struct StackNode {
int data;
struct StackNode *next;
} StackNode;
typedef struct {
StackNode *top; // 栈顶指针
int size; // 栈中元素个数
} LinkedStack;
// 初始化栈
void initLinkedStack(LinkedStack *stack) {
stack->top = NULL;
stack->size = 0;
}
// 入栈操作
void linkedPush(LinkedStack *stack, int value) {
StackNode *newNode = (StackNode*)malloc(sizeof(StackNode));
if (!newNode) {
printf("内存分配失败\n");
return;
}
newNode->data = value;
newNode->next = stack->top; // 新节点指向原栈顶
stack->top = newNode; // 更新栈顶指针
stack->size++;
}
// 出栈操作
int linkedPop(LinkedStack *stack, int *value) {
if (stack->top == NULL) {
printf("栈为空\n");
return 0;
}
StackNode *temp = stack->top;
*value = temp->data;
stack->top = temp->next; // 更新栈顶指针
free(temp);
stack->size--;
return 1;
}
```
### 队列的基本定义与实现
队列是一种在一端插入、另一端删除的线性表,插入端称为队尾,删除端称为队头。队列遵循先进先出的原则。
**数组实现循环队列**
```c
#define QUEUE_SIZE 100
typedef struct {
int data[QUEUE_SIZE];
int front; // 队头指针
int rear; // 队尾指针
int count; // 队列中元素个数
} CircularQueue;
// 初始化队列
void initQueue(CircularQueue *queue) {
queue->front = 0;
queue->rear = 0;
queue->count = 0;
}
// 检查队列是否为空
int isQueueEmpty(CircularQueue *queue) {
return queue->count == 0;
}
// 检查队列是否已满
int isQueueFull(CircularQueue *queue) {
return queue->count == QUEUE_SIZE;
}
// 入队操作
int enqueue(CircularQueue *queue, int value) {
if (isQueueFull(queue)) {
printf("队列已满\n");
return 0;
}
queue->data[queue->rear] = value;
queue->rear = (queue->rear + 1) % QUEUE_SIZE; // 循环移动
queue->count++;
return 1;
}
// 出队操作
int dequeue(CircularQueue *queue, int *value) {
if (isQueueEmpty(queue)) {
printf("队列为空\n");
return 0;
}
*value = queue->data[queue->front];
queue->front = (queue->front + 1) % QUEUE_SIZE; // 循环移动
queue->count--;
return 1;
}
// 获取队头元素
int getFront(CircularQueue *queue, int *value) {
if (isQueueEmpty(queue)) {
printf("队列为空\n");
return 0;
}
*value = queue->data[queue->front];
return 1;
}
```
**链表实现队列**
```c
typedef struct QueueNode {
int data;
struct QueueNode *next;
} QueueNode;
<"7h.adfw.cn"><"2e.adfw.cn"><"9l.adfw.cn">
typedef struct {
QueueNode *front; // 队头指针
QueueNode *rear; // 队尾指针
int size; // 队列大小
} LinkedQueue;
// 初始化队列
void initLinkedQueue(LinkedQueue *queue) {
queue->front = NULL;
queue->rear = NULL;
queue->size = 0;
}
// 入队操作
void linkedEnqueue(LinkedQueue *queue, int value) {
QueueNode *newNode = (QueueNode*)malloc(sizeof(QueueNode));
if (!newNode) {
printf("内存分配失败\n");
return;
}
newNode->data = value;
newNode->next = NULL;
if (queue->rear == NULL) { // 空队列
queue->front = queue->rear = newNode;
} else {
queue->rear->next = newNode;
queue->rear = newNode;
}
queue->size++;
}
// 出队操作
int linkedDequeue(LinkedQueue *queue, int *value) {
if (queue->front == NULL) {
printf("队列为空\n");
return 0;
}
QueueNode *temp = queue->front;
*value = temp->data;
queue->front = queue->front->next;
// 如果出队后队列为空,更新rear指针
if (queue->front == NULL) {
queue->rear = NULL;
}
free(temp);
queue->size--;
return 1;
}
```
### 栈与队列的核心操作复杂度分析
**时间复杂度比较**
```c
// 栈操作的时间复杂度
void analyzeStackComplexity() {
// 数组实现的栈:
// push: O(1) 平均,当需要扩容时为O(n)
// pop: O(1)
// peek: O(1)
// 链表实现的栈:
// push: O(1)
// pop: O(1)
// peek: O(1)
}
// 队列操作的时间复杂度
void analyzeQueueComplexity() {
// 循环队列:
// enqueue: O(1)
// dequeue: O(1)
// getFront: O(1)
// 链表队列:
// enqueue: O(1)
// dequeue: O(1)
// getFront: O(1)
}
```
**空间复杂度分析**
```c
// 空间复杂度对比
void analyzeSpaceComplexity() {
// 数组实现:
// 栈/队列:O(n),n为预先分配的数组大小
// 优点:连续内存,缓存友好
// 缺点:大小固定,可能浪费空间或需要扩容
// 链表实现:
// 栈/队列:O(n),n为实际元素个数
// 优点:动态扩展,无空间浪费
// 缺点:额外指针开销,内存碎片
}
```
### 栈的典型应用场景
**括号匹配验证**
```c
int isValidParentheses(char *s) {
char stack[10000];
int top = -1;
for (int i = 0; s[i] != '\0'; i++) {
char ch = s[i];
if (ch == '(' || ch == '[' || ch == '{') {
// 左括号入栈
stack[++top] = ch;
} else {
// 右括号检查匹配
if (top == -1) return 0; // 栈为空
char topChar = stack[top];
if ((ch == ')' && topChar == '(') ||
(ch == ']' && topChar == '[') ||
(ch == '}' && topChar == '{')) {
top--; // 匹配成功,出栈
} else {
return 0; // 不匹配
}
}
}
return top == -1; // 栈为空说明全部匹配
}
```
**表达式求值**
```c
// 中缀表达式转后缀表达式
void infixToPostfix(char *infix, char *postfix) {
char stack[1000];
int top = -1;
int j = 0;
for (int i = 0; infix[i] != '\0'; i++) {
char ch = infix[i];
if (isdigit(ch)) {
// 操作数直接输出
postfix[j++] = ch;
} else if (ch == '(') {
// 左括号入栈
stack[++top] = ch;
} else if (ch == ')') {
// 右括号:弹出直到遇到左括号
while (top != -1 && stack[top] != '(') {
postfix[j++] = stack[top--];
}
top--; // 弹出左括号
} else {
// 运算符:根据优先级处理
while (top != -1 && precedence(stack[top]) >= precedence(ch)) {
postfix[j++] = stack[top--];
}
stack[++top] = ch;
}
}
// 弹出栈中剩余运算符
while (top != -1) {
postfix[j++] = stack[top--];
}
postfix[j] = '\0';
}
int precedence(char op) {
switch (op) {
case '+':
case '-': return 1;
case '*':
case '/': return 2;
default: return 0;
}
}
```
### 队列的典型应用场景
**广度优先搜索中的队列应用**
```c
// 使用队列实现图的BFS
void bfs(int graph[][MAX_N], int start, int vertices) {
int visited[MAX_N] = {0};
CircularQueue queue;
initQueue(&queue);
visited[start] = 1;
enqueue(&queue, start);
printf("BFS遍历顺序: ");
while (!isQueueEmpty(&queue)) {
int current;
dequeue(&queue, ¤t);
printf("%d ", current);
// 遍历相邻节点
for (int i = 0; i < vertices; i++) {
if (graph[current][i] == 1 && !visited[i]) {
visited[i] = 1;
enqueue(&queue, i);
}<"4t.adfw.cn"><"0u.adfw.cn"><"5e.adfw.cn">
}
}
printf("\n");
}
```
**任务调度系统**
```c
typedef struct {
int taskId;
int priority;
char description[100];
} Task;
typedef struct {
Task tasks[MAX_TASKS];
int front;
int rear;
int size;
} TaskQueue;
// 任务调度器
void taskScheduler(TaskQueue *queue) {
while (queue->size > 0) {
Task currentTask;
if (dequeueTask(queue, ¤tTask)) {
printf("执行任务 %d: %s (优先级: %d)\n",
currentTask.taskId,
currentTask.description,
currentTask.priority);
// 模拟任务执行
// ...
}
}
printf("所有任务执行完成\n");
}
```
### 双端队列的特殊应用
双端队列结合了栈和队列的特性,可以在两端进行插入和删除操作。
```c
#define DEQUE_SIZE 100
typedef struct {
int data[DEQUE_SIZE];
int front;
int rear;
int size;
} Deque;
// 前端插入
void insertFront(Deque *deque, int value) {
if (deque->size == DEQUE_SIZE) {
printf("双端队列已满\n");
return;
}
if (deque->size == 0) {
deque->front = deque->rear = 0;
} else {
deque->front = (deque->front - 1 + DEQUE_SIZE) % DEQUE_SIZE;
}
deque->data[deque->front] = value;
deque->size++;
}
// 后端插入
void insertRear(Deque *deque, int value) {
if (deque->size == DEQUE_SIZE) {
printf("双端队列已满\n");
return;
}
if (deque->size == 0) {
deque->front = deque->rear = 0;
} else {
deque->rear = (deque->rear + 1) % DEQUE_SIZE;
}
deque->data[deque->rear] = value;
deque->size++;
}
// 前端删除
int deleteFront(Deque *deque, int *value) {
if (deque->size == 0) {
printf("双端队列为空\n");
return 0;
}
*value = deque->data[deque->front];
deque->front = (deque->front + 1) % DEQUE_SIZE;
deque->size--;
return 1;
}
```
### 栈与队列的选择策略
**何时选择栈**
1. 需要后进先出访问顺序的场景
2. 递归函数的系统栈实现
3. 深度优先搜索中的路径记录
4. 语法解析和表达式求值
5. 撤销操作功能实现
**何时选择队列**
1. 需要先进先出处理顺序的场景
2. 广度优先搜索中的节点管理
3. 任务调度和消息传递系统
4. 缓冲区管理和数据流处理
5. 打印队列和请求处理
**性能对比表**
```
特性 数组栈 链表栈 循环队列 链表队列
插入速度 O(1) O(1) O(1) O(1)
删除速度 O(1) O(1) O(1) O(1)
空间效率 固定 动态 固定 动态
内存局部性 好 差 好 差
扩容成本 高 低 高 低
```
### 实际编程中的最佳实践
**栈的实现建议**
```c
// 使用动态数组实现可扩容的栈
typedef struct {
int *data;
int top;
int capacity;
} DynamicStack;
void resizeStack(DynamicStack *stack) {
stack->capacity *= 2;
stack->data = realloc(stack->data,
stack->capacity * sizeof(int));
}
```
**队列的实现建议**
```c
// 使用链表实现无界队列
typedef struct {
Node *front;
Node *rear;
pthread_mutex_t lock; // 线程安全
} ThreadSafeQueue;
```
### 总结与扩展
栈和队列作为基础数据结构,其重要性不仅体现在简单的存储功能上,更在于它们为解决复杂问题提供了基本的模式框架。理解这两种数据结构的核心特性、实现方式及应用场景,是算法学习的重要基础。
从基础实现到高级应用,栈和队列展现了计算机科学中抽象的力量。栈的后进先出特性自然对应函数调用、回溯算法等场景,而队列的先进先出特性则完美匹配任务调度、广度优先搜索等需求。掌握这两种数据结构,能够为解决更复杂的算法问题奠定坚实基础。
在实际开发中,应根据具体需求选择合适的数据结构实现。对于固定大小的场景,数组实现具有更好的性能;对于需要动态扩展的情况,链表实现提供更大的灵活性。理解这些权衡,能够帮助开发者做出更明智的技术选择。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3104876/ ,如需转载,请注明出处,否则将追究法律责任。