队列

Queue:队列,队头删除,队尾插入
Deque:两端队列,队头、队尾都能插入或删除元素
队列的实现类:
1.LinkedList 具有队列、两端队列的功能,内部使用链表来实现
2.ArrayDeque 具有队列 、两端队列的功能,内部使用循环数组来实现
3.PriorityQueue 优先级队列,它内部实现结构可以快速把所有元素中最小的元素单独放出来,最典型的应用场景:任务调度
队列的2个应用场景:任务调度、LRU
两个工具:Arrays、Colletions

队列Queue

import java.util.LinkedList;
import java.util.Queue;

public class QueueTest {
    public void queueTest(){
        // Queue:队列,队头删除,队尾插入
        // 创建队列
        Queue<String> queue = new LinkedList<String>();
        // 队尾添加元素: add 和 offer,两者区别:在队列已满时,add 会报错,offer 会返回false
        queue.add("str1");
        queue.add("str2");
        queue.offer("str3");
        queue.offer("str4");
        System.out.println(queue);

        // 队头删除元素并返回删除的元素:remove 和 poll,区别:若队列为空时,remove 会报错,poll 会返回null
        // 如果根据删除获取元素时,使用remove时,在remove前要判断队列是否为空(size() == 0  或 isEmpty()),
        //                        使用poll时,在poll后根据返回的内容是否为null判断是否后续操作
        System.out.println("使用remove:" + queue.remove());
        System.out.println("remove后:" + queue);
        System.out.println("使用poll:" + queue.poll());
        System.out.println("poll后:" + queue);

        // 查询队头元素,仅用于查询:element 和 peek,区别:当队列为空时,element 会报错,peek 会返回null
        System.out.println(queue.element());
        System.out.println(queue.peek());

        // 清空队列
        queue.clear();
        System.out.println("清空队列后:" + queue);
        System.out.println(queue.peek());
    }
    public static void main(String[] args){
        new QueueTest().queueTest();
    }
}

执行结果:

[str1, str2, str3, str4]
使用remove:str1
remove后:[str2, str3, str4]
使用poll:str2
poll后:[str3, str4]
str3
str3
清空队列后:[]
null

两端队列Deque

import java.util.Deque;
import java.util.LinkedList;

public class QueueTest {
public void dequeTest(){
        // 创建两端队列Deque
        Deque<String> deque = new LinkedList<String>();
        // 队头插入元素:addFirst 和 offerFirst
        // 队尾插入元素:add 和 addLast 和 offerLast
        // 区别:在队列已满时,add 和 addLast 会报错,offer 会返回false
        deque.add("str1");
        deque.add("str2");
        deque.addFirst("str3");
        deque.addLast("str4");
        deque.offer("str5");
        deque.offerFirst("str6");
        deque.offerLast("str7");
        System.out.println(deque);

        // 查询队头元素:getFirst 和 peekFirst
        // 查询队尾元素:element/getLast 和 peek/peekLast
        // 区别:队列为空时,getFirst、element、getLast 会报错,peekFirst、peek、peekLast 会返回null
        System.out.println("----------------------查询元素----------------------");
        System.out.println("使用 getFirst 查询队头元素:" + deque.getFirst());
        System.out.println("使用 peekFirst 查询队头元素:" + deque.peekFirst());
        System.out.println("使用 getLast 查询队尾元素:" + deque.getLast());
        System.out.println("使用 peekLast 查询队尾元素:" + deque.peekLast());
        System.out.println("使用 element 查询队头元素:" + deque.element());
        System.out.println("使用 peek 查询队头元素:" + deque.peek());

        // 删除队头元素:remove/removeFirst 和 poll/pollFirst
        // 删除队尾元素:removeLast 和 peekLast
        // 两者区别:队列为空时,remove/removeFirst、removeLast 会报错
        //                      poll/pollFirst、peekLast 会返回null
        System.out.println("----------------------删除元素----------------------");
        System.out.println("删除元素前完整队列:" + deque);
        System.out.println("使用 remove 删除队头元素:" + deque.remove());
        System.out.println(deque);
        System.out.println("使用 removeFirst 删除队头元素:" + deque.removeFirst());
        System.out.println(deque);
        System.out.println("使用 poll 删除队头元素:" + deque.poll());
        System.out.println(deque);
        System.out.println("使用 pollFirst 删除队头元素:" + deque.pollFirst());
        System.out.println(deque);
        System.out.println("使用 removeLast 删除队尾元素:" + deque.removeLast());
        System.out.println(deque);
        System.out.println("使用 pollLast 删除队尾元素:" + deque.pollLast());
        System.out.println(deque);
    }
    public static void main(String[] args){
        new QueueTest().dequeTest();
    }
}

执行结果

[str6, str3, str1, str2, str4, str5, str7]
----------------------查询元素----------------------
使用 getFirst 查询队头元素:str6
使用 peekFirst 查询队头元素:str6
使用 getLast 查询队尾元素:str7
使用 peekLast 查询队尾元素:str7
使用 element 查询队头元素:str6
使用 peek 查询队头元素:str6
----------------------删除元素----------------------
删除元素前完整队列:[str6, str3, str1, str2, str4, str5, str7]
使用 remove 删除队头元素:str6
[str3, str1, str2, str4, str5, str7]
使用 removeFirst 删除队头元素:str3
[str1, str2, str4, str5, str7]
使用 poll 删除队头元素:str1
[str2, str4, str5, str7]
使用 pollFirst 删除队头元素:str2
[str4, str5, str7]
使用 removeLast 删除队尾元素:str7
[str4, str5]
使用 pollLast 删除队尾元素:str5
[str4]

