0
点赞
收藏
分享

微信扫一扫

数据结构之SWUSTOJ965循环队列and Leetcode622设计循环队列。对循环队列的一点思考。(数组和链表两种方式实现循环队列)

题目:

代码:

#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、拓展知识:
  为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列。

举报

相关推荐

0 条评论