C语言数据结构(队列、循环队列)

简介: C语言数据结构(队列、循环队列)

一、队列


1、queue.c内容


#include "02queue.h"
//队列的初始化函数
void queue_init(queue *p_queue/*指向调用函数提供的代表队列的结构体存储区*/) {
    //初始化要保证队列里没有数字,也就是
    //head和tail成员变量必须相等
    p_queue->head = 0;
    p_queue->tail = 0;
}
//队列的清理函数
void queue_deinit(queue *p_queue) {
    //清理函数需要把队列里的数字都删除
    p_queue->head = 0;
    p_queue->tail = 0;
}
//获得队列里数字个数的函数
int /*表示得到的数字个数*/queue_size(const queue *p_queue) {
    return p_queue->tail - p_queue->head;
}
//判断队列是否空的函数
int /*返回值为真表示队列空,否则不空*/queue_empty(const queue *p_queue) {
    return p_queue->head == p_queue->tail;
}
//判断队列是否满的函数
int /*返回值为真表示队列满,否则不满*/queue_full(const queue *p_queue) {
    //只要最后一个存储区被使用过
    //就表示队列满了
    return p_queue->tail >= SIZE;
}
//向队列里加入数字的函数
int /*返回值为真表示成功加入,否则加入不成功*/queue_push(queue *p_queue, int val/*要加入的数字*/) {
    if (p_queue->tail >= SIZE) {
        //如果队列已经满了就不能在加入数字了
        return 0;
    }
    p_queue->buf[p_queue->tail] = val;   //把新数字放在数组里以tail做下标的存储区里
    p_queue->tail++;    //tail向后移动一步
    return 1;
}
//从队列里获得数字的函数(同时删除数字)
int /*返回值为真表示获得数字成功,否则失败*/queue_pop(queue *p_queue, int *p_val/*用来向调用函数传递数字*/) {
    if (p_queue->head == p_queue->tail) {
        //队列是空的
        return 0;
    }
    *p_val = p_queue->buf[p_queue->head];   //以head做下标的存储区里面就是最前面的数字,把它赋值给整数指针形式参数指向的存储区
    p_queue->head++;   //把head向后移动一步,这样下次获得的就是后面的数字(相当于把当前数字删除了)
    return 1;
}
//从队列里获得数字的函数(不会删除数字)
int queue_front(const queue *p_queue, int *p_val) {
    if (p_queue->head == p_queue->tail) {
        //队列空的情况
        return 0;
    }
    *p_val = p_queue->buf[p_queue->head];
    return 1;
}


2、queue.h内容


#ifndef           __QUEUE_H__
#define           __QUEUE_H__
typedef struct {
    int buf[SIZE];    //用来存放队列里的数字.前面的数字记录到小下标的存储区里,后面的数字记录到大下标的存储区里.只要最后一个存储区被使用过就认为队列已经被充满了,即使前面有空着的存储区也不可以使用
    int head;         //代表最前面的数字所在的下标.如果队列里没有数字则head应该等于tail
    int tail;         //代表下一个数字应该放置的位置下标
} queue;   //代表队列的结构体类型
//队列的初始化函数
void queue_init(queue */*指向调用函数提供的代表队列的结构体存储区*/);
//队列的清理函数
void queue_deinit(queue *);
//获得队列里数字个数的函数
int /*表示得到的数字个数*/queue_size(const queue *);
//判断队列是否空的函数
int /*返回值为真表示队列空,否则不空*/queue_empty(const queue *);
//判断队列是否满的函数
int /*返回值为真表示队列满,否则不满*/queue_full(const queue *);
//向队列里加入数字的函数
int /*返回值为真表示成功加入,否则加入不成功*/queue_push(queue *, int /*要加入的数字*/);
//从队列里获得数字的函数(同时删除数字)
int /*返回值为真表示获得数字成功,否则失败*/queue_pop(queue *, int * /*用来向调用函数传递数字*/);
//从队列里获得数字的函数(不会删除数字)
int queue_front(const queue *, int *);
#endif      //__QUEUE_H__


3、主函数


#include <stdio.h>
#include "queue.h"
int main() {
    int val = 0;
    queue que = {0};
    queue_init(&que);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_push(&que, 10);
    queue_push(&que, 20);
    queue_push(&que, 30);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_front(&que, &val);
    printf("最前面的数字是%d\n", val);
    queue_pop(&que, &val);
    printf("%d ", val);
    queue_pop(&que, &val);
    printf("%d\n", val);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_push(&que, 40);
    queue_push(&que, 50);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    while (1) {
        if (!queue_pop(&que, &val)) {
            //不能从队列里获得数字了
            break;
        }
        printf("%d ", val);
    }
    printf("\n");
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_deinit(&que);
    return 0;
}
运行结果:
数字个数是0
判断空的结果是1
判断满的结果是0
数字个数是3
判断空的结果是0
判断满的结果是0
最前面的数字是10
10 20
数字个数是1
判断空的结果是0
判断满的结果是0
数字个数是3
判断空的结果是0
判断满的结果是0
30 40 50
数字个数是0
判断空的结果是1
判断满的结果是0

二、循环队列


1、loop_queue.c文件内容


