0%

数据结构:循环队列

循环队列

https://leetcode-cn.com/explore/learn/card/queue-stack/216/queue-first-in-first-out-data-structure/

leetcode这里有关于循环队列的所有细节和动画描述,这里我就不再赘述了,更多讲讲代码的东西吧。

代码实现

用了LeetCode上面的那道题目,自己花了点时间瞎写了一个循环队列。

先贴上题目的要求:

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。

  • Front: 从队首获取元素。如果队列为空,返回 -1 。

  • Rear: 获取队尾元素。如果队列为空,返回 -1 。

  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

  • isEmpty(): 检查循环队列是否为空。

  • isFull(): 检查循环队列是否已满。

先贴上代码再说注意事项吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class MyCircularQueue {
private:
int* s;
int len,front,rear;
public:
/** Initialize your data structure here. Set the size of the queue to be k. */
MyCircularQueue(int k) {
s=new int[k+10];
len=k+1;
front=rear=0;
}

/** Insert an element into the circular queue. Return true if the operation is successful. */
bool enQueue(int value) {
if(isFull())
return false;
s[rear]=value;
rear=(rear+1)%len;
return true;
}

/** Delete an element from the circular queue. Return true if the operation is successful. */
bool deQueue() {
if(isEmpty())
return false;
front=(front+1)%len;
return true;
}

/** Get the front item from the queue. */
int Front() {
if(isEmpty())
return -1;
else
return s[front];
}

/** Get the last item from the queue. */
int Rear() {
if(isEmpty())
return -1;
else
return rear==0?s[len-1]:s[(rear-1)%len];
}

/** Checks whether the circular queue is empty or not. */
bool isEmpty() {
if(rear==front)
return true;
else
return false;
}

/** Checks whether the circular queue is full or not. */
bool isFull() {
if((rear+1)%len==front)
return true;
else
return false;
}
};

/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue obj = new MyCircularQueue(k);
* bool param_1 = obj.enQueue(value);
* bool param_2 = obj.deQueue();
* int param_3 = obj.Front();
* int param_4 = obj.Rear();
* bool param_5 = obj.isEmpty();
* bool param_6 = obj.isFull();
*/

我们可以看到并不难实现循环队列,主要的注意事项是很多人喜欢先写入队出队再去写判空判满的代码。。。然后惊讶地发现其实前面的出队入队可以直接调用后面的isEmpty()和isFull()2333。

所以建议自己实现数据结构的时候先把判断空和慢的代码先码出来再去实现其他功能,这样就可以省下很多的时间和无效的代码。

还有一个注意点就是rear指针(就是队尾指针)的设定是指空的(也就是先把值放到rear所指的区域然后再让rear往前走),但是front指针我设定是直接指向队头元素(因为没必要给它也指个其他元素吧。。。),所以这两个指针的模式是不一样的。front函数直接取值就行(front指向队头元素),但是rear函数需要做一个转换,取出它所指向位置-1的位置的值(当然如果你直接把rear退回去算我输,那下次入队就凉了),如果rear指向0的位置,那我们需要手动转换为最后一个位置(因为数组没有负一位置),也就是下面这行代码的作用

1
return rear==0?s[len-1]:s[(rear-1)%len];

希望大家能在无聊的理论考试后通过实际的代码巩固数据结构知识,比较会敲代码才是王道。。。