5. 队列 - 存储结构

16 篇文章 0 订阅

文章目录

5. 队列 - 存储结构

5.1 队列 - 基本概念

  • 队列是两端都开口"的线性储存结构,要求数据只能从一端进,从另一端出,遵循 "先进先出" 的原则。
  • 队列存储结构的实现有以下两种方式:
    • 顺序队列:在顺序表的基础上实现的队列结构。
    • 链队列:在链表的基础上实现的队列结构。

5.2 队列 - 顺序表实现队列存储结构

  • 顺序队列的底层使用的是数组,因此需预先申请一块足够大的内存空间初始化顺序队列。为了满足顺序队列中数据从队尾进,队头出且先进先出的要求,我们还需要定义两个指针(top 和 rear)分别用于指向顺序队列中的队头元素和队尾元素

  • 如果数据在数组中位置只向后移动,整个顺序队列在数据不断地进队出队过程中,在顺序表中的位置不断后移,存储区会不停的扩大,因此实际中存储数组循环存储,相当于存储区域是一个环形结构

  • 顺序表实现队列存储结构如下:

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

    typedef struct QueueDefine {
    uint8_t* QueueAdress; // 存储地址
    uint16_t top; // 队头
    uint16_t rear; // 队尾
    uint16_t size; // 队列容量
    uint8_t FullOrEmptyflag; //解决取存中top和rear重合时为空或者为满的情况,1为满
    }Queue;
    /**

    • Discribe : 创建一个队列
    • Input : size -> 创建队列的容量尺寸
    • return : 申请队列的地址
      /
      Queue CreateQueue(uint16_t size) {
      Queue QueueCreate;
      QueueCreate.QueueAdress = (uint8_t
      )malloc(size * sizeof(uint8_t));
      memset(QueueCreate.QueueAdress, 0xff, size);
      QueueCreate.top = 0;
      QueueCreate.rear = 0;
      QueueCreate.size = size;
      QueueCreate.FullOrEmptyflag = 0;
      return QueueCreate;
      }
      /
      *
    • Discribe : 判断队列是否为空或者满
    • Input : queue -> 存储队列
    • return : 1 -> 队列为满 , 0 -> 队列为空
      /
      uint8_t QueueIsEmptyOrFull(Queue
      queue) {
      return queue->FullOrEmptyflag;
      }
      /
      *
    • Input : queue->存储队列
    • return : 队列可存储空间
    • /
      uint16_t GetQueueSpace(Queue
      queue) {
      if (queue->top == queue->rear) {
      return QueueIsEmptyOrFull(queue) ? 0 : queue->size ;
      }
      if (queue->top < queue->rear) {
      return queue->size - (queue->rear - queue->top );
      }else {
      return queue->top - queue->rear;
      }
      }
      /**
    • Discribe : 数据入队
    • Input : queue -> 存储队列, data -> 入队数据, length -> 入队长度
    • return : 1 -> 入队成功 , 0 -> 入队失败
      /
      uint8_t EnterQueue(Queue
      queue, uint8_t
      data, uint8_t length) {
      if (data == NULL || length < 1) {
      printf("入队数据有误!!!
      ");
      return 0;
      }
      if (GetQueueSpace(queue) < length) {
      printf("队列空间不足, space = %d, data length = %d!!!
      ", GetQueueSpace(queue), length);
      return 0;
      }
      for (uint16_t i = 0; i < length; i++) {
      queue->QueueAdress[queue->rear % queue->size] = data[i];
      queue->rear = ((queue->rear + 1) % queue->size);
      if (queue->top == queue->rear) {
      queue->FullOrEmptyflag = 1;
      }
      }
      }

    /**

    • Discribe : 数据出队
    • Input : queue -> 存储队列, data -> 出队存放地址, length -> 出队长度
    • return : 1 -> 出队成功 , 0 -> 出队失败
      /
      uint8_t LeaveQueue(Queue
      queue, uint8_t
      data, uint8_t length) {
      if (data == NULL || length < 1) {
      printf("出队数据指令有误!!!
      ");
      return 0;
      }
      if ((queue->size - GetQueueSpace(queue)) < length) {
      printf("取出数据长度大于队列存储数据长度, save size = %d, data length = %d!!!
      ", queue->size - GetQueueSpace(queue), length);
      return 0;
      }
      for (uint16_t i = 0; i < length; i++) {
      data[i] = queue->QueueAdress[queue->top % queue->size];
      queue->QueueAdress[queue->top % queue->size] = 0xff;
      queue->top = ((queue->top + 1 ) % queue->size);
      if (queue->top == queue->rear) {
      queue->FullOrEmptyflag = 0;
      }
      }
      }

    void display(Queue* queue) {
    printf(“队列空间存储内容为(ff无效值):”);
    for (uint16_t i = 0; i < queue->size; i++) {
    printf("%x “, queue->QueueAdress[i]);
    }
    printf(”[ top = %d , rear = %d ]", queue->top, queue->rear);
    printf(" 队列空间 space = %d !

    ", GetQueueSpace(queue));
    }

    int main() {
    Queue quece = CreateQueue(10);
    printf("创建了一个容量为 :%d 的队列!
    ", quece.size);
    display(&quece);
    uint8_t data[10] = {0};
    for (uint16_t i = 0; i < 10; i++) {
    data[i] = i + 1;
    }
    EnterQueue(&quece, data, 2);
    display(&quece);
    EnterQueue(&quece, &data[2], 8);
    display(&quece);
    uint8_t getdata[10] = { 0 };
    LeaveQueue(&quece, getdata, 3);
    display(&quece);
    LeaveQueue(&quece, getdata, 7);
    display(&quece);
    EnterQueue(&quece, data, 5);
    display(&quece);
    return 0;
    }

在存取时会遇到top和rear重合的情况,如下示意图所示,因此上述方法中引入一个存储标志来解决取存中top和rear重合时为空或者为满的情况,当入队时遇到重合,则只可能为满,同理出队遇到重合为空
在这里插入图片描述

  • 直接用数组和指针实现方法

    #include <stdio.h>
    #include <stdlib.h>
    #include<stdint.h>
    #define BUFFER_LENGTH 2048
    typedef unsigned char BOOL;
    #define TRUE 1
    #define FALSE 0
    void FifoQueueInit();
    BOOL FifoQueueIsEmpty();
    BOOL FifoQueueIsFull();
    int GetFifoQueueSize();
    int GetFifoQueueSpace();
    int FifoQueueInster(unsigned char Datas[], int nSize);
    int FifoQueuePopup(unsigned char Datas[], int nSize);

    static unsigned char FifoQueueBuffer[BUFFER_LENGTH + 1]; // 存储队列
    static unsigned char* pFifoQueueHead = FifoQueueBuffer; // 头指针
    static unsigned char* pFifoQueueTail = FifoQueueBuffer; // 尾指针

    void FifoQueueInit() // 初始化队列
    {
    memset(FifoQueueBuffer, 0x00, BUFFER_LENGTH + 1);
    pFifoQueueHead = FifoQueueBuffer;
    pFifoQueueTail = FifoQueueBuffer;
    }

    BOOL FifoQueueIsEmpty()
    {
    // 头尾指针指向同一个位置,则队列为空
    return (pFifoQueueHead == pFifoQueueTail) ? TRUE : FALSE;
    }

    BOOL FifoQueueIsFull()
    {
    if (pFifoQueueTail == FifoQueueBuffer)
    { // 尾指针指向数组[0]位置
    return ((pFifoQueueHead - pFifoQueueTail) == BUFFER_LENGTH) ? TRUE : FALSE;
    }
    else
    { // 头执政在前,尾指针紧随其后
    return (pFifoQueueHead == pFifoQueueTail - 1) ? TRUE : FALSE;
    }
    }

    int GetFifoQueueSize() // 已存长度
    {
    if (pFifoQueueHead >= pFifoQueueTail)
    { // 头指针在前
    return pFifoQueueHead - pFifoQueueTail;
    }
    else
    { // 头指针在后
    return (BUFFER_LENGTH - (pFifoQueueTail - pFifoQueueHead - 1));
    }
    }

    int GetFifoQueueSpace() // 剩余可存空间
    {
    return (BUFFER_LENGTH - GetFifoQueueSize());
    }

    int FifoQueueInster(unsigned char Datas[], int nSize)
    {
    int n = 0; // 统计存入数据长度
    for (int i = 0; i < nSize; i++)
    {
    if (FifoQueueIsFull()) // 如果存储已满,停止存储
    {
    break;
    }
    (*pFifoQueueHead) = Datas[i];
    if (pFifoQueueHead == FifoQueueBuffer + BUFFER_LENGTH) {
    pFifoQueueHead = FifoQueueBuffer;
    }
    else {
    pFifoQueueHead++;
    }
    n++;
    }
    return n;
    }

    int FifoQueuePopup(unsigned char Datas[], int nSize)
    {
    int i = 0;
    int n = 0;
    for (i = 0; i < nSize; i++)
    {
    if (FifoQueueIsEmpty())
    {
    break;
    }
    Datas[i] = (*pFifoQueueTail);
    if (pFifoQueueTail == FifoQueueBuffer + BUFFER_LENGTH)
    {
    pFifoQueueTail = FifoQueueBuffer;
    }
    else
    {
    pFifoQueueTail++;
    }
    n++;
    }
    return n;
    }

5.3 队列 - 链表实现队列存储结构

  • 链式是实时申请空间,因此链式队列就不需要考虑空间利用的问题

  • 链表实现队列存储结构如下:

    #include <stdio.h>
    #include <stdlib.h>
    typedef struct QNode{
    int data;
    struct QNode * next;
    }QNode;
    QNode * initQueue(){
    QNode * queue = (QNode*)malloc(sizeof(QNode));
    queue->next = NULL;
    return queue;
    }
    QNode* enQueue(QNode * rear,int data){
    QNode * enElem = (QNode*)malloc(sizeof(QNode));
    enElem->data = data;
    enElem->next = NULL;
    // 使用尾插法向链队列中添加数据元素
    rear->next = enElem;
    rear = enElem;
    return rear;
    }
    QNode* DeQueue(QNode * top,QNode * rear){
    if (top->next == NULL) {
    printf("队列为空!!!
    “);
    return rear;
    }
    QNode * p = top->next;
    printf(”%d ", p->data);
    top->next = p->next;
    if (rear == p) {
    rear = top;
    }
    free§;
    return rear;
    }
    int main() {
    QNode * queue,*top,*rear;
    queue = top = rear = initQueue();// 创建头结点
    // 向链队列中添加结点,使用尾插法添加的同时,队尾指针需要指向链表的最后一个元素
    rear = enQueue(rear, 1);
    rear = enQueue(rear, 2);
    rear = enQueue(rear, 3);
    rear = enQueue(rear, 4);
    // 入队完成,所有数据元素开始出队列
    rear = DeQueue(top, rear);
    rear = DeQueue(top, rear);
    rear = DeQueue(top, rear);
    rear = DeQueue(top, rear);
    rear = DeQueue(top, rear);
    return 0;
    }


感谢阅读 若有错误 敬请见谅!!!


总结

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于 java开发 的学习思路及方向。从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。

由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的Gitee获取
还有 高级java全套视频教程 java进阶架构师 视频+资料+代码+面试题!

全方面的java进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值