优先级队列PriorityQueue

优先级队列使⽤堆(heap)这种数据结构,它是⼀个可以⾃我调整的⼆叉树,对树执⾏添加(add)和删除(remove)操作,可以让最⼩的元素移动到根,⽽不必对元素进⾏排序。
和 TreeSet ⼀样,优先级队列可以保存实现了 Comparable 接⼝的类对象,也可以保存在构造器中提供⽐较器的对象(即在创建队列时提供实现了 Comparator 接口的对象)。其比较器定义可以参考TreeSet的方法 集(Set)的具体使用
本文只示例在构造器中提供比较器的方法

import java.util.*;

public class QueueTest {
    static class Task{
        private String task;
        private Integer priority;
        public Task(String task, Integer priority){
            this.task = task;
            this.priority = priority;
        }

        @Override
        public String toString(){
            return String.format("(%s, %d)", this.task, this.priority);
        }
    }

    public void priorityQueueTest(){
        PriorityQueue<Task> pq = new PriorityQueue<Task>(new Comparator<Task>() {
            @Override
            public int compare(Task task, Task t1) {
                if(task.priority > t1.priority)
                    return 1;
                if(task.priority == t1.priority)
                    return 0;
                return -1;
            }
        });

        for(int i = 0; i < 10; i++){
            int priority = new Random().nextInt(20);
            pq.add(new Task("任务"+ (i+1), priority));
        }
        System.out.println(pq);

        while(!(pq.isEmpty())){
        // remove ⽅法总是会获得当前优先级队列中最⼩的元素
            System.out.println(String.format("执行的任务信息:%s", pq.remove()));
        }
    }
    public static void main(String[] args){
        new QueueTest().priorityQueueTest();
    }
}

执行结果

[(任务9, 2), (任务3, 3), (任务1, 11), (任务8, 6), (任务10, 17), (任务6, 16), (任务7, 12), (任务4, 18), (任务2, 15), (任务5, 18)]
执行的任务信息:(任务9, 2)
执行的任务信息:(任务3, 3)
执行的任务信息:(任务8, 6)
执行的任务信息:(任务1, 11)
执行的任务信息:(任务7, 12)
执行的任务信息:(任务2, 15)
执行的任务信息:(任务6, 16)
执行的任务信息:(任务10, 17)
执行的任务信息:(任务4, 18)
执行的任务信息:(任务5, 18)

LRU算法

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUTest {
    // LRU:Least Recently Used ,最近最少使用,缓存的一种淘汰算法
    // 缓存:缓存热点数据,即被经常使用的数据
    // 当缓存已满时,再向缓存内添加内容时,删除(淘汰)缓存中已存在元素最近最少被使用的那个
    // LinkedHashMap 支持 LRU 算法
    // LinkedHashMap 具有 HashMap 的所有功能 + 可保持插入顺序(遍历),即HashMap + 双向链表
    // LinkedHashMap 使有序的 ,根据 boolean accessOrder 可以确定插入顺序:
    //      1.accessOrder=false 时是插入顺序:即每次插入元素,都将放到双向链表的末尾
    //      2.accessOrder=true 时是访问顺序:每次插入元素/获取元素,将插入或访问的元素放到双向链表的末尾

    static class LRU<K, V> extends LinkedHashMap<K, V> implements Map<K, V> {
        private int maxCount = 5;
        public LRU(){
            super(10, 0.75f, true);
        }
        @Override
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest){
            if(size() > maxCount){
                System.out.println("淘汰最近最少使用的元素:" + eldest);
                return true;
            }
            return false;
        }

    }

    public static void lruTest(){
        LRU<String, String> lru = new LRU();
        lru.put("001", "陆亿");
        lru.put("003", "张三");
        lru.put("006", "老六");
        lru.put("004", "李四");
        lru.put("002", "小二");
        lru.put("005", "王五");
        System.out.println(lru);

        System.out.println(lru.get("006"));
        System.out.println(lru);
        lru.put("007", "琪琪");
        System.out.println(lru);
        System.out.println(lru.get("002"));
        System.out.println(lru);

        lru.put("004", "李四-new");
        System.out.println(lru);
    }

    public static void main(String[] args){
        lruTest();
    }
}

执行结果

淘汰最近最少使用的元素:001=陆亿
{003=张三, 006=老六, 004=李四, 002=小二, 005=王五}
老六
{003=张三, 004=李四, 002=小二, 005=王五, 006=老六}
淘汰最近最少使用的元素:003=张三
{004=李四, 002=小二, 005=王五, 006=老六, 007=琪琪}
小二
{004=李四, 005=王五, 006=老六, 007=琪琪, 002=小二}
{005=王五, 006=老六, 007=琪琪, 002=小二, 004=李四-new}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值