问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言中栈和队列的实现与应用

创作时间:
作者:
@小白创作中心

C语言中栈和队列的实现与应用

引用
1
来源
1.
https://docs.pingcode.com/baike/1307451

栈和队列是C语言中两种重要的数据结构,它们分别遵循后进先出(LIFO)和先进先出(FIFO)的原则。本文将从基本概念、C语言实现、应用场景等多个维度,深入浅出地讲解栈和队列的相关知识。


栈和队列在C语言中的理解:栈是后进先出(LIFO)结构、队列是先进先出(FIFO)结构。栈是一种受限的线性表,只允许在一端进行插入和删除操作,这一端称为栈顶。队列也是一种受限的线性表,但它只允许在一端进行插入操作(队尾),而在另一端进行删除操作(队首)。

为了更深入地理解栈和队列,本文将详细介绍它们的概念、操作方法、应用场景及其在C语言中的实现。

一、栈的基本概念与实现

栈的基本概念

栈是一种后进先出(LIFO,Last In First Out)的数据结构。栈的基本操作包括:

  • 入栈(Push):将元素压入栈顶。
  • 出栈(Pop):从栈顶弹出元素。
  • 查看栈顶(Top/Peek):获取栈顶元素但不弹出。
  • 判断栈是否为空(IsEmpty):检查栈是否为空。

栈在C语言中的实现

栈可以使用数组或链表来实现。在这里,我们将分别介绍这两种方法。

使用数组实现栈

使用数组实现栈的优点是操作简单,缺点是需要预定义栈的最大容量,且栈的大小固定。

#include <stdio.h>
#include <stdlib.h>  

#define MAX 100  

typedef struct {  
    int data[MAX];  
    int top;  
} Stack;  

// 初始化栈  
void initStack(Stack *s) {  
    s->top = -1;  
}  

// 判断栈是否为空  
int isEmpty(Stack *s) {  
    return s->top == -1;  
}  

// 入栈  
void push(Stack *s, int value) {  
    if (s->top == MAX - 1) {  
        printf("Stack Overflown");  
        return;  
    }  
    s->data[++(s->top)] = value;  
}  

// 出栈  
int pop(Stack *s) {  
    if (isEmpty(s)) {  
        printf("Stack Underflown");  
        exit(1);  
    }  
    return s->data[(s->top)--];  
}  

// 查看栈顶元素  
int peek(Stack *s) {  
    if (isEmpty(s)) {  
        printf("Stack is emptyn");  
        exit(1);  
    }  
    return s->data[s->top];  
}  

int main() {  
    Stack s;  
    initStack(&s);  
    push(&s, 10);  
    push(&s, 20);  
    push(&s, 30);  
    printf("Top element is %dn", peek(&s));  
    printf("Popped element is %dn", pop(&s));  
    printf("Top element is %dn", peek(&s));  
    return 0;  
}  

使用链表实现栈

使用链表实现栈的优点是栈的大小可以动态调整,不需要预定义最大容量。

#include <stdio.h>
#include <stdlib.h>  

typedef struct Node {  
    int data;  
    struct Node *next;  
} Node;  

typedef struct {  
    Node *top;  
} Stack;  

// 初始化栈  
void initStack(Stack *s) {  
    s->top = NULL;  
}  

// 判断栈是否为空  
int isEmpty(Stack *s) {  
    return s->top == NULL;  
}  

// 入栈  
void push(Stack *s, int value) {  
    Node *newNode = (Node *)malloc(sizeof(Node));  
    if (!newNode) {  
        printf("Memory allocation failedn");  
        exit(1);  
    }  
    newNode->data = value;  
    newNode->next = s->top;  
    s->top = newNode;  
}  

// 出栈  
int pop(Stack *s) {  
    if (isEmpty(s)) {  
        printf("Stack Underflown");  
        exit(1);  
    }  
    Node *temp = s->top;  
    int poppedValue = temp->data;  
    s->top = s->top->next;  
    free(temp);  
    return poppedValue;  
}  

