特殊容器的学习与使用

在这里插入图片描述

HashMap的EntrySet学习(HashMap的遍历)

EntrySet 和Map.Entry<K,V>

在这里插入图片描述

set的迭代器

不要在foreach循环里增删操作!!!请使用迭代器
在这里插入图片描述

在这里插入图片描述

map键值对的遍历学习

        Map<Integer,Integer> map=new HashMap<>();
        map.put(10,20);
        map.put(20,45);
        //获取键值对的set集合
        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
        
        //是set结合都可以使用iterator迭代器来遍历
        Iterator<Map.Entry<Integer, Integer>> iterator = entries.iterator();
        System.out.println("使用set的迭代器实现map遍历:");
        while (iterator.hasNext()){
            Map.Entry<Integer, Integer> next = iterator.next();
            System.out.println(next.getKey()+" "+next.getValue());
        }

        System.out.println("set的foreach来实现遍历:");
        for (Map.Entry<Integer, Integer> entry : entries) {
            System.out.println(entry.getKey()+" "+entry.getValue());
        }

TreeMap使用学习

在这里插入图片描述

注意:treeMap的key的字符串的升序排序,本质属于按照首字符开始的ASSIC码的升序排序(0:48,A:65,a:97),但是可能出现长度长的字符串在短的字符串的前面。(针对咱们自定义比较器对key进行排序)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在按照key的排序基础上,再进行按照value进行排序,需要转换为entryset,将entryset装入list容器/或者封装为2维数组里,再进行按照value进行排序。
(注意1:按照value进行排序必须将map集合转换为entrySet进行排序
注意2:此时value的排序的优先级是最高的!!!)

显然如果想先按照value排序再按照key排序,要么需要重构treemap将key和value的位置相互互换;要么key和value可以封装为一个对象,对它使用PriorityQueue进行排序输出!!!
在这里插入图片描述
注意:set集合本身是不能进行排序的,Collections.sort(list容器,比较器)是给有序集合例如list来使用的(所以需要将entryset装到list容器里)
注意:实际PriorityQueue的排队功能更加强大一点
在这里插入图片描述

荣耀按照时间戳排序的学习

public class Main2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int size=scanner.nextInt();
        Set<String> set=new HashSet<>();

//        首先去除相同的字符串
        for(int i=0;i<size;i++){
            set.add(scanner.next());
        }
//       稳定性排序:确保按照ASSIC的字典排序
        Map<String,Long> map=new TreeMap<>();
        for(String s:set){
            String[] sp=s.split("/");
            for(int i=0;i<sp.length;i++){
                if(isDate(sp[i])){
                    Date date=getDate(sp[i]);
                    long t=date.getTime();
                    map.put(s,t);
                    break;
                }
            }
        }

        ArrayList<Map.Entry<String, Long>> entries = new ArrayList<>(map.entrySet());
        
//        之后确保:按照时间戳排序,再按照长度进行排序
        Collections.sort(entries, new Comparator<Map.Entry<String, Long>>() {
            @Override
            public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) {
                if(!o1.getValue().equals(o2.getValue())){
                    return o1.getValue().compareTo(o2.getValue());
                }else{
                    return Integer.compare(o1.getKey().length(),o2.getKey().length());
                }
            }
        });

        for(Map.Entry<String, Long> e:entries){
            System.out.println(e.getKey());
        }



    }

    public static boolean isDate(String s){
        Date date=null;
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        try {
            date=sdf.parse(s);
        } catch (ParseException e) {
//            e.printStackTrace();
        }
        if(date==null){
            return false;
        }else{
            return true;
        }

    }

    public static Date getDate(String s){
        Date date=null;
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        try {
            date=sdf.parse(s);
        } catch (ParseException e) {
//            e.printStackTrace();
        }
        return date;

    }
}

考虑封装多个属性为一个类—实现Comprate接口&&compareTo方法,之后直接调用list集合进行排序

//希望实现按照时间,长度好和ASSIC码进行排序
public class DateString implements Comparable<DateString>{
    public String source;
    public Long date;
    public int len;
    DateString(String source,Long date){
        this.source=source;
        this.len=source.length();
        this.date=date;
    }

