首页 > 其他分享 >数据结构之环形队列

数据结构之环形队列

时间:2023-05-29 19:32:24浏览次数:48  
标签:head return 队列 环形 tail obj 数据结构

@TOC



一.环形队列的定义及其特点

循环队列是一种线性数据结构,其操作依然是先进先出原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

特点:

对于一个普通队列来说,每出队一次,头指针就必须往后移一位,这样使用过的空间就无法再重复使用,(头指针无法回移),即使队列元素小于队列大小,也无济于事,造成空间的浪费。

而对于循环队列来说,可以重复利用使用过的空间。解决了普通队列的问题。

基于循环队列的特点:我们可以使用数组或者循环链表来实现循环队列。

使用数组实现的话,尾指针到数组的大小时,回溯到头位置即可。

在这里给出一道题来实现环形队列。数据

二.使用数组来实现环形队列

首先,需要了解清楚的一件事是:如何判断环形队列的数据是否为空或者是否满了?

假如创建一个大小为4的环形队列,判断环形队列是否为空很简单,如果头指针和尾指针相等,则队列是空的,因为如果插入数据,尾指针一定往后移动。

环形队列插满数据是这样的:

数据结构之环形队列_数据

此时头指针和尾指针指向的位置也是相同的!

所以当队列满队的时候无法区分是队空还是队满。

解决办法:

假如环形队列大小是k,我们就创建k+1大小的环形队列。

数据结构之环形队列_数据_02

只需判断 (tail+1)%(k+1)是否等于head 即可。

1.创建一个队列

解读:对于普通队列来说,需要头指针和尾指针来维护入队和出队操作,入队时尾指针后移,出队时头指针后移。在环形队列中也是如此。

以下代码中的head和front是一样的。

typedef struct 
{
    int*a;
    int head;//队头
    int tail;//队尾,指向插入元素的下一个
    int k; //环形队列大小
} MyCircularQueue;

2.初始化队列

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue*p = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    assert(p);
    p->a = (int*)malloc(sizeof(int)*(k+1));
    p->head = p->tail = 0;
    p->k = k; //环形队列大小
    return p;
}

开辟两块空间,一块空间是结构体的空间,一块空间是结构体的数组的空间。

数据结构之环形队列_数组_03

3. 判断环形队列是否为空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->head == obj->tail;
}

解读:环形队列是否为空就是判断头指针和尾指针是否相等,如果相等整个环形队列就为空,如果是其他情况,则环形队列至少有一个以上的数据。

4.判断环形队列是否已满

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if((obj->tail+1)%(obj->k+1) ==obj->head)
    {
        return true;
    }
    return false;
}

判断环形队列是否已满,就是判断tail+1是否等于head,如果

5. 向循环队列插入元素,插入成功返回真

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        //满了
        return false;
    }
    obj->a[obj->tail] =value;
    //考虑特殊情况,如果插入之后tail是在外面,应该让tail回到0位置
    if(obj->tail+1 == obj->k+1) 
    {
        obj->tail = 0;
    }  
    else
    {
        ++obj->tail;
    }
    //也可以这样写
    // ++obj->tail;
    // obj->tail%=(obj->k+1);
    return true;
}

数据结构之环形队列_数据_04

解读:

  1. 这里应该考虑的一种特殊情况是,假如插入的数据在环形队列的末尾,尾指针应该指向下一个位置,此时走出了数组的范围,所以需要回到数组0位置。2.如果环形队列满了,则不能再插入了。

6.删除环形链表的数据

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    //也是考虑特殊情况,如果删除后head在队列外面,则应让head回到0位置
    if(obj->head+1 == obj->k+1)
    {
        obj->head = 0;
    }
    else
    {
        ++obj->head;
    }
    //也可以这样写
    // ++obj->head;
    // obj->head%=obj->k+1;
    return true;
}
解读:
需要考虑特殊情况:特殊情况如下图:

数据结构之环形队列_环形队列_05

7. 取队头元素

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->head];
}

8.取队尾元素

int myCircularQueueRear(MyCircularQueue* obj) {
    //取队尾元素有特殊情况,如果tail在0位置,那么需要返回
    //它的前一个,也就是第k个
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    if(obj->tail == 0)
    {
        return obj->a[obj->k];
    }
    else
    {
        return obj->a[obj->tail-1];
    }
    //也可以这样写
    //return (obj->tail+obj->k)%(obj->k+1);
}

取队尾元素有一种特殊情况:

数据结构之环形队列_数组_06

