当前位置: 首页 > news >正文

学习记录——day17 数据结构 队列 链式队列

队列介绍

1、队列也是操作受限的线性表:所有操作只能在端点处进行,其删除和插入必须在不同端进行

2、允许插入操作的一端称为队尾,允许删除操作的一端称为队头

3、特点:先进先出(FIFO)

4、分类:

        顺序存储的栈称为顺序栈

        链式存储的队列,称为链式队列

顺序队列

1、使用一片连续存储的空间存储队列,并且给定两个变量,分别记录队头和队尾下标

2、普通顺序队列使用中,存在“假溢满”现象

        假溢满:队列中明明还有存储空间,但是由于队尾已经达到了数组的最大下标,不能在继续                          入队元素了

3、为了解决“假溢满”现象,我们引入了循环顺序队列

循环顺序队列

循环顺序队列:通过相关操作,当对头或队尾达到数组最大下标时,可以返回到下标为0的位置

注:以下均使用人为浪费一个空间的方法判满

1、创建

头节点类型定义

//类型重定义
typedef int datatype;//队列类型结构体
typedef struct Queue
{datatype data[MAX];int head;int tail;}SeqQueue, *SeqQueuePtr;

创建队列

SeqQueuePtr queue_create()
{SeqQueuePtr Q = (SeqQueuePtr)malloc(sizeof(SeqQueue));if(NULL == Q){return NULL;}bzero(Q->data,sizeof(Q->data));Q->front = Q->tail = 0;printf("创建成功 \n");return Q;
}

2、判空判满

int queue_empty(SeqQueuePtr Q)
{return Q->tail == Q->front;
}int queue_full(SeqQueuePtr Q)
{return (Q->tail+1)%MAX == Q->front;
}

3、插入

void queue_push(SeqQueuePtr Q ,datatype e)
{if (NULL == Q || queue_full(Q)){return;}Q->data[Q->tail] = e;Q->tail = (Q->tail+1)%MAX;return;
}

4、遍历

void queue_show(SeqQueuePtr Q)
{if (NULL == Q){return;}printf("遍历结果:");for (int i = Q->front; i !=Q->tail; i=(i+1)%MAX){printf("%d\t",Q->data[i]);}putchar(10);return;
}

5、出队

void queue_pop(SeqQueuePtr Q)
{if (NULL == Q || queue_empty(Q)){return;}printf("%d 出队\n",Q->data[Q->front]);Q->front = (Q->front+1)%MAX;
}

6、求实际大小

int queue_size(SeqQueuePtr Q)
{if (NULL == Q){return -1;}//不使用循环求大小int size = ((Q->tail-Q->front)+MAX)%MAX;return size;
}

7、销毁

void queue_destroy(SeqQueuePtr Q)
{if (NULL != Q){free(Q);Q = NULL;}printf("boom!!\n");return;
}

8、完整代码

dui_lie.h

#ifndef DUI_LEI
#define DUI_LEI#include <myhead.h>#define MAX 8
typedef int datatype;typedef struct 
{datatype data[MAX];int front;int tail;
}SeqQueue,*SeqQueuePtr;SeqQueuePtr queue_create();int queue_empty(SeqQueuePtr Q);int queue_full(SeqQueuePtr Q);void queue_push(SeqQueuePtr Q ,datatype e);void queue_show(SeqQueuePtr Q);void queue_pop(SeqQueuePtr Q);int queue_size(SeqQueuePtr Q);void queue_destroy(SeqQueuePtr Q);#endif // !DUI_LEI.H

dui_lie.c

#include "dui_lie.h"
#include <myhead.h>SeqQueuePtr queue_create()
{SeqQueuePtr Q = (SeqQueuePtr)malloc(sizeof(SeqQueue)*MAX);if(NULL == Q){return NULL;}bzero(Q->data,sizeof(Q->data));Q->front = Q->tail = 0;printf("创建成功 \n");return Q;
}int queue_empty(SeqQueuePtr Q)
{return Q->tail == Q->front;
}int queue_full(SeqQueuePtr Q)
{return (Q->tail+1)%MAX == Q->front;
}void queue_push(SeqQueuePtr Q ,datatype e)
{if (NULL == Q || queue_full(Q)){return;}Q->data[Q->tail] = e;Q->tail = (Q->tail+1)%MAX;return;
}void queue_show(SeqQueuePtr Q)
{if (NULL == Q){return;}printf("遍历结果:");for (int i = Q->front; i !=Q->tail; i=(i+1)%MAX){printf("%d\t",Q->data[i]);}putchar(10);return;
}void queue_pop(SeqQueuePtr Q)
{if (NULL == Q || queue_empty(Q)){return;}printf("%d 出队\n",Q->data[Q->front]);Q->front = (Q->front+1)%MAX;
}int queue_size(SeqQueuePtr Q)
{if (NULL == Q){return -1;}//不使用循环求大小int size = ((Q->tail-Q->front)+MAX)%MAX;return size;
}void queue_destroy(SeqQueuePtr Q)
{if (NULL != Q){free(Q);Q = NULL;}printf("boom!!\n");return;
}

main.c

#include "dui_lie.h"
int main(int argc, char const *argv[])
{SeqQueuePtr Q = queue_create();if (NULL == Q){return -1;}queue_push(Q,90);queue_push(Q,80);queue_push(Q,100);queue_push(Q,20);queue_show(Q);queue_pop(Q);queue_pop(Q);queue_show(Q);printf("数组实际大小为%d:\n",queue_size(Q));queue_destroy(Q);return 0;
}

链式队列

链式存储的队列称为链式队列