    @Override
    public int compareTo(DateString o) {
        if(date.equals(o.date)){
            if(len==o.len){
                return source.compareTo(o.source);
            }else{
                return Integer.compare(len,o.len);
            }

        }else{
            return Long.compare(date,o.date);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int size=scanner.nextInt();
        Set<String> set=new HashSet<>();

//        首先去除相同的字符串
        for(int i=0;i<size;i++){
            set.add(scanner.next());
        }

        List<DateString> list=new ArrayList<>();
        
        for(String s:set){
            String[] sp=s.split("/");
            for(int i=0;i<sp.length;i++){
                if(isDate(sp[i])){
                    long date = getDate(sp[i]);
                    list.add(new DateString(s,date));
                    break;
                }
            }
        }
        Collections.sort(list);

        for (DateString dateString : list) {
            System.out.println(dateString.source);
        }

    }


    public static boolean isDate(String s){
        Date date=null;
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        try {
            date=sdf.parse(s);
        } catch (ParseException e) {
//            e.printStackTrace();
        }
        if(date==null){
            return false;
        }else{
            return true;
        }

    }

    public static long getDate(String s){
        Date date=null;
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        try {
            date=sdf.parse(s);
        } catch (ParseException e) {
//            e.printStackTrace();
        }
        return date.getTime();

    }
}

在这里插入图片描述

SimpleDateformat学习

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

使用构造函数自定义需要解析的时间格式的模式情况,使用parse()方法解析具体的字符串

在这里插入图片描述

在这里插入图片描述

Date类的学习

注意date一般转换为long进行比较两个时间的大小,或者使用自带的after和before进行比较两个时间
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

LinkedHashMap(继承自HashMap)

在这里插入图片描述
指定顺序的构造函数(默认插入顺序;访问顺序-高级的LRU(最近最少使用))
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

访问顺序(每次都是在访问过的节点移动到双向链表的尾结点)

在这里插入图片描述
最近最少使用的原理
在这里插入图片描述

题:LRU缓存(最近最少使用)

力扣题:实现最近最少使用缓存
LRU类的成员变量:容量+当前size+假头he假尾(双向链表,维护最近使用关系)+map集合实现cache(数据 , 数据节点的位置信息)
双向链表需要自己创建:key,value,pre,next,构造函数

将最近使用的放在链表的头部,最少使用的都在链表的尾部。put和get都会引发将数据的最新的使用节点移动至链表的头部

class LRUCache {
    private int capacity;
    private int size;
    private DLinkedNode head;//构建假头与假尾方便拼接与删除
    private DLinkedNode tail;
    private Map<Integer,DLinkedNode> cache;
    

    //构造一个双向链表,存储的值是key和value
    class DLinkedNode{
        int key;
        int value;
        DLinkedNode pre;//前驱结点
        DLinkedNode next;//后驱节点
        public DLinkedNode(){}
        public DLinkedNode(int key,int value){
            this.key=key;
            this.value=value;
        }
    }

    //初始化缓存
    public LRUCache(int capacity) {
        this.capacity=capacity;
        size=0;
        head=new DLinkedNode();
        tail=new DLinkedNode();
        head.next=tail;
        tail.pre=head;
        cache=new HashMap<Integer,DLinkedNode>();
    }
    

    public int get(int key) {
        if(!cache.containsKey(key)){
            return -1;
        }else{
            DLinkedNode cur=cache.get(key);
            int value=cur.value;//注意get操作也要更新
            moveToHead(cur);
            return value;
        }
    }
    

    public void put(int key, int value) {

        //如果不存在这个key,则加入
        if(!cache.containsKey(key)){
            size++;
            DLinkedNode add=new DLinkedNode(key,value);
            addToHead(add);
            cache.put(key,add);
            if(size>capacity){
                DLinkedNode tail=deleteTail();
                cache.remove(tail.key);
                size--;
            }

        }else{//存在这个数就更新
            DLinkedNode p=cache.get(key);
            p.value=value;
            cache.put(key,p);
            moveToHead(p);       
        }

    }


    //删除一个节点
    public void removeNode(DLinkedNode cur){
        cur.pre.next=cur.next;
        cur.next.pre=cur.pre;
    }

    //增加一个节点至头部(假头的后面)
    public void addToHead(DLinkedNode cur){
        DLinkedNode temp=head.next;
        head.next=cur;
        cur.pre=head;
        cur.next=temp;
        temp.pre=cur;  
    }

    //将一个节点移动到头结点(删除原来位置的节点+加入头结点)
    public void moveToHead(DLinkedNode cur){
        removeNode(cur);
        addToHead(cur);
    }

    //删除尾部节点(并返回删除的节点,用于删除缓存数据)
    public DLinkedNode deleteTail(){
        DLinkedNode t=tail.pre;//位于假头的前面
        removeNode(t);
        return t;
    }

}

PriorityQueue(优先级队列)

在这里插入图片描述
不指定排序顺序,默认升序排列;利用Comparator接口实现
在这里插入图片描述

peek()和poll()都是针对队首元素(排序的队列)
add操作要按照定义的优先级插入,不一定是队尾

在这里插入图片描述

题: 前k个高频元素

力扣题
在这里插入图片描述

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int len=nums.length;
        Map<Integer,Integer> map=new HashMap<>();