假如tail是在0位置,取队尾元素之后,tail需要回退到上一个位置,即k+1位置处。

8.释放空间

void myCircularQueueFree(MyCircularQueue* obj) {
    //注意结构体有两层,需要先释放内层
    free(obj->a);
    obj->a = NULL;
    free(obj);
}

总结

环形队列在普通队列的基础上优化了空间重复利用问题,使空间利用率更高。实际生活中使用队列的问题还是有很多的,比如营业厅,医院,银行的自动排队出票的机子,也是通过队列的先进先出的特点来实现的。

标签:head,return,队列,环形,tail,obj,数据结构
From: https://blog.51cto.com/u_15818575/6373679

相关文章

  • hdu 5102(队列+节点扩展)
    TheK-thDistanceTimeLimit:8000/4000MS(Java/Others)    MemoryLimit:65536/65536K(Java/Others)ProblemDescriptionGivenatree,whichhasnnodeintotal.Definethedistancebetweentwonodeuandvisthenumberofedgeontheirunique......
  • 关于消息队列的一些思考
    日志与消费队列消息队列的应用价值数据集成于系统解耦异步处理与事件驱动流量削峰事务消息与分布式事务的最终一致从历史看消息队列的价值演化思考手上的工作,找到他的价值和定位,将价值最大化1.日志和消息队列推荐文章:TheLog:Whateverysoftwareengineershou......
  • 什么是数据结构中的特殊矩阵和稀疏矩阵
    在数据结构中,特殊矩阵和稀疏矩阵是描述矩阵中元素分布特点的两个概念。特殊矩阵(SpecialMatrix)是指具有一定规律和特殊性质的矩阵,其中大部分元素具有相同的值或者具有特定的规律。特殊矩阵的特点在于其元素之间存在一种明显的关联关系,可以利用这种关系来进行高效的存储和操作。......
  • 描述图的两种数据结构 - 邻接表和邻接矩阵
    图的邻接表和邻接矩阵是两种常用的表示图的数据结构,用于描述图中各个顶点之间的连接关系。图是由一组顶点和一组边组成的数据结构,顶点表示图中的对象,边表示对象之间的关系。邻接表和邻接矩阵都可以有效地表示图的结构,并提供了不同的优势和适用场景。邻接表:邻接表是一种链表的......
  • Disruptor内存消息队列简单使用
    Disruptor内存消息队列最近在做一个有关使用内存消息队列到功能,比如将日志信息或点击统计信息持久化等操作,开始想着用java到内存队列作为缓冲区,后来在网上搜到Disruptor这个东西,神乎其神到,就简单了解了一下,做了一个demo,感觉还不错,可以用用,有关概念可以自行搜索,下面就简单介绍一下开......
  • 数据结构与算法
    @目录数据结构与算法图解:算法——排序普通(简单)排序冒泡算法选择排序插入排序希尔排序堆排序递归排序归并排序快速排序分布式排序计数排序桶排序基数排序算法——搜索顺序搜索(线性搜索)有序搜索二分搜索插值搜索斐波那契搜索索引搜索(分块搜索)树搜索哈希搜索算法——随机算法算法设......
  • 初级数据结构--线性表
    线性表定义线性表是具有相同数据类型n(n>=0)个数据元素的有限序列。当n=0时线性表为一个空表。顺序表实现方式:动态分配、静态分配特点:随机访问储存密度高扩展容量不方便插入删除数据元素不方便......
  • 第三章 基本数据结构
    3.1线性数据结构一旦某个元素被添加进来,它与前后元素的相对位置将保持不变3.2栈3.3.1什么是栈添加和删除操作总发生在同一端,即顶端,另一端称为底端。元素添加顺序:后进先出。应用:点击返回按钮,反向浏览网页。......
  • 《数据结构与算法》之栈结构
    导言:在计算机发明之初是为了计算,所以叫计算机,对我们给定的一个算式,然后给定的一套规则加,减,乘,除,等,它就可以自己进行计算了,然后返回一个结果给我们对于一般的算式:2+3+4很显然,从左往右依次扫描,依次相加很简单的计算出来,因为它们是同级运算,可以很简单的做到但是,常见的运算不只......
  • 数据结构与算法脉络总结
    目录一、数据结构1.链表2.栈3.队列4.散列表5.集合6.字典树7.堆8.优先队列9.并查集二、算法1.排序2.字符串3.图论4.贪心5.动态规划6.其他:分治、二分查找、双指针、多路归并一、数据结构1.链表2.栈3.队列4.散列表5.集合6.字典树7.堆8.优先队列9.......