概念
队列是一种首受限的线性表,它是一种先进先出,后进后出的数据结构。
特点
- 只允许在一端进行插入(入队)操作,在另一段进行删除(出队)操作
- 插入的一端叫队尾,删除的一段叫队首
队列的实现方式
- 使用顺序表实现队列
- 使用链表实现队列
使用顺序表实现队列
需求
1. 队列的判空操作:isEmpty() 对应Array的isEmpty()
2. 求队列的长度:getSize() 对应Array的getSize()
3. 取队首元素操作:peek() 对应Array的getFirst()
4. 入队操作:push(x) 对应Array的addLast()
5. 出队操作:pop() 对应Array的removeFirst()
代码
- 定义一个名为IQueque的接口
public interface IQueue<E> {
/*
1. 队列的判空操作:isEmpty() 对应Array的isEmpty()
2. 求队列的长度:getSize() 对应Array的getSize()
3. 取队首元素操作:peek() 对应Array的getFirst()
4. 入队操作:push(x) 对应Array的addLast()
5. 出队操作:pop() 对应Array的removeFirst()
*/
Boolean isEmpty();
int getSize();
E peek();
void push(E e);
E pop();
}
- 使用原生数组实现队列
public class ArrayListQueue<E> implements IQueue<E> {
private E[] data;
private int size;
public ArrayListQueue(int Capacity) {
this.data = (E[])new Object[Capacity];
}
public ArrayListQueue() {
this.data = (E[])new Object[10];
}
@Override
public Boolean isEmpty() {
return size==0;
}
@Override
public int getSize() {
return size;
}
@Override
public E peek() {
return data[0];
}
@Override
public void push(E e) {
//入队需要判断原生数组容量
if (data.length==size){
//数组满,需要扩容
resize(data.length*2);
}
data[size]=e;
size++;
}
@Override
public E pop() {
//取出队首元素
E ele = data[0];
//将数组向前移动一位
for (int i = size-1; i>=1; i--) {
data[i-1] = data[i];
}
//将数组最后一个元素赋值为null
data[size-1] = null;
size--;
//判断是否需要缩容
if (data.length>=20&&size==data.length/4){
resize(data.length/2);
}
return ele;
}
private void resize(int newCapacity) {
//1.定义一个新的数组
E[] newData = (E[])new Object[newCapacity];
//2.将data中的数据迁移到newData中
for (int i = 0; i < data.length; i++) {
newData[i] = data[i];
}
data=newData;
}
}
使用链表实现队列
补充:
使用原生数组实现循环队列
import java.util.Arrays;
public class LoopQueue<E> implements IQueue<E> {
private E[] data;
private int front,tail; //指针:fron表示队首index,tail表示队尾index(一般指的是带添加元素位置的索引)
private int size;
public LoopQueue() {
data = (E[]) new Object[10];
}
public LoopQueue(int capatity) {
data = (E[]) new Object[capatity];
}
@Override
public String toString() {
return Arrays.toString(data);
}
@Override
public Boolean isEmpty() {
return front==tail;
}
@Override
public int getSize() {
return size;
}
@Override
public E peek() {
return data[front];
}
@Override
public void push(E e) {
//1.判断队列是否满了
if ((tail+1)%data.length==front){
//满,则需要扩容
resize(data.length*2);
}
//2.入队
data[size]=e;
//3.tail指向下待添加元素的位置)
tail = (tail+1)%data.length;//该算法可以实现指针的转弯
//4.数组长度+1
size++;
}
@Override
public E pop() {
//0.判断队列中是否还有元素
if (isEmpty()==true){
throw new RuntimeException("队列为空");
}
//1.取出队首元素,再将data[front]=null
E lastEle = data[front];
data[front]=null;
//2.front指向下一个队首元素
front = (front+1)%data.length;//该算法可以实现指针的转弯
//3.缩容,需要解决复杂度震荡问题
if (data.length>=20&&size == data.length/4){
resize(data.length/2);
}
//4.size--
size--;
return lastEle;
}
public void resize(int newCapacity){
//1.创建新数组,用于存放data中的数据
E[] newData = (E[])new Object[newCapacity];
//2.将data中的数据迁移到newdata中
for (int i = 0; i < size; i++) {
newData[i] = data[(i+front)%data.length];
}
//3.将data替换
data = newData;
}
}
使用原生链表实现循环队列
public class LoopQueue<E> implements IQueue<E> {
//虚拟头节点
private Node dummyNode;
//链表长度
private int size;
private class Node{
//节点值
private E e;
//该节点指向的下一个节点
private Node next;
public Node() {
}
public Node(E e) {
this.e = e;
}
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
}
public LoopQueue() {
dummyNode = new Node(null,dummyNode);
size = 0;
}
@Override
public Boolean isEmpty() {
return size==0;
}
@Override
public int getSize() {
return size;
}
@Override
public E peek() {
return dummyNode.next.e;
}
@Override
public void push(E e) {
Node newNode = new Node(e, dummyNode);
if (size==0){
dummyNode.next=newNode;
}else{
//找到队尾元素
Node tailNode=dummyNode;
for (int i = 0; i <size ; i++) {
tailNode=tailNode.next;
}
tailNode.next=newNode;
}
size++;
}
@Override
public E pop() {
if (size==0){
return null;
}else{
//找到队首元素
Node firstNode = dummyNode.next;
dummyNode.next=firstNode.next;
size--;
return firstNode.e;
}
}
}