【数据结构】队列(Queue)

目录

队列的概念    

队列的使用

队列的具体方法

​编辑队列的实现(双向链表实现)

双向链表的定义

入队方法

出队方法

获取队头元素

获取有效元素个数

队列是否为空

用单链表实现队列(补充)

循环队列

定义

循环队列的实现

循环队列的代码实现 

定义

 入队操作

出队操作

获取队首元素

获取队尾元素

队列是否为空

队列是否为满

双端队列 


队列的概念    

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)   

【数据结构】队列(Queue)_第1张图片

队列的使用

在Java中,Queue是个接口,底层是通过链表实现的。

【数据结构】队列(Queue)_第2张图片

队列的具体方法

【数据结构】队列(Queue)_第3张图片
队列的实现(双向链表实现)

双向链表的定义

 public static class ListNode{
        int val; // 值域
        ListNode prev;// 前驱
        ListNode next;// 后继

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head; // 头节点记录
    public ListNode tail; // 尾节点记录
    public int size;      // 链表的数量(队列大小)

入队方法

 public void offer(int e){
        ListNode node = new ListNode(e);
        //说明此时的链表为空,所以头节点和尾节点同时指向node即可
        if(head == null){
            head = node;
        }else {
        //不是空链表,操作尾节点进行入队操作
            tail.next = node;
            node.prev = tail;
        }
        tail = node;
        //队列大小加一
        size++;
    }

出队方法

 public int poll(){
        //首先判断队列是不是为空
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
        //记录头节点下一个值
        int headValue = head.val;
        // 头节点往后走一步
        head = head.next;
        // 后面再无节点
        if(head == null){
            tail = null;
        }else {
        // 删除头节点操作
            head.prev.next = null;
            head.prev = null;
        }
        //队列大小减一
        size--;
        // 返回出队的值
        return headValue;
    }

获取队头元素

 public int peek(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
       //直接返回头节点的值即可
        return head.val;
    }

获取有效元素个数

  public int size(){
        return size;
    }

队列是否为空

private boolean isEmpty() {
        return size == 0;
    }

到此队列用双向链表实现完成,完整代码如下:


/**
 * 功能描述
 * 双向链表实现队列
 * @author wileda
 * @date 2022/10/18  21:22
 */
public class MyQueue {
    public static class ListNode{
        int val;
        ListNode prev;
        ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head;
    public ListNode tail;
    public int size;

    public void offer(int e){
        ListNode node = new ListNode(e);
        if(head == null){
            head = node;
        }else {
            tail.next = node;
            node.prev = tail;
        }
        tail = node;
        size++;
    }

    public int poll(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
        int headValue = head.val;
        head = head.next;
        if(head == null){
            tail = null;
        }else {
            head.prev.next = null;
            head.prev = null;
        }
        size--;
        return headValue;
    }

    public int peek(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
        return head.val;
    }
    public int size(){
        return size;
    }

    private boolean isEmpty() {
        return size == 0;
    }
    public void display(){
        StringBuilder  sb = new StringBuilder();
        if (head == null){
            sb.append("[]");
        }
        ListNode current = head;
            sb.append("[");
            while(current != null){
                sb.append(current.val);
                if(current.next != null){
                    sb.append(",");
                }
                current = current.next;
            }
            sb.append("]");
        System.out.println(sb);
    }
}

用单链表实现队列(补充)


/**
 * 功能描述
 *  单向链表实现队列
 * @author wileda
 * @date 2022/10/18  21:59
 */
public class MyQueue1 {
    public static class ListNode{
        int val;
        ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }
    int size;
    ListNode first;
    ListNode last;

    public void offer(int e){
        ListNode node = new ListNode(e);
        if (first == null){
            first = node;
        }else {
            last.next = node;
            node.next = null;
        }
        last = node;
        size++;
    }

    public int poll(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
        int firstValue = first.val;
        if(first == null){
            last = null;
        }else {
            first = first.next;
        }
        size--;
        return firstValue;
    }

    public int peek(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
        return first.val;
    }

    public int size(){
        return size;
    }
    private boolean isEmpty() {
        return size == 0;
    }
    public void display(){
        StringBuilder  sb = new StringBuilder();
        if (first == null){
            sb.append("[]");
        }
      ListNode current = first;
        sb.append("[");
        while(current != null){
            sb.append(current.val);
            if(current.next != null){
                sb.append(",");
            }
            current = current.next;
        }
        sb.append("]");
        System.out.println(sb);
    }
}

循环队列

定义

将队列臆造成一个环状的空间,即把存储队列元素的表从按逻辑上视为一个环,称为循环队列。循环队列在底层还是是由一个数组实现的。指定一个数组大小,首尾相接之后就呈现为循环队列,当队列为满时不能再入队,同样当队列为空时不能再出队。

循环队列的实现

【数据结构】队列(Queue)_第4张图片【数据结构】队列(Queue)_第5张图片

 队列为空时,front ,rear指向同一位置                                        入队时front ,rear所指的位置

 所以我们在循环队列入队操作时,在rear位置添加元素,然后rear++;

那么我们如何判断队列空或者队列已满呢?

【数据结构】队列(Queue)_第6张图片【数据结构】队列(Queue)_第7张图片

      满队列                                                                                                  空队列

 

1)可以记录一个属性size,来判断队列的空与满,当front == rear,size == 0时,证明队列为空,

front == rear,size == n 时,队列已满。

2)加一个冗余位置,当rear + 1 = front时,则可以判定队列已满

【数据结构】队列(Queue)_第8张图片

 那么我们怎么让最后一个下标 + 1,回到数组的第一个位置?

  改变下标位置,用一个公式来处理(index + x)% array.length = 正确下标 ,用以上公式,我们就可以很好确定插入位置的下表,也便于我们后续操作。

循环队列的代码实现 

定义

private int[] elementData;
    // 队首的下标
    private int front;
    // 队尾的下标
    private int rear;

    public MyCircularQueue(int k) {
// 用冗余最后一个数组空间的方式去处理,这时要让k + 1,真实存储数据的大小不变
        elementData = new int[k + 1];
    }

 入队操作

public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
    // 开始处理数组元素与下标
        elementData[rear] = value;
    // 新的rear位置
        rear = (rear + 1 ) % elementData.length;
        return true;
    }

出队操作

public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        front = (front + 1) % elementData.length;
        return true;

    }

获取队首元素

 public int Front() {
        if (isEmpty()) {
            return 0;
        }
        return elementData[front];
    }

获取队尾元素

队尾位置rear特殊,若rear此时不是0下表,我们可以简单获取队尾元素,rear - 1即可,但是若rear此时位于0号下标,那我们想要直接获取位置就会出现数组越界错误,因此我们获取队尾元素操作为 (rear + array.length - 1)% array.length,

 public int Rear() {
        if(isEmpty()) {
            return 0;
        }
        return elementData[(rear - 1 + elementData.length) % elementData.length];
    }

队列是否为空

 public boolean isEmpty() {
        return front == rear;
    }

队列是否为满

 public boolean isFull() {
        return (rear + 1) % elementData.length == front;
    }

双端队列 

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
Deque是一个接口,使用时必须创建LinkedList的对象。

【数据结构】队列(Queue)_第9张图片

 

你可能感兴趣的:(数据结构,java,数据结构)