新知识-Queue(FIFO)
FIFO:First in First out; 队列:先进先出
- 入队和出队。入队会向队列追加一个新元素,而出队会删除第一个元素,一个索引来指出起点。
代码:
/** ... 动态数组和指向起点的标志位*/
class MyQueue {
// store elements
private List<Integer> data;
//start sign
private int p_start;
public MyQueue() {
data = new ArrayList<Integer>();
p_start = 0;
}
/** 插入值,返回是否成功. */
public boolean enQueue(int x) {
data.add(x);
return true;
};
/** 删除. */
public boolean deQueue() {
if (isEmpty() == true) { /** 非空判断,空队列不能删除,返回false*/
return false;
}
p_start++; /*删除队首,指针后移*/
return true;
}
/** 队首. */
public int Front() {
return data.get(p_start);
}
/** 检查非空. */
public boolean isEmpty() {
return p_start >= data.size(); /*队首>=长度==0 队列为空*/
}
};
public class Main {
public static void main(String[] args) {
MyQueue q = new MyQueue(); /* ... 动态数组对象建立,起点位初始化*/
q.enQueue(5);
q.enQueue(3);
if (q.isEmpty() == false) {
System.out.println(q.Front()); /* FIFO*/
}
q.deQueue();
if (q.isEmpty() == false) {
System.out.println(q.Front());
}
q.deQueue();
if (q.isEmpty() == false) {
System.out.println(q.Front());
}
}
}
#include <iostream>
class MyQueue {
private:
// store elements
vector<int> data;
// a pointer to indicate the start position
int p_start;
public:
MyQueue() {p_start = 0;}
/** Insert an element into the queue. Return true if the operation is successful. */
bool enQueue(int x) {
data.push_back(x);
return true;
}
/** Delete an element from the queue. Return true if the operation is successful. */
bool deQueue() {
if (isEmpty()) {
return false;
}
p_start++;
return true;
};
/** Get the front item from the queue. */
int Front() {
return data[p_start];
};
/** Checks whether the queue is empty or not. */
bool isEmpty() {
return p_start >= data.size();
}
};
int main() {
MyQueue q;
q.enQueue(5);
q.enQueue(3);
if (!q.isEmpty()) {
cout << q.Front() << endl;
}
q.deQueue();
if (!q.isEmpty()) {
cout << q.Front() << endl;
}
q.deQueue();
if (!q.isEmpty()) {
cout << q.Front() << endl;
}
}
循环队列
-
基础实现非常的低效,当队列排队溢满时,我们要想继续
insert
则需要将队首delete
-
我们在这里引入双指针思路,在固定的数组中两个指针表示起始位置和结束位置,达到重用我们浪费的存储空间
-
头指针和尾指针之间实现循环的作用(
环形缓冲器
),利用先前使用的空间。 -
当front和Tail(头尾指针)都指向-1时,队列为空。
-
insert第一位时,front和Tail都向后移一位,指向0,后面insert非第一位时,Tail单独向后移动。
-
当Tail指向最后一位时,通过取余%位数或者==0,返回队首,完成循环,继续插入,当Tail移动到front前面时,队列满队。
-
通过front往后移动完成delete,当front移动到Tail前面时,frontTail-1完成清空。
-
自我实现代码:
后面有标准答案,自寻,学习的话建议先粗略看一下我的过程,发现一下我的哪一步需要完善,再去看标准答案,会有柳暗花明的感觉...反面教材来一手
class MyCircularQueue {
private int[] data;
private int front,tail;
public MyCircularQueue(int k) {
data = new int[k + 1]; /**-1位导致循环队列要比数值多一位 */
front = 0;
tail = 0;
}
public boolean enQueue(int value) {
if(isFull()){
return false;
}else{
data[tail] = value;
tail = (tail + 1) % data.length;
return true;
}
}
public boolean deQueue() {
if(isEmpty()){
return false;
}else{
front = (front + 1) % data.length;
return true;
}
}
public int Front() {
if(isEmpty()){
return -1;
}else{
return data[front];
}
}
public int Rear() {
if(isEmpty()){
return -1;
}else{
return data[(tail - 1 + data.length) % data.length];
}
}
public boolean isEmpty() {
if(front == tail){
return true;
}
return false;
}
public boolean isFull() {
if((tail + 1)%data.length == front){
return true;
}
return false;
}
}
-
实现循环列表错误记录:
-
判满的时候注意tail+1==front注意取余,不然会影响到enQueue,错误的判满导致错误的插入,
-
入列要判满,出列要判空,取队首尾先判空。
3.k+1好像这个思路可有可无
-
标准实现
class MyCircularQueue {
private int[] data;
private int head;
private int tail;
private int size;
public MyCircularQueue(int k) {
data = new int[k];
head = -1; /** ..-1起步,嗯这才是标准*/
tail = -1;
size = k; /** 存放数组大小,这个地方不知道干嘛,往后看...*/
}
public boolean enQueue(int value) {
if (isFull() == true) {
return false;
}
if (isEmpty() == true) { /**加了个判空,空意味着第一步,前面说了第一步先设0,没错*/
head = 0;
}
tail = (tail + 1) % size; //偷懒的,没事了
data[tail] = value;/**把tail设0放在了后面,就可以变成先移动指针再设值,嗐我怎么没想到*/
return true;
}
public boolean deQueue() {
if (isEmpty() == true) {
return false;
}
if (head == tail) { /**谨慎的加了个清空,先前说了头尾为-1为初始化状态*/
head = -1;
tail = -1;
return true; /**属于最后一步出列,return true*/
}
head = (head + 1) % size;
return true;
}
public int Front() {
if (isEmpty() == true) {
return -1;
}
return data[head];
}
public int Rear() {
if (isEmpty() == true) {
return -1;
}
return data[tail]; /**这个地方就可以省略那一大步了。。。*/
}
public boolean isEmpty() {
return head == -1;
}
public boolean isFull() {
return ((tail + 1) % size) == head; /**important*/
}
}
-
内置队列库实现:
public class Main { public static void main(String[] args) { Queue<Integer> q = new LinkedList(); /**LinkedList*/ System.out.println("The first element is: " + q.peek()); /*peek队首*/ //offer入列 q.offer(1); q.offer(2); q.offer(3); q.offer(123); //poll出列 q.poll(); // 队首 System.out.println("The first element is: " + q.peek()); // 队列长度size System.out.println("The size is: " + q.size()); } }