Java手写数组队列和链表队列并使用java里面现成的队列方法

说明

这里记录下使用数组和链表手动实现队列功能,并使用java里面现成的队列方法。

使用数组手动实现队列功能

package com.example.deesign_patterns.test;

//java使用数组简单实现队列
public class ArrayQueue {
    private int[] queue;  // 内部数组
    private int front;    // 队列头部指针
    private int rear;     // 队列尾部指针
    private int size;     // 队列当前元素个数
    private int capacity; // 队列容量

    //构造方法,初始化的时候必须要传队列容量值
    public ArrayQueue(int capacity) {
        this.capacity = capacity;
        queue = new int[capacity];
        front = 0;
        rear = -1;
        size = 0;
    }

    //判断是否是空队列
    public boolean isEmpty() {
        return size == 0;
    }

    //判断队列是否已满
    public boolean isFull() {
        return size == capacity;
    }

    //队列元素个数
    public int size() {
        return size;
    }

    //元素入队列
    public void add(int value) {
        if (isFull()) {
            System.out.println("队列已经满了,无法添加队列。");
            return;
        }
        rear = (rear + 1) % capacity; // 循环队列,计算新的尾部位置
        queue[rear] = value;//在数组尾部添加元素
        size++;//如果添加成功,则队列元素数量加1
        System.out.println("入队列元素值: " + value);
    }

    //头部元素出队列,重新计算头部位置,数组索引往后移了一位,相当于删除头元素
    public int pull() {
        if (isEmpty()) {
            System.out.println("队列是空的,无法出队列。");
            return -1;
        }
        int value = queue[front];
        front = (front + 1) % capacity; // 循环队列,计算新的头部位置
        size--;//如果出队列成功,则队列元素数量减1
        System.out.println("出队列元素值: " + value);
        return value;
    }

    //获取队列里面的首元素,不会删除元素
    public int peek() {
        if (isEmpty()) {
            System.out.println("队列是空的!");
            return -1;
        }
        return queue[front];
    }

    //显示队列元素
    public void display() {
        if (isEmpty()) {
            System.out.println("队列是空的!");
            return;
        }
        System.out.print("队列当前元素值: ");
        int index = front;
        for (int i = 0; i < size; i++) {
            System.out.print(queue[index] + " ");
            index = (index + 1) % capacity; // 循环遍历队列
        }
        System.out.println();
    }

    //测试类
    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(5);
        queue.add(10);
        queue.add(20);
        queue.add(30);
        queue.display(); // Queue: 10 20 30
        queue.pull();
        queue.display(); // Queue: 20 30
        queue.add(40);
        queue.add(50);
        queue.display(); // Queue: 20 30 40 50
        queue.pull();
        queue.pull();
        queue.display(); // Queue: 40 50
        System.out.println("当前队列首元素为:"+queue.peek());//Queue: 40
    }
}


执行结果如下:
在这里插入图片描述

使用单向链表手动实现队列功能

单向链表类

package com.example.deesign_patterns.test;

//单向链表类
public class Node<T> {
    public T data;
    public Node next;

    //无参构造方法
    public Node() {}

