什么是队列(Queue)???——》是一种线性存储结构,也就是存储数据的存储结构;但是注意啦!!!——》不是数据结构;
那么队列有什么特点???——》
- 队列中数据是按照"先进先出(FIFO, First-In-First-Out)或后进后出"方式进出队列的;
- 队列只允许在"队首"进行删除操作,而在"队尾"进行插入操作;
讲完了特点,那就到队列的基本操作啦!!!——》入队和出队
接着我就在下面把基本操作用图文解释下:
1、队列的示意图
队列中有10,20,30共3个数据。
2、出队列
出队列前:队首是10,队尾是30。
出队列后:出队列(队首)之后。队首是20,队尾是30。
3、入队列
入队列前:队首是20,队尾是30。
入队列后:40入队列(队尾)之后。队首是20,队尾是40。
代码实现有两种方式:
1、数组实现的队列,能存储任意类型的数据
2、运用Java的Collection集合中的自带"队列"(LinkedList)
1、数组实现的队列,能存储任意类型的数据
/**
* Java : 数组实现“队列”,只能存储int数据。
*
* @author skywang
* @date 2013/11/07
*/
public class ArrayQueue {
private int[] mArray;
private int mCount;
public ArrayQueue(int sz) {
mArray = new int[sz];
mCount = 0;
}
// 将val添加到队列的末尾
public void add(int val) {
mArray[mCount++] = val;
}
// 返回“队列开头元素”
public int front() {
return mArray[0];
}
// 返回“栈顶元素值”,并删除“栈顶元素”
public int pop() {
int ret = mArray[0];
mCount--;
for (int i=1; i<=mCount; i++)
mArray[i-1] = mArray[i];
return ret;
}
// 返回“栈”的大小
public int size() {
return mCount;
}
// 返回“栈”是否为空
public boolean isEmpty() {
return size()==0;
}
public static void main(String[] args) {
int tmp=0;
ArrayQueue astack = new ArrayQueue(12);
// 将10, 20, 30 依次推入栈中
astack.add(10);
astack.add(20);
astack.add(30);
// 将“栈顶元素”赋值给tmp,并删除“栈顶元素”
tmp = astack.pop();
System.out.printf("tmp=%d\n", tmp);
// 只将“栈顶”赋值给tmp,不删除该元素.
tmp = astack.front();
System.out.printf("tmp=%d\n", tmp);
astack.add(40);
System.out.printf("isEmpty()=%b\n", astack.isEmpty());
System.out.printf("size()=%d\n", astack.size());
while (!astack.isEmpty()) {
System.out.printf("size()=%d\n", astack.pop());
}
}
}
2、Java的 Collection集合 中自带的"队列"(LinkedList)的示例
import java.util.Stack;
/**
* 用“栈”实现队列
*
* @author skywang
*/
public class StackList<T> {
// 向队列添加数据时:(01) 将“已有的全部数据”都移到mIn中。 (02) 将“新添加的数据”添加到mIn中。
private Stack<T> mIn = null;
// 从队列获取元素时:(01) 将“已有的全部数据”都移到mOut中。(02) 返回并删除mOut栈顶元素。
private Stack<T> mOut = null;
// 统计计数
private int mCount = 0;
public StackList() {
mIn = new Stack<T>();
mOut = new Stack<T>();
mCount = 0;
}
private void add(T t) {
// 将“已有的全部数据”都移到mIn中
while (!mOut.empty())
mIn.push(mOut.pop());
// 将“新添加的数据”添加到mIn中
mIn.push(t);
// 统计数+1
mCount++;
}
private T get() {
// 将“已有的全部数据”都移到mOut中
while (!mIn.empty())
mOut.push(mIn.pop());
// 统计数-1
mCount--;
// 返回并删除mOut栈顶元素
return mOut.pop();
}
private int size() {
return mCount;
}
private boolean isEmpty() {
return mCount==0;
}
public static void main(String[] args) {
StackList slist = new StackList();
// 将10, 20, 30 依次推入栈中
slist.add(10);
slist.add(20);
slist.add(30);
System.out.printf("isEmpty()=%b\n", slist.isEmpty());
System.out.printf("size()=%d\n", slist.size());
while(!slist.isEmpty()) {
System.out.printf("%d\n", slist.get());
}
}
}
测试结果
tmp=10
tmp=20
isEmpty()=false
size()=3
tmp=20
tmp=30
tmp=40
顺序队列需要分配一块地址连续的存储区域来依次存放队列中从队首到队尾的所有元素;但是这样就会频繁出现“假溢出”;
什么是“假溢出”???——》也就是因顺序队列的多次入队和出队操作后出现有存储空间,但是不能进行入队操作的溢出现象;
——》通俗点讲,也就是出现顺序队列数组的头部有空的存储空间,而队尾却因数组下标越界而引发的假溢出现象;
那么怎么解决这个问题???——》最好的办法就是把顺序队列所使用的存储空间看成是一个逻辑上首尾相连的循环队列;
那怎么看???——》也就是利用Java语言中对整数数据求模(或取余)运算来实现,即令rear = (rear+1)% maxsizse;
虽然解决了假溢出现象;但是,这不就变成了循环队列了吗???那么我们如何使用代码来辨别循环顺序队列的队空和队满呢???——》其实有三种方式:
1、少用一个存储单元???——》但就是只允许最多放进maxSize-1个数据;
——》所以判断为空的依据是from==rear;而判断为满的依据是front == (rear+1)%maxSizs;
2、设置一个计数器???——》引进一个计数变量,其初始值置为0;每当入队操作成功后,计数变量就加1;
那如何判断是否为空是否为满???——》判空也就是头和尾相等;判满其实除了头和尾相等外,还要有一个条件:尾巴大于零;
3、设置一个标志变量???——》引进一个计数变量,其初始值置为0;每当入队操作成功执行后,该计数变量的值就置为1;每当出队操作成功执行后,该计数变量的值就置为0;
那如何判断是否为空是否为满???——》判空也就是尾等于0;判满既要头和尾相等,其标志变量必须为1;