#include "loop_queue.h"
//队列的初始化函数
void queue_init(queue *p_queue) {
    p_queue->tail = 0;    //下一个数字应该放在下标为0的存储区里
    p_queue->qty = 0;     //队列里还没有数字
}
//队列的清理函数
void queue_deinit(queue *p_queue) {
    p_queue->tail = 0;
    p_queue->qty = 0;
}
//计算第一个数字所在下标的函数
int /*得到的下标*/get_head(const queue *p_queue) {
    //如果tail是6,qty是3
    //使用tail - qty可以得到第一个数字
    //的下标
    //如果tail是3,qty是6
    //使用tail - qty + SIZE可以得到第一个
    //数字的下标
    int ret = p_queue->tail - p_queue->qty;
    if (ret < 0) {
        //最前面的数字在最后面数字的后面
        ret += SIZE;
    }
    return ret;
}
//获得队列里数字个数的函数
int queue_size(const queue *p_queue) {
    return p_queue->qty;
}
//判断队列空的函数
int queue_empty(const queue *p_queue) {
    return !p_queue->qty;
}
//判断队列满的函数
int queue_full(const queue *p_queue) {
    return p_queue->qty >= SIZE;
}
//向队列里加入数字的函数
int queue_push(queue *p_queue, int val) {
    if (p_queue->qty >= SIZE) {
        //队列已经满了
        return 0;
    }
    p_queue->buf[p_queue->tail] = val;
    p_queue->tail++;
    if (p_queue->tail >= SIZE) {
        //当最后一个存储区里已经放好数字后
        //应该把tail设置成0,表示后面的
        //数字应该从下标为0的存储区
        //开始继续存放
        p_queue->tail = 0;
    }
    p_queue->qty++;    //数字个数加一
    return 1;
}
//从队列里获得数字的函数(同时删除数字)
int queue_pop(queue *p_queue, int *p_val) {
    if (!p_queue->qty) {
        //队列是空的
        return 0;
    }
    *p_val = p_queue->buf[get_head(p_queue)];   //首先计算第一个数字所在存储区的下标,然后把这个存储区里的数字传递给调用函数
    p_queue->qty--;     //把数字个数减一,这导致最前面数字所在的下标向后移动一步(相当于删除最前面的数字)
    return 1;
}
//从队列里获得数字的函数(不会删除数字)
int queue_front(const queue *p_queue, int *p_val) {
    if (!p_queue->qty) {
        //队列是空的
        return 0;
    }
    *p_val = p_queue->buf[get_head(p_queue)];
    return 1;
}

2、loop_queue.h文件内容


#ifndef          __LOOP_QUEUE_H__
#define          __LOOP_QUEUE_H__
typedef struct {
    int buf[SIZE];    //用来存放队列里的数字.前面的数字存放在小下标的存储区里,后面的数字存放在大下标的存储区里.当最后一个存储区被使用过以后可以把后面的数字存放在下标为0的存储区里(前提条件是下标为0的存储区里没有有效数字)
    int qty;          //记录队列里的数字个数
    int tail;         //记录下一个数字应该放置的存储区下标
} queue;    //代表循环队列的结构体
//队列的初始化函数
void queue_init(queue *);
//队列的清理函数
void queue_deinit(queue *);
//获得队列里数字个数的函数
int queue_size(const queue *);
//判断队列空的函数
int queue_empty(const queue *);
//判断队列满的函数
int queue_full(const queue *);
//向队列里加入数字的函数
int queue_push(queue *, int );
//从队列里获得数字的函数(同时删除数字)
int queue_pop(queue *, int *);
//从队列里获得数字的函数(不会删除数字)
int queue_front(const queue *, int *);
#endif         //__03LOOP_QUEUE_H__


3、主函数内容


#include <stdio.h>
#include "loop_queue.h"
int main() {
    int val = 0;
    queue que = {0};
    queue_init(&que);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_push(&que, 10);
    queue_push(&que, 20);
    queue_push(&que, 30);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_front(&que, &val);
    printf("最前面的数字是%d\n", val);
    queue_pop(&que, &val);
    printf("%d ", val);
    queue_pop(&que, &val);
    printf("%d\n", val);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_push(&que, 40);
    queue_push(&que, 50);
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    while (1) {
        if (!queue_pop(&que, &val)) {
            //不能从队列里获得数字了
            break;
        }
        printf("%d ", val);
    }
    printf("\n");
    printf("数字个数是%d\n", queue_size(&que)/*获得队列里的数字个数*/);
    printf("判断空的结果是%d\n", queue_empty(&que)/*判断队列是否空*/);
    printf("判断满的结果是%d\n", queue_full(&que));/*判断队列是否满*/
    queue_deinit(&que);
    return 0;
}
运行结果:
数字个数是0
判断空的结果是1
判断满的结果是0
数字个数是3
判断空的结果是0
判断满的结果是0
最前面的数字是10
10 20
数字个数是1
判断空的结果是0
判断满的结果是0
数字个数是3
判断空的结果是0
判断满的结果是0
30 40 50
数字个数是0
判断空的结果是1
判断满的结果是0
目录
相关文章
|
16天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
28 1
|
25天前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
41 4
|
25天前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
38 4
|
25天前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
35 4
|
25天前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
40 4
|
25天前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
34 4
|
18天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
39 5
|
16天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
43 1
|
存储 缓存 C语言
数据结构——双链表(C语言)
数据结构——双链表(C语言)
|
1月前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
67 4