    //有参构造方法
    public Node(T data, Node next) {
        this.data = data;
        this.next = next;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

队列需要实现的功能接口(也可以在链表队列类里面直接写方法):

package com.example.deesign_patterns.test;

/**
 * 队列功能接口
 * 队列是一种先进先出的线性表
 * 只能在表的一端进行插入,另一段进行删除
 * 允许插入的一端叫队尾,允许删除的一端叫队头()
 */
public interface IQueue<T> {
    /**
     * 初始化队列 构造一个空队列
     */
    IQueue InitQueue();

    /**
     * 销毁队列
     */
    IQueue DestroyQueue();

    /**
     * 清空队列
     */
    IQueue ClearQueue();

    /**
     * 队列判空
     */
    Boolean isEmpty();

    /**
     * 返回队列长度
     */
    Integer QueueLength();

    /**
     * 返回队列头元素
     */
    T GetHead();

    /**
     * 插入队尾元素
     */
    Boolean EnQueue(T e);

    /**
     * 删除队头元素  即出队
     */
    T DeQueue();

    /**
     * 打印队列元素
     */
    void printQueue();
}

链表队列类:

package com.example.deesign_patterns.test;

//java使用链表简单实现队列
public class LinkedQueue<T> implements IQueue<T> {
    private  Node<T> front;//队头指针
    private  Node<T> rear;//队尾指针
    private int size;//队列长度

    //无参构造方法
    public LinkedQueue() {
        front = null;
        rear = null;
        size = 0;
    }

    //初始化队列方法
    @Override
    public IQueue InitQueue() {
        front = null;
        rear = null;
        size = 0;
        return this;
    }

    //销毁队列方法
    @Override
    public IQueue DestroyQueue() {
        //销毁
        front = null;
        rear = null;
        size = 0;
        return this;
    }

    //清空队列方法
    @Override
    public IQueue ClearQueue() {
        front = null;
        rear = null;
        size = 0;
        return this;
    }

    //判断队列是否为空
    @Override
    public Boolean isEmpty() {
        return size == 0;
    }

    //判断队列长度
    @Override
    public Integer QueueLength() {
        return size;
    }

    //获取队列里面的首元素
    @Override
    public T GetHead() {
        if (isEmpty()) {
            return null;
        }
        return front.getData();
    }

    //将元素入队
    @Override
    public Boolean EnQueue(T e) {
        Node<T> newNode = new Node<>(e, null);
        if (isEmpty()) {
            front = newNode;
        } else {
            rear.setNext(newNode);
        }
        rear = newNode;
        size++;
        return true;
    }

    //将元素出队
    @Override
    public T DeQueue() {
        if (isEmpty()) {
            return null;
        }
        T data = front.getData();
        front = front.getNext();
        size--;
        if (isEmpty()) {
            rear = null;
        }
        return data;
    }

    @Override
    public void printQueue() {
        for (Node current = front;current != null;current = current.next){
            System.out.print(current.data+" ");
        }
        System.out.println();
    }
	
	//测试类
    public static void main(String[] args) {
        IQueue<Integer> queue = new LinkedQueue<>();
        queue.InitQueue();
        queue.EnQueue(1);
        queue.EnQueue(2);
        queue.EnQueue(3);
        System.out.println("队列长度: " + queue.QueueLength());
        queue.printQueue();//打印队列值
        System.out.println("队头元素: " + queue.GetHead());
        System.out.println("出队元素: " + queue.DeQueue());
        System.out.println("出队元素: " + queue.DeQueue());
        System.out.println("出队元素: " + queue.DeQueue());
        queue.printQueue();//打印队列值
        System.out.println("队列长度: " + queue.QueueLength());
        System.out.println("队列是否为空: " + queue.isEmpty());
    }
}

在这里插入图片描述

Java中ArrayBlockingQueue和ArrayQueue和LinkedBlockingQueue使用

在Java中,ArrayBlockingQueue和ArrayQueue是两种不同的队列实现。它们之间有以下区别:

  1. 数据结构不同:ArrayBlockingQueue是基于数组的有界阻塞队列,它的容量是固定的。而ArrayQueue是基于数组的无界队列,它的容量可以动态增长。
  2. 插入和删除操作的不同:ArrayBlockingQueue的插入和删除操作是线程安全的,并且支持阻塞操作。当队列已满时,插入操作将会被阻塞,直到有空间可用;当队列为空时,删除操作将会被阻塞,直到有元素可用。而ArrayQueue的插入和删除操作不是线程安全的,需要自行处理同步。
  3. 性能方面的不同:由于ArrayBlockingQueue支持阻塞操作,它在多线程环境下具有更好的线程安全性。然而,由于需要处理同步和阻塞,它的性能相对较低。相比之下,ArrayQueue在单线程环境下的性能更好,不需要处理同步和阻塞。

ArrayQueue使用方法如下:

package com.example.deesign_patterns.test;

import com.sun.jmx.remote.internal.ArrayQueue;

public class Test3Main {

    public static void main(String[] args) {
        //数组队列使用,给数组一个大小,当数组里面的元素数量超过5,就会报错,可以通过resize()方法扩容
        ArrayQueue arrayQueue=new ArrayQueue<Integer>(5);
        arrayQueue.add(1);//入队列
        arrayQueue.add(2);
        arrayQueue.add(3);
        arrayQueue.add(4);
        arrayQueue.add(5);
        System.out.println("当前队列元素:"+arrayQueue);
        System.out.println("当前队列大小:"+arrayQueue.size());
        System.out.println("获取当前队列索引为1的元素:"+arrayQueue.get(1));
        //重新设置队列大小,相当于扩容,扩容后大小由原来的5变为6,值必须比原来大
        arrayQueue.resize(6);
        arrayQueue.add(6);
        System.out.println("当前队列元素:"+arrayQueue);
        System.out.println("当前队列大小:"+arrayQueue.size());
        //只能删除队列头元素,必须是索引0,不为0报错,相当于出队列
        arrayQueue.remove(0);
        System.out.println("当前队列元素:"+arrayQueue);
    }
}

在这里插入图片描述

ArrayBlockingQueue常用使用方法如下:

在Java中,ArrayBlockingQueue是一个具有固定容量的阻塞队列。它的实现是基于数组的,它实现了BlockingQueue接口,提供了一组方法用于操作队列中的元素。

  1. add(element):向队列尾部添加一个元素,如果队列已满,则IllegalStateExceptio异常。
  2. offer(element):向队列尾部添加一个元素,如果队列已满,则返回false。
  3. put(element):向队列尾部添加一个元素,如果队列已满,则会一直阻塞直到队列有空闲位置。
  4. poll():从队列头部移除并返回一个元素,如果队列为空,则返回null。
  5. take():从队列头部移除并返回一个元素,如果队列为空,则会一直阻塞直到队列有元素可取。
  6. peek():获取队列头部的元素,但不会移除该元素。
  7. size():返回队列中当前元素的数量。
  8. remainingCapacity():返回队列中剩余的可用容量。
  9. isEmpty(): 判断队列是否为空,如果队列为空则返回true,否则返回false。
package com.example.deesign_patterns.test;

import java.util.concurrent.ArrayBlockingQueue;

public class Test3Main {

    public static void main(String[] args) {
        //数组队列使用,必须给数组一个大小,当数组里面的元素数量超过5,就会报错,不能扩容
        ArrayBlockingQueue queue=new ArrayBlockingQueue(5);
        queue.add(1);
        queue.add(2);
        queue.add(3);
        queue.add(4);
        queue.add(5);
        System.out.println("当前队列元素:"+queue);
        System.out.println("当前队列大小:"+queue.size());
        System.out.println("队列已满返回boolean值为:"+queue.offer(6));
        System.out.println("获取队列头部元素:"+queue.peek());
        //出队列
        queue.poll();
        System.out.println("当前队列元素:"+queue);
        System.out.println("当前队列可用容量:"+ queue.remainingCapacity());
    }
}


在这里插入图片描述

LinkedBlockingQueue常用使用方法如下:

LinkedBlockingQueue是一个线程安全的队列,它的实现是基于链表的。LinkedBlockingQueue的容量可以是无限的。

常用使用方法和ArrayBlockingQueue队列方法一样

package com.example.deesign_patterns.test;

import java.util.concurrent.LinkedBlockingQueue;

public class Test3Main {

    public static void main(String[] args) {
        //链表队列使用
        //如果没有给链表一个大小,默认值是Integer.MAX_VALUE
        //LinkedBlockingQueue queue=new LinkedBlockingQueue();
        //如果给链表一个大小,当链表里面的元素数量超过5,就会报错,不能扩容
        LinkedBlockingQueue queue=new LinkedBlockingQueue(5);
        queue.add(1);
        queue.add(2);
        queue.add(3);
        queue.add(4);
        queue.add(5);
        System.out.println("当前队列元素:"+queue);
        System.out.println("当前队列大小:"+queue.size());
        System.out.println("队列已满返回boolean值为:"+queue.offer(6));
        System.out.println("获取队列头部元素:"+queue.peek());
        //出队列
        queue.poll();
        System.out.println("当前队列元素:"+queue);
        System.out.println("当前队列可用容量:"+ queue.remainingCapacity());
    }
}

在这里插入图片描述

ArrayBlockingQueue和LinkedBlockingQueue区别

Java中的ArrayBlockingQueue和LinkedBlockingQueue都是实现了BlockingQueue接口,用于实现多线程环境下的阻塞队列。它们之间的区别主要有以下几个方面:

  1. 数据结构:ArrayBlockingQueue使用数组作为底层数据结构,而LinkedBlockingQueue使用链表作为底层数据结构。这导致了它们在插入和删除操作上的性能特点不同。
  2. 队列大小:ArrayBlockingQueue有一个固定的容量,需要在创建时指定大小,而LinkedBlockingQueue的容量是可选的,默认为Integer.MAX_VALUE。
  3. 线程阻塞:ArrayBlockingQueue在插入和删除元素时,如果队列已满或为空,操作线程会被阻塞,直到有可用的空间或元素可供操作。而LinkedBlockingQueue在插入和删除元素时,如果队列已满或为空,操作线程可以选择被阻塞或立即返回。
  4. 迭代性能:由于LinkedBlockingQueue使用链表作为底层数据结构,迭代操作的性能通常比ArrayBlockingQueue更好。
  5. 吞吐量:在高并发场景下,LinkedBlockingQueue通常比ArrayBlockingQueue具有更好的吞吐量,因为它能够更好地支持并发的插入和删除操作。

综上所述,ArrayBlockingQueue适用于有固定容量要求的场景,操作线程需要在队列满或空时被阻塞;而LinkedBlockingQueue适用于没有固定容量要求的场景,可以更好地支持高并发的插入和删除操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值