栈和队列---队列(Queue)

1.概念

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

2.队列的使用

现实生活中各种排队:都是队列的一种使用。

广义的队列一般有以下几种:

1.普通队列FIFO:链式队列---基于链表实现(单链表足够,尾插头删)

2.循环队列:可以从队尾走到队首,使用定长数组来实现。

3.优先级队列(非线性结构):一般都是先进先出,但是优先级较高的元素可以优先出队。内部其实使用堆这个数据结构来实现(JDK默认使用的是最小堆---完全二叉树)

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

注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因此LinkedList实现了Queue接口。

Queue<Integer> q = new LinkedList<>();
q.offer(1);
q.offer(2);
q.offer(3);
q.offer(4);
q.offer(5); // 从队尾入队列
// 5
System.out.println(q.size());
// 1
System.out.println(q.peek()); // 获取队头元素
q.poll();
// 2
System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
// 3
if(q.isEmpty()){
    System.out.println("队列空");
}else{
    System.out.println(q.size());
}

3.队列的模拟实现

package seqlist.stack_queue.queue;
/**
 * 队列的核心接口
 * 队列的具体实现可能有多种,普通队列,循环队列,优先级队列
 * 无论哪种队列实现都得满足接口中定义的方法
 */
public interface Queue {
    // 入队
    void offer(int val);
    // 出队
    int poll();
    // 查看队首元素
    int peek();
    // 判断队列是否为空
    boolean isEmpty();
}
package seqlist.stack_queue.queue.impl;

import seqlist.stack_queue.queue.Queue;

import java.util.NoSuchElementException;

/**
 * @description 基于链表实现的普通队列
 */
public class LinkedQueue implements Queue {
    // 内部的节点类
    private static class Node {
        int val;
        Node next;
        public Node(int val) {
            this.val = val;
        }
    }
    private int size;
    // 当前链表的头结点,出队元素
    private Node head;
    // 当前链表的尾结点,添加元素
    private Node tail;

    @Override
    public void offer(int val) {
        Node node = new Node(val);
        size ++;
        if (tail == null) {
            head = tail = node;
            return;
        }
        // 尾插,从队列的尾部添加元素
        tail.next = node;
        tail = node;
    }

    @Override
    public int poll() {
        if (isEmpty()) {
            throw new NoSuchElementException("queue is empty!cannot poll!");
        }
        // 出队在头部进行删除
        Node node = head;
        head = head.next;
        size --;
        node.next = null;
        return node.val;
    }

    @Override
    public int peek() {
        if (isEmpty()) {
            throw new NoSuchElementException("queue is empty!cannot peek!");
        }
        return head.val;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("front [");
        for (Node x = head;x != null;x = x.next) {
            sb.append(x.val);
            if (x.next != null) {
                sb.append(", ");
            }
        }
        sb.append("] tail");
        return sb.toString();
    }
}
package seqlist.stack_queue.queue.impl;
import seqlist.stack_queue.queue.Queue;
import seqlist.stack_queue.queue.impl.LinkedQueue;

public class QueueTest {
    public static void main(String[] args) {
        Queue queue = new LinkedQueue();
        queue.offer(1);
        queue.offer(3);
        queue.offer(5);
        queue.offer(7);
        // 1
        System.out.println(queue.poll());
        // 3
        System.out.println(queue.peek());
        System.out.println(queue);
    }
}

4.循环队列

循环队列使用定长数组(保证元素个数)来实现,数组的首位相连就构成了循环队列(就是走到数组最后一个元素时,下一个访问的就是数组的首地址)。循环队列一般用在OS(操作系统)生产消费者模型。环形队列通常使用数组实现。

4.1 如何区分循环队列空与满

循环队列

判断是否为空:head == tail

判断队列是否已满:(tail + 1) % num.length == head

eg:要保存一个最大支持5个元素的循环队列,则开辟一个长度为6的数组!多余这个空间就是来判断队列是否已满。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹿小伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值