java有队列函数吗_队列的基本概念以及java实现队列

队列

队列的基本概念

队列的抽象数据类型

顺序队列

构造函数

入队

出队

查询front

获取队列长度

链式队列

构造函数

入队

出队

查询front

获取队列长度

循环列队

构造函数

入队

出队

查询front

获取循环队列的大小

判断队列是否为空

判断队列是否满

代码传送门,欢迎star:https://github.com/mcrwayfun/java-data-structure

1. 队列的基本概念

队列是一种限定存取位置的线性表。它只允许在表的一端插入,在另一端删除。允许插入的一端叫做队尾,允许删除的一端叫做队头。

每次在队尾加入元素,因此入队的顺序为a1,a2,a3,…,an,最先入队的元素最先出队,所以队列具有的这种特性成为先进先出FIFO(First In First Out)

2. 队列的抽象数据类型

队列是一种特殊的线性表,其包含了一般线性表的操作,抽象数据类型ADT可以概括为两种:基于数组的存储表示和基于链表的存储表示。基于数组实现的是栈称为顺序队列,基于链表实现的栈称为链式队列。基本方法可以概括为

public interface Queue {

// 判断队列是否为空

boolean isEmpty();

// 入队

void push(E data);

// 出队

E pop();

// 查询front

E peek();

// 清空队列

void clear();

// 返回当前队列中的元素个数

int length();

}

3. 顺序队列

顺序栈基于数组来存储表示,申明一个一维数组来存储数据

private Object[] elementData;

定义两个整型变量front和rear,分别表示为队头和队尾;队头front保存着即将出队的元素的索引,而队尾rear保存着下一个即将入队元素的索引。DEFAULT_SIZE为初始化数组的默认长度,capacity为数组中元素的个数

// 队列默认长度

private int DEFAULT_SIZE = 10;

// 保存数组的长度。

private int capacity;

// 队列头元素位置

private int front = 0;

// 队列尾元素位置

private int rear = 0;

3.1 构造函数

提供一个无参构造函数来初始化数组,数组长度为DEFAULT_SIZE

/**

* 初始化数组长度和数组

*/

public SequenceQueue() {

this.capacity = DEFAULT_SIZE;

elementData = new Object[capacity];

}

提供value作为队列第一个元素,initSize作为数组的初始化长度

/**

* 以指定长度的数组来创建队列

*

*@param value 指定顺序中的第一个元素

*@param initSize 数组长度

*/

public SequenceQueue(E value, int initSize) {

this.capacity = initSize;

elementData = new Object[capacity];

elementData[0] = value;

rear++;

}

3.2 入队

检查队列是否已经满了,若不满则在队尾入队,且rear++

/**

* 入队

*

*@param data

*@throws IndexOutOfBoundsException

*/

@Override

public void push(E data) {

// 检查队列是否已经满了

checkQueueIsFull();

elementData[rear++] = data;

}

3.3 出队

检查队列是否为空,若不为空则在队头出队,且front++

/**

* 出队,推出元素

*

*@return

*@throws IndexOutOfBoundsException

*/

@Override

@SuppressWarnings("unchecked")

public E pop() {

// 检查队列是否为空

checkQueueIsEmpty();

E oldValue = (E) elementData[front];

// 释放队列已经出栈的元素

elementData[front++] = null;

return oldValue;

}

3.4 查询front

/**

* 推出元素但不出队

*

*@return

*@throws IndexOutOfBoundsException

*/

@Override

@SuppressWarnings("unchecked")

public E peek() {

// 检查队列是否为空

checkQueueIsEmpty();

return (E) elementData[front];

}

3.5 获取队列长度

/**

* 获取顺序队列的大小

*

*@return

*/

@Override

public int length() {

return rear - front;

}

4. 链式队列

链式队列使用结点的方式来存储表示数据,不用预先分配存储空间。使用front指针表示队头,rear指针表示队尾,size来统计当前队列中的结点数

/**

* 定义一个内部类Node,实现链表队列的结点

*

*@param */

private static class Node {

E item;

Nodenext;

public Node() {

}

public Node(E item, Nodenext) {

this.item = item;

this.next = next;

}

}

/**

* 队列头指针

*/

private Nodefront;

/**

* 队列尾指针

*/

private Noderear;

/**

* 队列包含的结点数

*/

private int size;

4.1 构造函数

无参构造函数

/**

* 无参构造函数

*/

public LinkQueue() {

front = null;

rear = null;

}

以特定的数据来构造链表队列的头结点

/**

* 以特定的数据来构造链表队列的头结点

*

*@param data

*/

public LinkQueue(E data) {

front = new Node<>(data, null);

rear = front;

size++;

}

4.2 入队

分两种情况,队列为空和不为空。若队列为空,则队头指针和队尾指针均指向新结点;若不为空,则队尾指针rear.next = newNode,且newNode成为新的队尾

/**

* 入队

*

*@param data

*/

@Override

public void push(E data) {

NodenewNode = new Node<>(data, null);

// 当前队列为空

if (isEmpty()) {

front = newNode;

rear = newNode;

} else {

// 队列存在元素

// 尾结点的next指向新结点

rear.next = newNode;

// 新结点成为新的尾结点

rear = newNode;

}

size++;

}

