数据结构与算法--队列
简介
先进先出(FIFO)的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表
数组实现队列
实现方式一:普通数组实现队列
分析
maxSize 是该队列的最大容量。因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear 则是随着数据输入而改变
在数据入队列时需要判断队列是否已满,同时数据出队列时也要判断队列是否为空
- 数据出队列时,若
rear == front
表示队列为空,无数据出队列 - 数据入队列时,若
rear == maxSize - 1
表示队列已满,无法存入数据
该方式实现的缺陷:数组使用一次就不能使用了,没有达到复用的效果
API实现
使用普通数组实现队列数据的入队列、出队列、获取头部数据、提供forEach方式遍历
package Queue.ArrayQueue;
import java.util.Iterator;
public class ArrayQueue<T> implements Iterable<T>{
/**表示数组最大容量*/
private final int maxSize;
/**队列尾*/
private int rear;
/**队列头*/
private int front;
/**存放数组元素,模拟数组队列*/
private final T[] arr;
/**数组中元素个数*/
private int num;
public ArrayQueue(int maxSize){
this.maxSize = maxSize;
//指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
this.rear = -1;
//指向队列头部,分析出front是指向队列头的前一个位置
this.front = -1;
this.num = 0;
arr = (T[]) new Object[maxSize];
}
/**判断队列是否满*/
public boolean isFull(){
return rear == maxSize-1;
}
/**判断队列是否空*/
public boolean isEmpty(){
return front == rear;
}
public int size(){
return num;
}
/**添加数据到队列*/
public void addQueue(T t){
//判断队列是否满
if(isFull()){
System.out.println("队列已满");
return;
}
arr[++rear] = t;
num++;
}
/**获取队列的数据, 出队列*/
public T delQueue(){
if (isEmpty()) {
System.out.println("队列已空");
return null;
}
T data = arr[++front];
arr[front] = null;
num--;
return data;
}
/**显示队列的对头数据, 注意不是取出数据*/
public T getFirst(){
if (isEmpty()) {
System.out.println("队列已空");
return null;
}
return arr[front+1];
}
@Override
public Iterator<T> iterator() {
//提供队列自定义的遍历方式
return new MyIterator();
}
private class MyIterator implements Iterator<T>{
public int index;
public MyIterator(){
this.index = 0;
}
@Override
public boolean hasNext() {
return index < maxSize;
}
@Override
public T next() {
return arr[index++];
}
}
}
测试
package Queue.ArrayQueue;
public class Test {
public static void main(String[] args) {
ArrayQueue<Integer> arrayQueue = new ArrayQueue<Integer>(10);
arrayQueue.addQueue(1);
arrayQueue.addQueue(2);
arrayQueue.addQueue(3);
arrayQueue.addQueue(4);
arrayQueue.addQueue(5);
arrayQueue.addQueue(6);
for (Integer data : arrayQueue) {
System.out.print(data+",");
}
System.out.println("-----------------------");
System.out.println("队列中元素个数:"+arrayQueue.size());
System.out.println("队头元素为:"+arrayQueue.getFirst());
System.out.println("将队头元素拿出:"+arrayQueue.delQueue());
System.out.println("队列中元素个数:"+arrayQueue.size());
System.out.println("-----------------------");
for (Integer data : arrayQueue) {
System.out.print(data+",");
}
}
}
结果如下
1,2,3,4,5,6,null,null,null,null,
-----------------------
队列中元素个数:6
队头元素为:1
将队头元素拿出:1
队列中元素个数:5
-----------------------
null,2,3,4,5,6,null,null,null,null,
实现方式二:循环数组实现队列
分析
可以根据实现方式一进行修改,将数组当做一个环形数组看待(通过取模的方式实现即可)
在数据入环形队列时需要判断队列是否已满,同时数据出环形队列时也要判断队列是否为空
- 数据入环形队列时,将队列容量空出一个作为约定,尾索引的下一个为头索引时表示队列已满:
API实现
package Queue.ArrayQueue;
import java.util.Iterator;
public class CircleArrayQueue<T> implements Iterable<T>{
/**表示数组最大容量*/
private final int maxSize;
/**队列尾*/
private int rear;
/**队列头*/
private int front;
/**存放数组元素,模拟数组队列*/
private final T[] arr;
/**数组中元素个数*/
private int num;
public CircleArrayQueue(int maxSize){
this.maxSize = maxSize;
//指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
this.rear = 0;
//指向队列头部,分析出front是指向队列头的前一个位置
this.front = 0;
this.num = 0;
arr = (T[]) new Object[maxSize];
}
/**判断队列是否满*/
public boolean isFull(){
return (rear + 1) % maxSize == front;
}
/**判断队列是否空*/
public boolean isEmpty(){
return front == rear;
}
/**返回数组中元素的个数*/
public int size(){
return (rear + maxSize - front) % maxSize;
}
/**添加数据到队列*/
public void addQueue(T t){
//判断队列是否满
if(isFull()){
System.out.println("队列已满");
return;
}
arr[rear] = t;
//将 rear 后移, 这里必须考虑取模
rear = (rear + 1) % maxSize;
num++;
}
/**获取队列的数据, 出队列*/
public T delQueue(){
if (isEmpty()) {
System.out.println("队列已空");
return null;
}
// 这里需要分析出 front是指向队列的第一个元素
// 1. 先把 front 对应的值保留到一个临时变量
// 2. 将 front 后移, 考虑取模
// 3. 将临时保存的变量返回
T data = arr[front];
front = (front + 1) % maxSize;
num--;
return data;
}
/**显示队列的对头数据, 注意不是取出数据*/
public T getFirst(){
if (isEmpty()) {
System.out.println("队列已空");
return null;
}
return arr[front];
}
/**显示队列的所有数据*/
public void showQueue() {
if (isEmpty()) {
System.out.println("队列空的,没有数据");
return;
}
// 思路:从front开始遍历
for (int i = front; i < front + size() ; i++) {
int num = i % maxSize;
System.out.printf("arr[%d]=%d\n", num, arr[num]);
}
}
/**提供遍历数组的方法*/
@Override
public Iterator<T> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<T>{
public int index;
public MyIterator(){
this.index = 0;
}
@Override
public boolean hasNext() {
return index < maxSize;
}
@Override
public T next() {
return arr[index++];
}
}
}
测试
package Queue.ArrayQueue;
public class TestCircleArrayQueue {
public static void main(String[] args) {
CircleArrayQueue<Integer> circleArrayQueue = new CircleArrayQueue<>(10);
circleArrayQueue.addQueue(1);
circleArrayQueue.addQueue(2);
circleArrayQueue.addQueue(3);
circleArrayQueue.addQueue(4);
circleArrayQueue.addQueue(5);
circleArrayQueue.addQueue(6);
circleArrayQueue.addQueue(7);
circleArrayQueue.addQueue(8);
circleArrayQueue.addQueue(9);
circleArrayQueue.addQueue(10);
for (Integer data : circleArrayQueue) {
System.out.print(data+",");
}
System.out.println();
System.out.println("----------circleArrayQueue-------------");
System.out.println("队列中元素个数:"+circleArrayQueue.size());
System.out.println("队头元素为:"+circleArrayQueue.getFirst());
System.out.println("将队头元素拿出:"+circleArrayQueue.delQueue());
System.out.println("队列中元素个数:"+circleArrayQueue.size());
System.out.println("-----------------------");
for (Integer data : circleArrayQueue) {
System.out.print(data+",");
}
}
}
结果如下
队列已满
1,2,3,4,5,6,7,8,9,null,
----------circleArrayQueue-------------
队列中元素个数:9
队头元素为:1
将队头元素拿出:1
队列中元素个数:8
----------circleArrayQueue-------------
1,2,3,4,5,6,7,8,9,null,
单链表实现队列
分析
,其物理结构不能表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列的结点(链表中的每一个元素称为结点)组成,结点可以在运行时动态生成
API实现
使用单链表实现队列数据的入队列、出队列、提供forEach循环遍历、获取队头数据
节点类
package Queue.LinearQueue;
public class Node<T>{
public T item;
public Node next;
public Node(T item,Node next){
this.item = item;
this.next = next;
}
}
链表队列实现类
package Queue.LinearQueue;
import java.util.Iterator;
public class LinearQueue<T> implements Iterable<T>{
/**记录首结点*/
private final Node<T> head;
/**当前队列中元素个数*/
private int n;
/**记录最后一个结点*/
private Node<T> last;
public LinearQueue(){
this.head = new Node<>(null,null);
this.last = null;
this.n = 0;
}
/**判断队列是否为空,是返回true,否返回false*/
public boolean isEmpty(){
return n == 0;
}
/**获取队列中元素的个数*/
public int size(){
return n;
}
/**往队列种插入一个元素*/
public void enQueue(T t){
if(null == last){
last = new Node<>(t, null);
head.next = last;
}else{
Node<T> oldLast = last;
this.last = new Node<>(t, null);
oldLast.next = last;
}
n++;
}
/**从队列中拿出一个元素*/
public T deQueue(){
if(isEmpty()){
return null;
}
Node<T> oldFirst = head.next;
head.next = oldFirst.next;
n--;
//如果队列已经删除完了,需要将last重置为null
if(isEmpty()){
this.last = null;
}
return (T)oldFirst.item;
}
/**提供外部遍历方式*/
@Override
public Iterator<T> iterator(){
return new MyIterator();
}
private class MyIterator implements Iterator<T>{
public Node<T> node;
public MyIterator(){
this.node = head;
}
@Override
public boolean hasNext(){
return node.next != null;
}
@Override
public T next(){
node = node.next;
return node.item;
}
}
}
测试
package Queue.LinearQueue;
public class Test{
public static void main(String[] args){
//创建Queue对象
LinearQueue<String> linearQueue = new LinearQueue<String>();
//添加元素
linearQueue.enQueue("a");
linearQueue.enQueue("b");
linearQueue.enQueue("c");
linearQueue.enQueue("d");
linearQueue.enQueue("e");
System.out.println("------------------原队列数据-------------------");
for(String value : linearQueue){
System.out.print(value+",");
}
System.out.println();
System.out.println("----------------队列大小-----------------------");
System.out.println(""+ linearQueue.size());
System.out.println("----------------移除队列的元素------------------");
String result = linearQueue.deQueue();
System.out.println(result);
System.out.println("----------------返回队列的元素个数---------------");
System.out.println(linearQueue.size());
System.out.println("------------------队列数据---------------------");
for(String value : linearQueue){
System.out.print(value+",");
}
}
}
结果
------------------原队列数据-------------------
a,b,c,d,e,
----------------队列大小-----------------------
5
----------------移除队列的元素------------------
a
----------------返回队列的元素个数---------------
4
------------------队列数据---------------------
b,c,d,e,