重生之“我打数据结构,真的假的?”--3.栈和队列(无习题)

news2024/12/30 17:01:47

栈和队列

C语言中的栈和队列总结

在C语言中,**栈(Stack)队列(Queue)**是两种非常重要的数据结构。它们广泛用于各种应用中,比如内存管理、任务调度、表达式求值等。本文将对这两种数据结构进行详细的介绍,并展示如何在C语言中实现它们。

1. 栈(Stack)

栈是一种先进后出(LIFO,Last In First Out)数据结构,类似于一摞盘子,最后放上去的盘子最先被拿下来。
在这里插入图片描述

1.1 栈的特点

  • 先进后出(LIFO):最后入栈的元素最先出栈。
  • 单端操作:栈的插入和删除操作都发生在栈顶。

1.2 栈的基本操作

  • 压栈(Push):将元素压入栈顶。
  • 弹栈(Pop):从栈顶移除元素。
  • 查看栈顶元素(Peek/Top):获取栈顶元素但不删除它。
  • 判断栈是否为空(isEmpty)

1.3 栈的实现方式

栈可以通过数组或链表来实现。以下分别讨论栈的数组实现和链表实现。

1.3.1 使用数组实现栈

以下是用C语言实现栈的数组版:

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

#define MAX_SIZE 100

typedef struct Stack {
    int items[MAX_SIZE];
    int top;
} Stack;

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

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

// 判断栈是否已满
bool isFull(Stack* stack) {
    return stack->top == MAX_SIZE - 1;
}

// 压栈操作
void push(Stack* stack, int value) {
    if (isFull(stack)) {
        printf("栈已满,无法压入元素。\n");
        return;
    }
    stack->items[++stack->top] = value;
    printf("压入元素:%d\n", value);
}

// 弹栈操作
int pop(Stack* stack) {
    if (isEmpty(stack)) {
        printf("栈为空,无法弹出元素。\n");
        return -1;
    }
    return stack->items[stack->top--];
}

// 查看栈顶元素
int peek(Stack* stack) {
    if (isEmpty(stack)) {
        printf("栈为空,没有栈顶元素。\n");
        return -1;
    }
    return stack->items[stack->top];
}

// 遍历栈
void traverseStack(Stack* stack) {
    if (isEmpty(stack)) {
        printf("栈为空。\n");
        return;
    }
    for (int i = 0; i <= stack->top; i++) {
        printf("%d ", stack->items[i]);
    }
    printf("\n");
}

int main() {
    Stack stack;
    initStack(&stack);

    push(&stack, 10);
    push(&stack, 20);
    push(&stack, 30);

    printf("栈的内容:");
    traverseStack(&stack);

    printf("弹出元素:%d\n", pop(&stack));
    printf("栈顶元素:%d\n", peek(&stack));

    printf("栈的内容:");
    traverseStack(&stack);

    return 0;
}
1.3.2 使用链表实现栈

以下是使用链表实现栈的C语言代码:

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

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

typedef struct Stack {
    Node* top;
} Stack;

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

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

// 压栈操作
void push(Stack* stack, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = stack->top;
    stack->top = newNode;
    printf("压入元素:%d\n", value);
}

// 弹栈操作
int pop(Stack* stack) {
    if (isEmpty(stack)) {
        printf("栈为空,无法弹出元素。\n");
        return -1;
    }
    Node* temp = stack->top;
    int poppedValue = temp->data;
    stack->top = stack->top->next;
    free(temp);
    return poppedValue;
}

// 查看栈顶元素
int peek(Stack* stack) {
    if (isEmpty(stack)) {
        printf("栈为空,没有栈顶元素。\n");
        return -1;
    }
    return stack->top->data;
}