4.3 出队

先检查队列是否为空,若不为空才能执行出队操作。出队元素为当前front指针指向的结点

/**

* 出队,并删除头元素

*

*@return

*@throws IndexOutOfBoundsException

*/

@Override

public E pop() {

// 检测队列是否空

checkQueueIsEmpty();

NodeoldFront = front;

front = front.next;

oldFront.next = null;

size--;

return oldFront.item;

}

4.4 查询front

当前front指向的结点即为队头

/**

* 查找队列的front元素

*

*@return

*@throws IndexOutOfBoundsException

*/

@Override

public E peek() {

// 检测队列是否空

checkQueueIsEmpty();

return front.item;

}

4.5 获取队列长度

/**

* 返回队列长度

*

*@return

*/

@Override

public int length() {

return size;

}

5. 循环列队

这是一个顺序队列,由图中可以得知,当front == rear的时候,队列为空。当rear = maxSize(maxSize = 数组长度),队列满,如果再加入新的元素,则会产生溢出。但是,这种溢出是一种假溢出,因为数组的前端可能还存在空位置,为了能够充分利用数组中的元素,把数组的前端和后端连接起来,形成一个环形的表,这就是循环队列。

循环队列首尾相接,当队头指针front和队尾rear进到maxSize-1时,在前进一个位置就自动到0,所以:

**队头指针进1:front = (front + 1)% maxSize

队尾指针进1:rear = (rear + 1) % maxSize**

队列为空的判断条件为front == rear,为了区别,队满的判断条件为front == (rear + 1) % maxSize,即当rear指向front的前一位置时就认为队列已经满了。还有一种判断队列满的方法,定义一个flag,当出队时,让flag = 0;入队时,让flag = 1。当遇到front == rear,若flag = 0,则队列空;若flag = 1,则队列满

// 队列默认长度

private int DEFAULT_SIZE = 10;

// 用来保存队列元素的数组

private Object[] elementData;

// 保存数组的长度。

private int capacity;

// 队列头元素位置

private int front = 0;

// 队列尾元素位置

private int rear = 0;

上述代码是操作循环队列申明的变量,用数组elementData来存储数据,capacity标识数组的长度。因为存在数组,我们可以利用elementData[rear]和elementData[front]来替换flag。当遇到front == rear时,若elementData[rear] == null,则队列空;若elementData[front] != null,则队列满

5.1 构造函数

无参构造函数,使用默认长度DEFAULT_SIZE来初始化数组长度

public LoopQueue() {

this.capacity = DEFAULT_SIZE;

elementData = new Object[capacity];

}

以初始元素和初始长度来构建循环队列

/**

* 以初始元素和初始长度来构建循环队列

*

*@param data

*@param initSize

*/

public LoopQueue(E data, int initSize) {

this.capacity = initSize;

elementData = new Object[capacity];

elementData[0] = data;

rear++;

}

5.2 入队

入队前先判断队是否满了,若满了则不能入队。将data放入数组,且rear++。判断rear == capacity,若等于则从下标0开始

/**

* 入队

*

*@param data

*@throws IndexOutOfBoundsException

*/

@Override

public void push(E data) {

// 判断队列是否已经满了

checkQueueIsFull();

elementData[rear++] = data;

// rear到头则rear转头

rear = rear == capacity ? 0 : rear;

}

5.3 出队

出队前先判断队列是否为空,若空了则不能出队。出队后front++,判断front == capacity,若等于则从下标0开始

/**

* 出队并删除头元素

*

*@return

*@throws IndexOutOfBoundsException

*/

@Override

@SuppressWarnings("unchecked")

public E pop() {

// 判断队列是否为空

checkQueueIsEmpty();

E oldValue = (E) elementData[front];

elementData[front++] = null;

// front到头则front转头

front = front == capacity ? 0 : front;

return oldValue;

}

5.4 查询front

/**

* 查找队列的第一个元素

*

*@return

*@throws IndexOutOfBoundsException

*/

@Override

@SuppressWarnings("unchecked")

public E peek() {

// 判断队列是否为空

checkQueueIsEmpty();

return (E) elementData[front];

}

5.5 获取循环队列的大小

分两种情况,如果front < rear,有效元素就是front到rear之间的元素,直接用rear - front即可;如果front >= rear,有效元素为front->capacity之间,0->front之间的

/**

* 获取循环队列的大小

*

*@return

*/

@Override

public int length() {

if (isEmpty()) {

return 0;

} else {

return rear - front > 0 ? rear - front

: capacity - (front - rear);

}

}

5.6 判断队列是否为空

/**

* 判断队列是否为空

*

*@return

*/

@Override

public boolean isEmpty() {

return rear == front

&& elementData[rear] == null;

}

5.7 判断队列是否满

/**

* 判断队列是否已经满了,若满了则抛出IndexOutOfBoundsException

*/

private void checkQueueIsFull() {

if (rear == front && elementData[front] != null) {

// throw exception

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值