// 查看栈顶元素  
int peek(Stack *s) {  
    if (isEmpty(s)) {  
        printf("Stack is emptyn");  
        exit(1);  
    }  
    return s->top->data;  
}  

int main() {  
    Stack s;  
    initStack(&s);  
    push(&s, 10);  
    push(&s, 20);  
    push(&s, 30);  
    printf("Top element is %dn", peek(&s));  
    printf("Popped element is %dn", pop(&s));  
    printf("Top element is %dn", peek(&s));  
    return 0;  
}  

二、队列的基本概念与实现

队列的基本概念

队列是一种先进先出(FIFO,First In First Out)的数据结构。队列的基本操作包括:

  • 入队(Enqueue):将元素插入队尾。
  • 出队(Dequeue):从队首移除元素。
  • 查看队首(Front/Peek):获取队首元素但不移除。
  • 判断队列是否为空(IsEmpty):检查队列是否为空。

队列在C语言中的实现

队列同样可以使用数组或链表来实现。在这里,我们将分别介绍这两种方法。

使用数组实现队列

使用数组实现队列的一个问题是,随着元素的不断入队和出队,数组的前端会出现“空洞”。解决这个问题的一种方法是使用循环数组。

#include <stdio.h>
#include <stdlib.h>  

#define MAX 100  

typedef struct {  
    int data[MAX];  
    int front;  
    int rear;  
} Queue;  

// 初始化队列  
void initQueue(Queue *q) {  
    q->front = -1;  
    q->rear = -1;  
}  

// 判断队列是否为空  
int isEmpty(Queue *q) {  
    return q->front == -1;  
}  

// 判断队列是否已满  
int isFull(Queue *q) {  
    return (q->rear + 1) % MAX == q->front;  
}  

// 入队  
void enqueue(Queue *q, int value) {  
    if (isFull(q)) {  
        printf("Queue Overflown");  
        return;  
    }  
    if (isEmpty(q)) {  
        q->front = 0;  
    }  
    q->rear = (q->rear + 1) % MAX;  
    q->data[q->rear] = value;  
}  

// 出队  
int dequeue(Queue *q) {  
    if (isEmpty(q)) {  
        printf("Queue Underflown");  
        exit(1);  
    }  
    int dequeuedValue = q->data[q->front];  
    if (q->front == q->rear) {  
        q->front = q->rear = -1;  
    } else {  
        q->front = (q->front + 1) % MAX;  
    }  
    return dequeuedValue;  
}  

// 查看队首元素  
int peek(Queue *q) {  
    if (isEmpty(q)) {  
        printf("Queue is emptyn");  
        exit(1);  
    }  
    return q->data[q->front];  
}  

int main() {  
    Queue q;  
    initQueue(&q);  
    enqueue(&q, 10);  
    enqueue(&q, 20);  
    enqueue(&q, 30);  
    printf("Front element is %dn", peek(&q));  
    printf("Dequeued element is %dn", dequeue(&q));  
    printf("Front element is %dn", peek(&q));  
    return 0;  
}  

使用链表实现队列

使用链表实现队列的优点是队列的大小可以动态调整,不需要预定义最大容量。

#include <stdio.h>
#include <stdlib.h>  

typedef struct Node {  
    int data;  
    struct Node *next;  
} Node;  

typedef struct {  
    Node *front;  
    Node *rear;  
} Queue;  

// 初始化队列  
void initQueue(Queue *q) {  
    q->front = NULL;  
    q->rear = NULL;  
}  

// 判断队列是否为空  
int isEmpty(Queue *q) {  
    return q->front == NULL;  
}  

// 入队  
void enqueue(Queue *q, int value) {  
    Node *newNode = (Node *)malloc(sizeof(Node));  
    if (!newNode) {  
        printf("Memory allocation failedn");  
        exit(1);  
    }  
    newNode->data = value;  
    newNode->next = NULL;  
    if (isEmpty(q)) {  
        q->front = q->rear = newNode;  
    } else {  
        q->rear->next = newNode;  
        q->rear = newNode;  
    }  
}  

