下题目为个人的刷题记录,在本节博客中我将详细谈论设计循环队列的思路,并给出代码,有需要借鉴即可。
题目:LINK
循环队列是线性表吗?或者说循环队列是线性结构吗?
对于这个问题,我们来看一下线性结构的定义:
因为循环队列结点个数为k个,且具有逻辑结构性,因此属于一种特殊的线性结构。
下面是思路分析:
首先一开始收到实现普通队列的思路影响+上题目中循环这俩字,那自然想到的是用链表来设计循环队列。
于是,为了便于分析我作了下面的草图:
现在我们一开始迎来了第一个问题:我们的头指针和尾指针初始化放到哪里?
为了解决这个问题,我想到了第一个方法:初始化头指针尾指针置为空
这个方法看似很好,但是结合一下我们要实现的接口,判空时候需要做特殊处理,其实并不是很好。
然后我又想到,那让他们一开始直接都指向第一个结点
我们继续往下想,如果这样做的化,还是那个问题,如何区分空队列与一个结点的情况?
那么为了解决这个区分问题,我们可以引入size来统计结点个数
不过这里还有个问题,如果front与rear初始化指向第一个结点,然后引入size来区分结点个数的话,我们发现rear是指向尾结点的后一个结点的,也就是说我们在搞取尾接口的时候并不好操作,因为这是单向链表。
那为了解决取尾接口问题,我们要把单链表改成双向链表。
但是这样一来,工作量就要变大很多,并不是很好的选择。
所以,不妨我们来用一下数组:
1.为了解决两个指针一开始都指向第一个空间特殊处理的问题,所以我们选择rear指向尾结点的后一个结点
2.为了解决不好判断的问题,我们多开一个空间,用rear+1 == front 为满的条件
3.为了解决数组循环问题,我们可以取模下面是示例代码:
typedef struct { int front;//头元素 int rear;//尾元素的下一个 int* arr;//数组指针 int k; } 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; } } //构造器,设置队列长度为 k MyCircularQueue* myCircularQueueCreate(int k) { //首先创造出一个MyCircularQueue结构体,为方便操作数组做铺垫 MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue)); //数组空间申请+初始化结构体 obj->arr = (int*)malloc((k+1)*sizeof(int)); obj->k = k; obj->front = obj->rear = 0; //返回结构体指针 return obj; } //向循环队列插入一个元素。如果成功插入则返回真 bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { //满了 if(myCircularQueueIsFull(obj)) { return false; } else//没满 { obj->arr[obj->rear++] = value;//放入数据并移动尾指针 obj->rear = obj->rear % (obj->k+1);//循环 return true; } } //从循环队列中删除一个元素。如果成功删除则返回真 bool myCircularQueueDeQueue(MyCircularQueue* obj) { //空的 if(myCircularQueueIsEmpty(obj)) { return false; } else//非空 { obj->front++; obj->front %= (obj->k+1); return true; } } //从队首获取元素。如果队列为空,返回 -1 int myCircularQueueFront(MyCircularQueue* obj) { if(myCircularQueueIsEmpty(obj))//为空 { return -1; } else//非空 { return obj->arr[obj->front]; } } //获取队尾元素。如果队列为空,返回 -1 int myCircularQueueRear(MyCircularQueue* obj) { if(myCircularQueueIsEmpty(obj))//为空 { return -1; } else { int prear = ((obj->rear + obj->k)%(obj->k+1)); return obj->arr[prear]; } } void myCircularQueueFree(MyCircularQueue* obj) { free(obj->arr); free(obj); } /** * Your MyCircularQueue struct will be instantiated and called as such: * MyCircularQueue* obj = myCircularQueueCreate(k); * bool param_1 = myCircularQueueEnQueue(obj, value); * bool param_2 = myCircularQueueDeQueue(obj); * int param_3 = myCircularQueueFront(obj); * int param_4 = myCircularQueueRear(obj); * bool param_5 = myCircularQueueIsEmpty(obj); * bool param_6 = myCircularQueueIsFull(obj); * myCircularQueueFree(obj); */
完。