栈和队列----循环队列详解

栈和队列----循环队列详解

循环队列的结构分析

例题:循环队列OJ

循环队列的概念

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

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

循环队列的特点

1.循环队列的大小是固定的

2.符合队列的先进先出

循环队列的不同实现:

循环队列可以用数组实现,也可以用链表实现。两种实现都差不太多,在结构方面有些不同。

队列也可以用数组实现,只是会产生假溢出问题,实现出来的性能不高,数组实现的循环队列解决了假溢出的问题,性能略高于链表实现的循环队列

用链表实现的循环队列,其实就是一个循环的单链表,只是增加了队列的先进先出的特性,已及大小固定

在这里插入图片描述

数组结构的循环队列

思路导图

在这里插入图片描述

代码

typedef struct {
    int* arr;
    //定义头指针和尾指针
    //头指针就是当前元素的下标
    //尾指针是尾元素的下一个位置的下标
    int head;
    int tail;
    int k;
} MyCircularQueue;
//判空和判满函数在最后面,声明一下,方便使用
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);

//初始化,循环队列的空间是固定大小的
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->arr=(int*)malloc(sizeof(int)*(k+1));
    obj->head=obj->tail=0;
    obj->k=k;
    return obj;
}
//向循环队列中增加元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    //增加元素后,尾指针tail要一道尾元素的下一个位置
    //要是尾元素在最后,tail就要循环到首元素的位置,所以得取模
    obj->arr[obj->tail]=value;
    obj->tail=(obj->tail+1)%(obj->k+1);
    return true;
}
//删除循环队列中的元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    //移动头指针就是删除元素了
    //也要考虑极端情况
    obj->head=(obj->head+1)%(obj->k+1);
    return true;
}
//获取头部元素
int myCircularQueueFront(MyCircularQueue* obj) {
    //判空
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->arr[obj->head];
}
//获取尾部元素
int myCircularQueueRear(MyCircularQueue* obj) {
    //判空
    if(myCircularQueueIsEmpty(obj))
        return -1;
    //极端情况,当tail在首元素的位置时,取尾元素就要到下标为元素个数的位置取
    //将tail加上元素个数,再模队列的长度就是尾元素的下标了
    int i=(obj->tail+obj->k)%(obj->k+1);
    return obj->arr[i];
}
//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    return obj->head==obj->tail;
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    return obj->head==(obj->tail+1)%(obj->k+1);
}
//销毁
void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
}

链表结构的循环队列

思路导图

在这里插入图片描述

代码

typedef struct Node
{	//定义存储数据的结点结构体
    int data;
    struct Node* next;
}Node;

typedef struct {
    //头指针和尾指针
    Node*head;
    Node*tail;
    //队列长
    int k;
    //计数器
    int sz;
} MyCircularQueue;
//判空,判满的声明
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);
//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->k=k;
    obj->sz=0;
    obj->head=obj->tail=NULL;
    return obj;
}
//向循环队列中增加元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    Node*newnode=(Node*)malloc(sizeof(Node));
    assert(newnode);
    newnode->data=value;
    newnode->next=NULL;
    if(myCircularQueueIsEmpty(obj))
        {   
            obj->head=obj->tail=newnode;
            obj->sz++;
        }
    else
        {
            obj->tail->next=newnode;
            obj->tail=newnode;
            obj->sz++;
        }
    return true;
}
//删除循环队列中的元素,删除后需销毁动态内存
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    Node*next=obj->head->next;
    free(obj->head);
    obj->head=next;
    obj->sz--;
    return true;
}
//返回循环队列的队头
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->head->data;
}
//返回循环队列的队尾
int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->tail->data;
}
//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    return obj->sz==0;
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    return obj->sz>=obj->k;
}
//销毁动态内存,要用循环将结点一个一个销毁
void myCircularQueueFree(MyCircularQueue* obj) {
    Node*cur=obj->head;
    while(cur)
    {
        Node*next=cur->next;
        free(cur);
        cur=next;
    }
    free(obj);
}

总结

初次看循环队列的时候有点懵,没咋理解,后来又返回去看了一遍,这下全看懂了。相对来说,数组实现的循环队列比链表实现的循环队列要难点,就是那个循环点那儿得小心分析,不然就掉坑里了。链表实现循环队列感觉就是写循环单链表的感觉。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值