// 出队  
int dequeue(Queue *q) {  
    if (isEmpty(q)) {  
        printf("Queue Underflown");  
        exit(1);  
    }  
    Node *temp = q->front;  
    int dequeuedValue = temp->data;  
    q->front = q->front->next;  
    if (q->front == NULL) {  
        q->rear = NULL;  
    }  
    free(temp);  
    return dequeuedValue;  
}  

// 查看队首元素  
int peek(Queue *q) {  
    if (isEmpty(q)) {  
        printf("Queue is emptyn");  
        exit(1);  
    }  
    return q->front->data;  
}  

int main() {  
    Queue q;  
    initQueue(&q);  
    enqueue(&q, 10);  
    enqueue(&q, 20);  
    enqueue(&q, 30);  
    printf("Front element is %dn", peek(&q));  
    printf("Dequeued element is %dn", dequeue(&q));  
    printf("Front element is %dn", peek(&q));  
    return 0;  
}  

三、栈和队列的应用场景

栈的应用场景

栈在计算机科学中有许多应用场景,包括但不限于:

  • 函数调用管理:每次函数调用都会将其返回地址和局部变量压入栈,函数返回时从栈中弹出。
  • 表达式求值:用于中缀表达式转换为后缀表达式,以及后缀表达式的求值。
  • 深度优先搜索(DFS):在图或树的遍历过程中使用栈来记录路径。

队列的应用场景

队列在计算机科学中也有许多应用场景,包括但不限于:

  • 任务调度:操作系统中的任务调度器通常使用队列来管理进程。
  • 广度优先搜索(BFS):在图或树的遍历过程中使用队列来记录层次。
  • 数据流处理:用于处理数据流中的先到先处理的数据。

四、栈和队列的高级话题

栈和递归

栈在递归函数调用中扮演着重要角色。每次递归调用都会将当前的函数状态压入栈中,递归返回时从栈中弹出上一个状态。这使得递归函数能够正确地返回到前一个调用点。

队列和并发编程

队列在并发编程中非常有用,特别是在生产者-消费者模型中。生产者将数据放入队列,消费者从队列中取出数据进行处理。这种模型能够有效地解决多线程间的同步问题。

五、总结

栈和队列是两种重要的数据结构,它们在计算机科学中的应用非常广泛。栈的特点是后进先出(LIFO),适用于函数调用管理、表达式求值和深度优先搜索等场景。队列的特点是先进先出(FIFO),适用于任务调度、广度优先搜索和数据流处理等场景。在C语言中,栈和队列可以使用数组或链表来实现,每种实现方式都有其优点和缺点。理解并掌握栈和队列的概念、操作方法及应用场景,对于编写高效、可靠的程序具有重要意义。

相关问答FAQs:

1. 什么是栈和队列?

栈和队列是计算机科学中常用的数据结构。栈是一种后进先出(LIFO)的数据结构,类似于一叠盘子,只能从顶部插入和移除元素。队列是一种先进先出(FIFO)的数据结构,类似于排队,只能从一端插入元素,从另一端移除元素。

2. 栈和队列有什么不同之处?

栈和队列的主要区别在于元素的插入和移除顺序。在栈中,最后插入的元素是第一个被移除的,而在队列中,最先插入的元素是第一个被移除的。另外,栈只有一个插入和移除的位置(顶部),而队列有两个插入和移除的位置(前端和后端)。

3. 栈和队列在C语言中的应用场景是什么?

栈和队列在C语言中有广泛的应用场景。栈常用于函数调用过程中的存储局部变量、保存返回地址等;还可以用于表达式求值、括号匹配、逆波兰表达式计算等。队列常用于任务调度、缓冲区管理、广度优先搜索等。在C语言中,栈和队列可以通过数组或链表来实现。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号