        for(int i=0;i<len;i++){
            map.put(nums[i],map.getOrDefault(nums[i],0)+1);
        }

        //按照数组的第二个元素升序排列(队列头部是最小的数:peek就是队列的头部)
        PriorityQueue<int[]> proQueue=new PriorityQueue<int[]>(new Comparator<int[]>(){
            public int compare(int[] o1,int[] o2){
                return Integer.compare(o1[1],o2[1]);
            }
        });

        Set<Map.Entry<Integer,Integer>> mapEntrySet=map.entrySet();
        for(Map.Entry<Integer,Integer> set:mapEntrySet){
            int value=set.getKey(),count=set.getValue();
            if(proQueue.size()==k){
                //当前仅当当前元素的数量多于队列的头部
                if(count>proQueue.peek()[1]){//peek是队首元素
                    proQueue.poll();//将队首元素弹出
                    proQueue.add(new int[]{value,count});//在队列添加元素(需要按照定义的顺序插入)
                 }
            }else{
                proQueue.add(new int[]{value,count});
            }
        }

        int[] res=new int[k];
        int i=k-1;
        while(i>=0){//每次弹出队首元素,倒序放在数组(最高频率的在数组的最前面)
            res[i]=proQueue.poll()[0];
            i--;
        }
        return res;

    }
}

题:美团笔试题—先按照很高排序,身高相等按照名字字典排序

PriorityQueue版本+使用String的字典顺序比较两个字符串

在这里插入图片描述

public class Solution2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String numInf = scanner.nextLine();
        int num=Integer.parseInt(numInf);

        String heightInf=scanner.nextLine();
        String nameInf=scanner.nextLine();
        String[] heightInfArr=heightInf.split(" ");
        int[] heightArr=new int[num];
        for(int i=0;i<num;i++){
            heightArr[i]=Integer.parseInt(heightInfArr[i]);
        }
        String[] nameArr=nameInf.split(" ");

        //使用map进行封装
        Map<String,Integer> map=new HashMap<>();
        for(int i=0;i<num;i++){
            map.put(nameArr[i],heightArr[i]);
        }

        Set<Map.Entry<String, Integer>> entries = map.entrySet();

        PriorityQueue<String[]> pro=new PriorityQueue<String[]>(new Comparator<>() {
            @Override
            public int compare(String[] o1, String[] o2) {
                int h1=Integer.parseInt(o1[1]);
                int h2=Integer.parseInt(o2[1]);
                if(h1==h2){
                    return o1[0].compareTo(o2[0]);//如果身高相等,按照字典排序名字(使用String本身的字典排序比较器)
                }else{
                    return Integer.compare(h1,h2);//身高不相等先按照身高排序
                }
            }
        });

        for (Map.Entry<String, Integer> entry : entries) {
            pro.offer(new String[]{entry.getKey(),entry.getValue()+""});
        }


        StringBuilder sb=new StringBuilder();
        for(int i=0;i<num;i++){
            sb.append(pro.poll()[0]);//注意PriorityQueue的poll()是从头部弹出数据的
            if(i<num-1){
                sb.append(" ");
            }
        }


        System.out.println(sb.toString());


    }
}

TreeMap版本(key本身按照字典排序)+自定义比较器按照值排序

public class Solution2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String numInf = scanner.nextLine();
        int num=Integer.parseInt(numInf);

        String heightInf=scanner.nextLine();
        String nameInf=scanner.nextLine();
        String[] heightInfArr=heightInf.split(" ");
        int[] heightArr=new int[num];
        for(int i=0;i<num;i++){
            heightArr[i]=Integer.parseInt(heightInfArr[i]);
        }
        String[] nameArr=nameInf.split(" ");

        //使用treemap对键按照字典排序,自定义比较器按照值进行排序
        Map<String,Integer> map=new TreeMap<>();
        for(int i=0;i<num;i++){
            map.put(nameArr[i],heightArr[i]);
        }

        List<Map.Entry<String, Integer>> entries = new ArrayList<>(map.entrySet());
        Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o1.getValue()-o2.getValue();
            }
        });//(o1,o2)->o1.getValue()-o2.getValue(),使用lambda表达式
        

        StringBuilder sb=new StringBuilder();
        int count=0;
        for (Map.Entry<String, Integer> entry : entries) {
            sb.append(entry.getKey());
            count++;
            if(count<num){
                sb.append(" ");
            }
        }
        System.out.println(sb.toString());


    }
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值