题目:
代码:
#include<iostream>
using namespace std;
typedef struct SList
{
int* data;
int n;//空间个数,注意实际放的元素个数是n-1个
int front;
int rear;
}SL;
SL* SListCreate(int n)
{
SL* p = (SL*)malloc(sizeof(SL));
p->n = n;
p->data = (int*)malloc(sizeof(int)*n);
p->front = 0;
p->rear = 0;
return p;
}
bool IsQueueFull(SL* ps)//判断队列是否为满
{
if ((ps->rear + 1) % ps->n == ps->front)//队列为满的判断条件
return true;
else
return false;
}
bool IsQueueEmpty(SL* ps)//判断队列是否为空
{
if (ps->rear == ps->front)
return true;
else
return false;
}
void SListOperation(SL* ps)
{
char a[5] = { 0 };//用第一个字符判断是入队操作还是出队操作
cin >> a;
if (a[0] == 'i')
{
//说明要入队
int val;
cin >> val;
if (!IsQueueFull(ps))//入队前先判满
{
ps->data[ps->rear] = val;
ps->rear++;
ps->rear = (ps->rear) % (ps->n);//防止越界
}
}
else if(a[0] == 'o')
{
//说明要出队
if (!IsQueueEmpty(ps))//入队前先判空
{
ps->front++;
ps->front = (ps->front) % (ps->n);//防止越界
}
}
}
void SListPrint(SL* ps)//剩下队列元素的打印
{
while (ps->front != ps->rear)
{
printf("%d ", ps->data[ps->front]);
ps->front++;
ps->front = (ps->front) % (ps->n);
}
}
int main()
{
int n = 0;
cin >> n;
SL* ret = SListCreate(n);
int k = 0;
cin >> k;
while (k)
{
SListOperation(ret);
k--;
}
SListPrint(ret);
return 0;
}
622. 设计循环队列 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/design-circular-queue/
用数组的方式实现循环队列:
typedef struct
{
int* a;
int k;//队列长度为k
int front;//头的下标
int rear;//尾的下标
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
if(obj->front==obj->rear)
return true;
else
return false;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
if((obj->rear+1)%(obj->k+1)==obj->front)
return true;
else
return false;
}
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//先给结构体开空间
q->a=(int*)malloc(sizeof(int)*(k+1));//开k+1个数组空间
q->front=q->rear=0;//给front和rear赋初值0
q->k=k;
return q;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
{
return false;
}
else
{
obj->a[obj->rear]=value;
obj->rear++;
obj->rear=obj->rear%(obj->k+1);//防止tail越界
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
else
{
obj->front++;
obj->front=obj->front%(obj->k+1);
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj)
{
//这一步非常容易忽略,但是题干中也有明确地提示到
if(myCircularQueueIsEmpty(obj))
return -1;
else
{
return obj->a[obj->front];
}
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
else
{
//return obj->a[obj->rear-1];//第一直觉的写法,思考这里有什么问题
int i=(obj->rear+obj->k)%(obj->k+1);
return obj->a[i];
}
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->a);//应当先将a这块开辟的空间free掉,也很容易忽略
free(obj);//再free掉这个结构体空间
}
typedef struct
{
int* a;
int k;//队列长度为k
int front;//头的下标
int rear;//尾的下标
} MyCircularQueue;
·第二步
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//先给结构体开空间
q->a=(int*)malloc(sizeof(int)*(k+1));//开k+1个数组空间
q->front=q->rear=0;//给front和rear赋初值0
q->k=k;
return q;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
if(obj->front==obj->rear)
return true;
else
return false;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
if((obj->rear+1)%(obj->k+1)==obj->front)
return true;
else
return false;
}
·第三步:实现完判空和判满接下来我们就需要来写一写入队和出队的接口了。
依旧通过具体的例子来看看:
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
{
return false;
}
else
{
obj->a[obj->rear]=value;
obj->rear++;
obj->rear=obj->rear%(obj->k+1);//防止tail越界
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
else
{
obj->front++;
obj->front=obj->front%(obj->k+1);
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj)
{
//这一步非常容易忽略,但是题干中也有明确地提示到
if(myCircularQueueIsEmpty(obj))
return -1;
else
{
return obj->a[obj->front];
}
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
else
{
//return obj->a[obj->rear-1];//第一直觉的写法,思考这里有什么问题
int i=(obj->rear+obj->k)%(obj->k+1);
return obj->a[i];
}
}
用链表的方式实现循环队列:
首先还是先来看看代码:
typedef struct SList
{
int data;
struct SList* next;
}SL;
typedef struct
{
int k;
SL* front;
SL* rear;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
SL* cur=(SL*)malloc(sizeof(SL));
q->k=k;
q->front=cur;
q->rear=cur;
while(k)
{
SL* newnode=(SL*)malloc(sizeof(SL));//开辟一个新节点
cur->next=newnode;
cur=newnode;
cur->next=q->front;
k--;
}//在入队出队之前首先要把空间所有的节点都开辟好,只是不存放有效数据而已
return q;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
if(obj->front==obj->rear)
return true;
else
return false;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
if(obj->rear->next==obj->front)
return true;
else
return false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
return false;
else
{
obj->rear->data=value;
obj->rear=obj->rear->next;
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
else
{
obj->front=obj->front->next;
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->front->data;
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
else
{
SL* prev=obj->front;
while(prev->next!=obj->rear)
{
prev=prev->next;
}
return prev->data;
}
}
void myCircularQueueFree(MyCircularQueue* obj)
{
while(obj->front!=obj->rear)
{
SL* cur=obj->front->next;
free(obj->front);
obj->front=cur;
}
free(obj->front);
free(obj);
}
最后看完循环队列的两道OJ题后,就在想为什么会有大佬弄出循环队列这个东西,比较好奇其中的原理和设计者的设计目的,所以去查阅了一下相关的大神博客关于循环队列的文章。
循环队列是队列的一种顺序存储结构。循环队列的引入,目的是为了克服假溢出时大量移动数据元素 。
循环队列的优点是相对于直线队列来讲的,直线队列在元素出队后,头指针向后移动,导致删除元素后的空间无法在利用,即使元素个数小于空间大小,依然无法再进行插入,即所谓的“假上溢”。 当变成循环队列之后,删除元素后的空间仍然可以利用,最大限度的利用空间。
1、循环队列的优点:
可以有效的利用资源。用数组实现队列时,如果不移动,随着数据的不断读写,会出现假满队列的情况。即尾数组已满但头数组还是空的;循环队列也是一种数组,只是它在逻辑上把数组的头和尾相连,形成循环队列,当数组尾满的时候,要判断数组头是否为空,不为空继续存放数据。
2、循环队列的缺点:
循环队列中,由于入队时尾指针向前追赶头指针;出队时头指针向前追赶尾指针,造成队空和队满时头尾指针均相等。因此,无法通过条件front==rear来判别队列是"空"是"满"。
3、拓展知识:
为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列。