循环队列
Posted wx5add7776993de
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了循环队列相关的知识,希望对你有一定的参考价值。
队列是一种只允许在一端插入,一端删除的数据结构
其他数据结构实现队列
栈实现队列
双栈实现
这里的思路使用到双栈实现队列,因为栈的后入先出,所以用到了一个辅助栈在出栈时操作,所以
- 入队操作还是O(1)
- 但是出队则需要将栈中的元素遍历压入辅助栈,再弹出辅助栈的栈顶元素,所以是O(n)
public class MyQueueOfStack
/**
* <h>用栈实现队列</h>
* <li>push(x) -- 将一个元素放入队列的尾部。</li>
* <li>pop() -- 从队列首部移除元素。</li>
* <li>peek() -- 返回队列首部的元素。</li>
* <li>empty() -- 返回队列是否为空。</li>
*/
//基于两个栈实现一个队列
Stack<Integer> stack;
Stack<Integer> temp;
/**
* Initialize your data structure here.
*/
public MyQueueOfStack()
stack = new Stack<>();
temp = new Stack<>();
/**
* Push element x to the back of queue.
*/
public void push(int x)
stack.push(x);
/**
* Removes the element from in front of queue and returns that element.
*/
public int pop()
if (temp.isEmpty())
int size = stack.size();
for (int i = 0; i < size; i++)
int data = stack.pop();
temp.push(data);
return temp.pop();
/**
* Get the front element.
*/
public int peek()
if (temp.isEmpty())
int size = stack.size();
for (int i = 0; i < size; i++)
int data = stack.pop();
temp.push(data);
return temp.peek();
/**
* Returns whether the queue is empty.
*/
public boolean empty()
return temp.isEmpty() && stack.isEmpty();
双向链表实现队列
linkedList实现
链表首部出队,尾部入队实现:
public class MyQueueOfLinkedList
/**
* <h>用栈实现队列</h>
* <li>push(x) -- 将一个元素放入队列的尾部。</li>
* <li>pop() -- 从队列首部移除元素。</li>
* <li>peek() -- 返回队列首部的元素。</li>
* <li>empty() -- 返回队列是否为空。</li>
*/
//基于LinkedList实现队列
List<Integer> list;
/**
* Initialize your data structure here.
*/
public MyQueueOfLinkedList()
list = new LinkedList<>();
/**
* Push element x to the back of queue.
*/
public void push(int x)
list.add(x);
/**
* Removes the element from in front of queue and returns that element.
*/
public int pop()
return list.remove(0);
/**
* Get the front element.
*/
public int peek()
return list.get(0);
/**
* Returns whether the queue is empty.
*/
public boolean empty()
return list.isEmpty();
循环队列
循环队列:具有头指针和尾指针
- 头指针指向队列头部元素,随着元素出队而变化,元素入队时不变化
- 尾指针指向队列尾部元素,随着元素入队而变化,元素出队时不变化
在循环数组中,头指针head,尾指针tail按照下列规律变化
head = (head + 1) % array.length
tail = (tail + 1) % array.length
为何要对数组取模?
- 因为是基于数组实现的一个循环队列,我们希望,能在有限的数组空间中尽可能的存储我们的队列元素,+1后对数组长度取模,其实就相当于求出了经过一次循环后的下标
循环队列特性
- 循环队列只能在队列头部删除元素,队列尾部插入元素
- 也是符合先进先出原则
为何要使用循环队列?
- 相比数组实现的普通队列,循环队列在删除或者新增元素后,只需要移动指针,而不需要移动数组中的元素
- 读取时的时间复杂度为O(1)。
- 插入、删除时的时间复杂度为O(1)
插入删除过程演示:
插入:
前:
后:
删除:
前:
后:
实现
public class MyCircularQueue
/**
* 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
* <p>
* 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
* <p>
* 你的实现应该支持如下操作:
* <p>
* MyCircularQueue(k): 构造器,设置队列长度为 k 。
* Front: 从队首获取元素。如果队列为空,返回 -1 。
* Rear: 获取队尾元素。如果队列为空,返回 -1 。
* enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
* deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
* isEmpty(): 检查循环队列是否为空。
* isFull(): 检查循环队列是否已满。
* <p>
* 示例:
* <p>
* MyCircularQueue circularQueue = new MycircularQueue(3); // 设置长度为 3
* circularQueue.enQueue(1); // 返回 true
* circularQueue.enQueue(2); // 返回 true
* circularQueue.enQueue(3); // 返回 true
* circularQueue.enQueue(4); // 返回 false,队列已满
* circularQueue.Rear(); // 返回 3
* circularQueue.isFull(); // 返回 true
* circularQueue.deQueue(); // 返回 true
* circularQueue.enQueue(4); // 返回 true
* circularQueue.Rear(); // 返回 4
*/
//数组实现循环队列
Integer[] list;
//头指针 -- 指向队列头部
int head;
//尾指针 -- 指向队列尾部
int tail;
//数组元素个数
// int size;
/**
* Initialize your data structure here. Set the size of the queue to be k.
*/
public MyCircularQueue(int k)
list = new Integer[k];
//初始化循环队列时,头指针和尾指针都指向同一处
head = 0;
tail = 0;
//size = 0;
/**
* Insert an element into the circular queue. Return true if the operation is successful.
*/
public boolean enQueue(int value)
if (isFull())
return false;
else
list[tail] = value;
//为什么需要取模? ---> 因为要实现在数组中循环,对+1后数组长度取模,就相当于求出了经过一次循环后的下标
//新的尾坐标
tail = (tail + 1) % list.length;
return true;
/**
* Delete an element from the circular queue. Return true if the operation is successful.
*/
public boolean deQueue()
if (isEmpty())
return false;
else
list[head] = null;
head = (head + 1) % list.length;
return true;
/**
* Get the front item from the queue.
*/
public int Front()
return isEmpty() == true ? -1 : list[head];
/**
* Get the last item from the queue.
*/
public int Rear()
if (isEmpty())
return -1;
else
if (tail != 0)
//循环队列未满
return list[tail - 1];
else
//循环队列已满
return list[list.length - 1];
/**
* Checks whether the circular queue is empty or not.
* 循环队列为空 ---> 如果头指针和尾指针指向同一处 && 头指针指向元素为空
*/
public boolean isEmpty()
if (head == tail && list[head] == null)
return true;
else
return false;
/**
* Checks whether the circular queue is full or not.
* 循环队列已满 ---> 如果头指针和尾指针指向同一处 && 头指针指向元素不为空
*/
public boolean isFull()
if (head == tail && list[head] != null)
return true;
else
return false;
以上是关于循环队列的主要内容,如果未能解决你的问题,请参考以下文章