// 遍历栈
void traverseStack(Stack* stack) {
    Node* current = stack->top;
    if (isEmpty(stack)) {
        printf("栈为空。\n");
        return;
    }
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

int main() {
    Stack stack;
    initStack(&stack);

    push(&stack, 10);
    push(&stack, 20);
    push(&stack, 30);

    printf("栈的内容:");
    traverseStack(&stack);

    printf("弹出元素:%d\n", pop(&stack));
    printf("栈顶元素:%d\n", peek(&stack));

    printf("栈的内容:");
    traverseStack(&stack);

    return 0;
}

1.4 栈的应用

  • 函数调用栈:计算机系统使用栈来保存函数调用的返回地址。
  • 表达式求值和括号匹配:在表达式求值中,栈用于临时保存操作数和操作符。
  • 深度优先搜索(DFS):在图的遍历中,栈可以用于实现深度优先搜索。

2. 队列(Queue)

队列是一种先进先出(FIFO,First In First Out)数据结构,类似于排队买票,第一个到达的人先买票。

2.1 队列的特点

  • 先进先出(FIFO):第一个入队的元素第一个出队。
  • 双端操作:插入操作发生在队尾,而删除操作发生在队头。

2.2 队列的基本操作

  • 入队(Enqueue):在队尾添加一个元素。
  • 出队(Dequeue):从队头移除一个元素。
  • 查看队头元素(Front)
  • 判断队列是否为空(isEmpty)

2.3 队列的实现方式

队列可以通过数组或链表来实现。以下分别介绍这两种实现方式。

2.3.1 使用数组实现队列

以下是使用数组实现队列的C语言代码:

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

#define MAX_SIZE 100

typedef struct Queue {
    int items[MAX_SIZE];
    int front;
    int rear;
} Queue;

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

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

// 判断队列是否已满
bool isFull(Queue* queue) {
    return queue->rear == MAX_SIZE - 1;
}

// 入队操作
void enqueue(Queue* queue, int value) {
    if (isFull(queue)) {
        printf("队列已满,无法入队元素。\n");
        return;
    }
    if (isEmpty(queue)) {
        queue->front = 0;
    }
    queue->items[++queue->rear] = value;
    printf("入队元素:%d\n", value);
}

// 出队操作
int dequeue(Queue* queue) {
    if (isEmpty(queue)) {
        printf("队列为空,无法出队元素。\n");
        return -1;
    }
    int value = queue->items[queue->front];
    if (queue->front >= queue->rear) {
        // 队列为空
        queue->front = queue->rear = -1;
    } else {
        queue->front++;
    }
    return value;
}

// 查看队头元素
int front(Queue* queue) {
    if (isEmpty(queue)) {
        printf("队列为空,没有队头元素。\n");
        return -1;
    }
    return queue->items[queue->front];
}

// 遍历队列
void traverseQueue(Queue* queue) {
    if (isEmpty(queue)) {
        printf("队列为空。\n");
        return;
    }
    for (int i = queue->front; i <= queue->rear; i++) {
        printf("%d ", queue->items[i]);
    }
    printf("\n");
}

int main() {
    Queue queue;
    initQueue(&queue);

    enqueue(&queue, 10);
    enqueue(&queue, 20);
    enqueue(&queue, 30);

    printf("队列的内容:");
    traverseQueue(&queue);

    printf("出队元素:%d\n", dequeue(&queue));
    printf("队头元素:%d\n", front(&queue));

    printf("队列的内容:");
    traverseQueue(&queue);

    return 0;
}
2.3.2 使用链表实现队列

以下是使用链表实现队列的C语言代码:

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

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

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

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

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

// 入队操作
void enqueue(Queue* queue, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = NULL;

    if (isEmpty(queue)) {
        queue->front = queue->rear = newNode;
    } else {
        queue->rear->next = newNode;
        queue->rear = newNode;
    }
    printf("入队元素:%d\n", value);
}

// 出队操作
int dequeue(Queue* queue) {
    if (isEmpty(queue)) {
        printf("队列为空,无法出队元素。\n");
        return -1;
    }
    Node* temp = queue->front;
    int value = temp->data;
    queue->front = queue->front->next;

    if (queue->front == NULL) {
        queue->rear = NULL;
    }

    free(temp);
    return value;
}

// 查看队头元素
int front(Queue* queue) {
    if (isEmpty(queue)) {
        printf("队列为空,没有队头元素。\n");
        return -1;
    }
    return queue->front->data;
}

// 遍历队列
void traverseQueue(Queue* queue) {
    Node* current = queue->front;
    if (isEmpty(queue)) {
        printf("队列为空。\n");
        return;
    }
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

int main() {
    Queue queue;
    initQueue(&queue);

    enqueue(&queue, 10);
    enqueue(&queue, 20);
    enqueue(&queue, 30);

    printf("队列的内容:");
    traverseQueue(&queue);

    printf("出队元素:%d\n", dequeue(&queue));
    printf("队头元素:%d\n", front(&queue));

    printf("队列的内容:");
    traverseQueue(&queue);

    return 0;
}

2.4 队列的应用

  • 操作系统中的任务调度:队列用于实现任务调度和处理。
  • 广度优先搜索(BFS):在图的遍历中,队列用于实现广度优先搜索。
  • 缓存(Buffer):队列可用于实现环形缓冲区或缓冲机制。

3. 栈和队列的对比

特性栈(Stack)队列(Queue)
数据结构类型线性线性
操作模式LIFO(后进先出)FIFO(先进先出)
插入/删除位置只在一端操作(栈顶)两端操作(队头和队尾)
应用场景函数调用、递归、括号匹配任务调度、广度优先搜索

4. 小结

栈和队列都是重要的线性数据结构,栈采用LIFO原则,而队列采用FIFO原则。栈和队列的操作非常简单,但它们在实际应用中起到了至关重要的作用。在C语言中,栈和队列可以通过数组或链表来实现,每种实现方式都有其优缺点。

在理解了这些数据结构的基本操作后,可以更好地应用它们来解决实际问题,如表达式求值、任务调度、图遍历等。掌握这些基础数据结构也为进一步学习更加复杂的数据结构(如树、图等)打下了坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2223777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

element ui中el-image组件查看图片的坑

比如说上传组件使用el-image-viewer组件去看&#xff0c;如果用错了&#xff0c;你会发现&#xff0c;你每次只能看一张图片 <template><div><el-upload action"#" list-type"picture-card" :auto-upload"false" :file-list"…

LTSC版本没有微软应用商店怎么办?一招装上

前言 这几天小白在办公电脑上安装了Windows 11 24H2 LTSC版本&#xff0c;哦豁&#xff0c;界面真的清爽。默认桌面上只有一个垃圾桶和EDGE浏览器&#xff0c;就再也没有其他图标了。 &#xff08;吐槽1️⃣&#xff1a;原版系统镜像开机之后不都是这样的吗&#xff1f;这也能…

Rust初踩坑

一、下载 到官网https://www.rust-lang.org/zh-CN/tools/install下载你需要的版本 二、安装 执行rustup-init 文件&#xff0c;选择1 按提示直到安装完成 可以通过以下命令测试&#xff1a; rustc -V # 注意的大写的 V cargo -V # 注意的大写的 V三、在VScode中…

GFF: Gated Fully Fusion for Semantic Segmentation门控融合语义分割-论文阅读笔记

摘要&#xff1a; 语义分割通过对每个像素密集预测其类别&#xff0c;生成对场景的全面理解。深度卷积神经网络的高级特征已经在语义分割任务中证明了它们的有效性&#xff0c;然而高级特征的粗分辨率经常导致对小/薄物体的结果不佳&#xff0c;而这些物体的细节信息非常重要。…

如何在算家云搭建GPT-SOVITS(语音转换)

一、模型介绍 GPT-SOVITS是一款强大的小样本语音转换和文本转语音 WebUI工具。它集成了声音伴奏分离、自动训练集分割、中文ASR和文本标注等辅助工具。 具有以下特征&#xff1a; 零样本 TTS&#xff1a; 输入 5 秒的声音样本并体验即时文本到语音的转换。少量样本 TTS&…

Rust的move关键字在线程中的使用

为什么使用 move&#xff1f; 在 Rust 中&#xff0c;move 关键字主要用于闭包。当我们在一个线程中创建一个闭包并将其传递给另一个线程时&#xff0c;如果闭包中使用了某些变量&#xff0c;就需要决定这些变量的所有权归属。 不使用 move&#xff1a; 默认情况下&#xff0…

python实战项目42:themoviedb电影网站信息

python爬取themoviedb电影网站信息 一、寻找数据接口二、解析主页数据,获取详情页url三、向详情页url发送请求、获取并解析数据四、完整代码一、寻找数据接口 打开网站首页,F12打开开发者工具,刷新页面。 向下滑动页面,点击页面上的“Load More”图标。 寻找到数据接口,…

【网络原理】TCP/IP五层网络模型之网络层-----IP协议详解,建议收藏!!

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 前几篇文章中我们深入研究了TCP协议&#xff0c;因为TCP协议在我们日常开发中的使用频率非常高。而相比之下&#xff0c;IP协议与我们普通程序员关系就没那么近了。一般是专门开发…

2024年妈杯MathorCup大数据竞赛A题超详细解题思路

2024年妈杯大数据竞赛初赛整体难度约为0.6个国赛。A题为台风中心路径相关问题&#xff0c;为评价预测问题&#xff1b;B题为库存和销量的预测优化问题。B题难度稍大于A题&#xff0c;可以根据自己队伍情况进行选择。26日早六点之前发布AB两题相关解题代码论文。 下面为大家带来…

创建型模式-----建造者模式

目录 背景&#xff1a; 构建模式UML 代码示例 房子成品&#xff1a; 构建器抽象&#xff1a; 具体构建器&#xff1a; 建筑师&#xff1a; 测试部…

配置nginx服务通过ip访问多网站

1.关闭防火墙 [rootlocalhost wzj]# systemctl stop firewalld [rootlocalhost wzj]# sstenforce 0 bash: sstenforce: command not found... [rootlocalhost wzj]# setenforce 0 2&#xff0c;挂mnt [rootlocalhost wzj]# mount/dev/sr0/mnt bash: mount/dev/sr0/mnt: No suc…

C++20中头文件ranges的使用

<ranges>是C20中新增加的头文件&#xff0c;提供了一组与范围(ranges)相关的功能&#xff0c;此头文件是ranges库的一部分。包括&#xff1a; 1.concepts: (1).std::ranges::range:指定类型为range&#xff0c;即它提供开始迭代器和结束标记(it provides a begin iterato…

【WPF】中Dispatcher的DispatcherPriority参数使用

在 WPF 中&#xff0c;DispatcherPriority 参数用于指定通过 Dispatcher 调度的操作的执行优先级。加入 DispatcherPriority 参数的情况通常取决于你希望操作何时以及如何被执行。 1.Dispatcher的DispatcherPriority参数使用 以下是几种情况和示例说明&#xff1a; 1.1 需要…

量子纠错--shor‘s 码

定理1 (量子纠错的条件) C是一组量子编码&#xff0c;P是映射到C上的投影算子。假设是一个算子元素描述的量子操作&#xff0c;那么基于量子编码C&#xff0c;存在一个能对抗描述的噪声的纠错操作R的充要条件是 对某个复元素厄米矩阵成立。 将算子元素称为导致的错误。如果这样…

数字 图像处理算法的形式

一 基本功能形式 按图像处理的输出形式&#xff0c;图像处理的基本功能可分为三种形式。 1&#xff09;单幅图像 单幅图像 2&#xff09;多幅图像 单幅图像 3&#xff09;单&#xff08;或多&#xff09;幅图像 数字或符号等 二 几种具体算法形式 1.局部处理邻域对于任一…

第二单元历年真题整理

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 参考答案 1. A 2. A 3. A 4. D 5. D 6. D 解析&#xff1a; 栈和队列是两个不一样的结构&#xff0c;不能放在一起表示 7. B 8. C 解析&#xff1a; S --> A0 | B1 --> (S1 | 1) 0 | (S0 | 0)1 --> S10 | 10 | S…

Java程序员如何获得高并发经验?

高并发编程 提到并发编程很多人就会头疼了&#xff1b;首先就是一些基础概念&#xff1a;并发&#xff0c;并行&#xff0c;同步&#xff0c;异步&#xff0c;临界区&#xff0c;阻塞&#xff0c;非阻塞还有各种锁全都砸你脸上&#xff0c;随之而来的就是要保证程序运行时关键…

蓝桥杯题目理解

1. 一维差分 1.1. 小蓝的操作 1.1.1. 题目解析&#xff1a; 这道题提到了对于“区间”进行操作&#xff0c;而差分数列就是对于区间进行操作的好方法。 观察差分数列&#xff1a; 给定数列&#xff1a;1 3 5 2 7 1 差分数列&#xff1a;1 2 2 -3 5 6 题目要求把原数组全部…

Leetcode239. 滑动窗口最大值

问题描述&#xff1a; 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a;nums [1,3,…

c#子控件拖动父控件方法及父控件限在窗体内拖动

一、效果 拖放位置不超过窗体四边,超出后自动靠边停靠支持多子控件拖动指定控件拖放(含父控件或窗体)点击左上角logo弹出消息窗口(默认位置右下角)1.1 效果展示 1.2 关于MQTTnet(最新版v4.3.7.1207)实现在线客服功能,见下篇博文 https://github.com/dotnet/MQTTnet 网上…