实现原理:
        单向链表头插尾删实现:链表的头部就是队尾,链表的尾部就是队头                                

        单向链表头删尾插实现:链表的头部就是队头,链表的尾部就是队尾

        但是,上述操作中,都要用到链表尾部节点,都需要遍历整个链表完成,于是专门使用一个指针指向队尾,称为尾指针

00.h

#ifndef DAY17_1
#define DAY17_1#include <myhead.h>//类型重定义
typedef int datatype;//节点结构体
typedef struct Node
{union {datatype data;int len;};struct Node *next;}Node, *NodePtr;//头节点结构体
typedef struct Queue
{NodePtr head;NodePtr tail;}Queue, *QueuePtr;//队列创建
QueuePtr queue_create();//判空
int queue_empty(QueuePtr Q);//头插
int queue_push(QueuePtr Q,datatype);//遍历
int queue_show(QueuePtr Q);//出队
int queue_pop(QueuePtr Q);//输出实际大小
int queue_size(QueuePtr Q);//销毁
void queue_destroy(QueuePtr Q);#endif // DAY17_1

00.c

#include "00.h"//先创建队列 然后创建链表,将队列的两个指针指向链表
QueuePtr queue_create()
{//申请队列的空间QueuePtr Q = (QueuePtr)malloc(sizeof(Queue));if (NULL == Q){printf("创建失败\n");return NULL;}//创建链表Q->head = (NodePtr)malloc(sizeof(Node));if (Q->head == NULL){printf("创建失败\n");free(Q);return NULL;}Q->head->len = 0;Q->head->next = NULL;Q->tail = Q->head;return Q;
}int queue_empty(QueuePtr Q)
{return Q->head->len == 0;
}int queue_push(QueuePtr Q,datatype e)
{if (NULL == Q){return -1;}NodePtr p = (NodePtr)malloc(sizeof(Node));if (NULL == p){return -1;}p->data = e;p->next = NULL;Q->tail->next = p;Q->tail = p;Q->head->len++;}int queue_show(QueuePtr Q)
{if (NULL == Q || queue_empty(Q)){return -1;}NodePtr q = Q->head->next;while (q){printf("%d\t",q->data);q = q->next;}putchar(10);
}int queue_pop(QueuePtr Q)
{if (NULL == Q){return -1;}NodePtr p = Q->head->next;Q->head->next = p->next;printf("%d 出队\n",p->data);free(p);p = NULL;//如果所有节点都出列成功,将尾节点重新指向头节点if (Q->tail == NULL)//Q->head->next == NULL{Q->tail = Q->head;}Q->head->len--;
}int queue_size(QueuePtr Q)
{if (NULL == Q){return -1;}return Q->head->len;
}void queue_destroy(QueuePtr Q)
{if (NULL == Q){return;}//释放所有节点while (!queue_empty(Q)){queue_pop(Q);}//释放头结点free(Q->head);Q->head = Q->tail = NULL;//释放队列空间free(Q);Q = NULL;
}

main.c

#include "00.h"int main(int argc, char const *argv[])
{QueuePtr Q = queue_create();if (NULL == Q){return -1;}queue_push(Q,233);queue_push(Q,1314);queue_push(Q,520);queue_show(Q);queue_pop(Q);queue_pop(Q);queue_pop(Q);queue_destroy(Q);return 0;
}

相关文章:

  • C#中GridControl的数据源双向绑定
  • 双向门控循环神经网络(BiGRU)及其Python和MATLAB实现
  • Redis快速入门(一)
  • Spring Boot中如何实现全链路调用日志跟踪?
  • 2.axios(发送get和post请求)
  • git学习笔记(总结了常见命令与学习中遇到的问题和解决方法)
  • 算法:二维数组打印问题
  • HDU1032——The 3n + 1 problem,HDU1033——Edge,HDU1034——Candy Sharing Game
  • nginx的配置和使用
  • ubuntu20.04使用systemd服务设置python程序开机自启动
  • [笔记]ONVIF服务端实现[进行中...]
  • 1.Spring Boot 简介(Spring MVC+Mybatis-plus)
  • oracle 查询锁表
  • JS 鼠标拖动实现移动滚动条的滚动效果
  • pageoffice常见问题处理
  • express + mock 让前后台并行开发
  • gcc介绍及安装
  • JavaScript类型识别
  • nodejs:开发并发布一个nodejs包
  • overflow: hidden IE7无效
  • Python实现BT种子转化为磁力链接【实战】
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • web标准化(下)
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 数据结构java版之冒泡排序及优化
  • 详解移动APP与web APP的区别
  • ​2020 年大前端技术趋势解读
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • # 利刃出鞘_Tomcat 核心原理解析(八)-- Tomcat 集群
  • #14vue3生成表单并跳转到外部地址的方式
  • (4)STL算法之比较
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (el-Date-Picker)操作(不使用 ts):Element-plus 中 DatePicker 组件的使用及输出想要日期格式需求的解决过程
  • (初研) Sentence-embedding fine-tune notebook
  • (六)软件测试分工
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (算法)求1到1亿间的质数或素数
  • ******之网络***——物理***
  • *2 echo、printf、mkdir命令的应用
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .htaccess 强制https 单独排除某个目录
  • .net Signalr 使用笔记
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • [Android开源]EasySharedPreferences:优雅的进行SharedPreferences数据存储操作
  • [BSidesCF 2019]Kookie1
  • [C#小技巧]如何捕捉上升沿和下降沿
  • [C++]AVL树怎么转
  • [C++随笔录] 红黑树
  • [Firefly-Linux] RK3568 pca9555芯片驱动详解
  • [Go 微服务] Kratos 验证码业务
  • [HeadFrist-HTMLCSS学习笔记][第一章Web语言:开始了解HTML]