JAVA数据结构-1.普通队列和循环队列的实现以及JAVA的Queue的使用解析
程序员文章站
2024-02-11 19:39:22
...
数据结构和算法
2. 队列
队列是一个有序列表,可用用数组或是链表来实现.
遵循先入先出的原则.
实现思路(普通队列)
- 使用数组的结构来实现队列时,创建一个类,其中包含数组对象queue,同时需要maxSize来表示该队列的最大容量;
- 因为队列的输入和输出时分别从前后端来处理,因此需要两个变量front以及rear分别记录队列前后端的下标,front会随着数据输出而改变,rear则随着数据的输入而改变;
- 其中,front指向队列中队列头一个对象的前一个位置.
- rear指向队列尾的位置.
- 编写类中方法addQueue表示队列加入:
- 将尾指针rear向后移动:rear+1;当front==rear(队列为空).
- 若移动后的尾指针小于队列的最大下标maxSize-1(下标从0开始),则将数据存入rear所指的数组元素中,否则无法存入数据(rear == maxSeize-1 队列满)
- 编写类中方法removeQueue表示移除队列:
- 当队列不为空时,将头指针front移动一位,找到队列中第一个数.
代码实现(普通队列)
public class ArrayQueue {
public static void main(String args[]){
}
}
class ArrayQueueClass{
private int maxSize;
private int front;
private int rear;
private int[] arr;
public ArrayQueueClass(int arrMaxSize){
this.maxSize = arrMaxSize;
front = -1;
rear = -1;
arr = new int[arrMaxSize];
}
public boolean isEmpty(){
if(front == rear){
return true;
}
return false;
}
public boolean isFull(){
if(rear == maxSize-1){
return true;
}
return false;
}
public void addQueue(int data){
if(isFull()){
throw new RuntimeException("队列已经满了~");
}
rear++;
arr[rear] = data;
}
public int removeQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,无法取数据");
}
front++;
return arr[front];
}
public void showQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空");
}
for (int i = front+1; i <= rear ; i++) {
System.out.printf("%d\t",arr[i]);
}
System.out.println();
}
public int check(){
if(isEmpty()){
throw new RuntimeException("队列为空");
}
return arr[front+1];
}
}
问题: 指针不断增加,数组使用一次就不能使用了,没有达到复用的效果.
解决方案:将数组改为环形数组,使用取模来实现
实现思路(循环队列)
- front 变量的含义做一个调整, front就指向队列的第一个元素,arr[front]就是队列的第一个元素, front初始值为0
- rear变量的含有做一个调整, rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定.此时队列的最大可使用容量为maxSize-1,rear初始值为0;
- 当队列满时,条件为(rear+1)%maxSize == front
- 当队列为空时,rear == front
- 队列中有效的数据个数为 (rear+maxSize -frotn)%maxSize
代码实现(循环队列)
public class CircleArrayQueueDemo {
public static void main(String args[]){
CricleArrayQueue queue = new CricleArrayQueue(4); //此时可以用队列为3
queue.addQueue(0);
queue.showQueue();
queue.addQueue(1);
queue.showQueue();
queue.addQueue(2);
queue.showQueue();
// queue.addQueue(3); //java.lang.RuntimeException: 队列已经满了~ front==0 rear==3
System.out.println(queue.removeQueue());
queue.showQueue();
System.out.println(queue.removeQueue());
queue.showQueue();
System.out.println(queue.removeQueue());
System.out.println();
// queue.showQueue();//java.lang.RuntimeException: 队列为空 front == rear ==3
queue.addQueue(4); //front ==3 rear ==0
queue.showQueue();
queue.addQueue(5); //front ==3 rear ==1
System.out.println(queue.removeQueue());//front ==0 rear ==1
System.out.println(queue.removeQueue());//front ==1 rear ==1
}
}
class CricleArrayQueue{
private int maxSize;
public int front;
public int rear;
private int[] arr;
public CricleArrayQueue(int arrMaxSize){
this.maxSize = arrMaxSize;
front = 0; //front表示指向第一个元素 取元素时先取再+1
rear = 0; //rear表示指向最后一个元素的后一个位置 加元素时先加元素在+1
arr = new int[arrMaxSize]; //设置队列最大长度,此时保留一个位置作为队列满的判断,因此最大可用数量为maxSize-1
}
public boolean isEmpty(){
if(front == rear){
return true;
}
return false;
}
public boolean isFull(){
if((rear+1)%maxSize == front){
return true;
}
return false;
}
public void addQueue(int data){
if(isFull()){
throw new RuntimeException("队列已经满了~");
}
arr[rear] = data;
rear = (rear+1)%maxSize;
}
public int removeQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空,无法取数据");
}
int value = arr[front];
front = (front+1)%maxSize;
return value;
}
public void showQueue(){
if(isEmpty()){
throw new RuntimeException("队列为空");
}
for (int i = front; i < front+ (rear - front + maxSize)%maxSize; i++) {
System.out.printf("%d\tarr[%d]",i%maxSize,arr[i%maxSize]);
System.out.println();
}
System.out.println();
}
public int check(){
if(isEmpty()){
throw new RuntimeException("队列为空");
}
return arr[front];
}
}
JAVA中的队列类Queue
在java的高级数据类型中,LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用.
LinkedList 会在双向链表数据结构章节补充源码解析.
public class javaQueue {
public static void main(String args[]){
//add()和remove()方法在失败的时候会抛出异常(不推荐)
Queue<String> queue = new LinkedList<String>();
//添加元素
queue.offer("a");
queue.offer("b");
queue.offer("c");
queue.offer("d");
queue.offer("e");
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("poll="+queue.poll()); //返回第一个元素,并在队列中删除
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("element="+queue.element()); //返回第一个元素
for(String q : queue){
System.out.println(q);
}
System.out.println("===");
System.out.println("peek="+queue.peek()); //返回第一个元素
for(String q : queue){
System.out.println(q);
}
}
}
offer,add 区别:
- 一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
- 这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
poll,remove 区别: - remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似, 但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。
peek,element区别: - element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。