day15_集合

news2024/12/16 11:42:28

今日内容

1.复习
2.LinkedList
3.Set(HashSet、TreeSet)
4.Map(HashMap)

一、复习

List集合的特点?

  • 有序,允许重复

ArrayList的底层实现原理,以及特点

  • 数组,初始10,扩容1.5倍
  • 查询更新快,删插入慢
  • 解释为什么快,慢?

增强for循环语法

写出以下几个集合的方法签名

  • 向集合添加元素 boolean add(E e)
  • 向集合指定下标处添加指定元素 void add(int index,E e)
  • 根据下标查询集合中元素 E get(int index)
  • 查询集合的大小 int size()

二、LinkedList[熟悉]

LinkedList是List的实现类,那么LinkedList也是允许重复,有序
且LinkedList集合也有关于下标操作集合的方法,但是还提供了一些关于操作开头和结尾的方法

底层是使用链表实现.

2.1 演示方法

    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>( );
        list.add(3);
        list.add(1);
        list.add(1);
        list.add(4);
        list.add(4);
        list.add(2);
        // 有序,允许重复
        System.out.println(list );
        // 且也有关于的下标的操作方法
        list.add(0,0);
        System.out.println(list );
        Integer e = list.get(1);
        System.out.println(e );
        // 也可以遍历
        for (Integer i : list) {
            System.out.println(i );
        }

        // 专门提供了关于头尾的操作
        list.addFirst(-1);
        list.addLast(8);

        System.out.println(list );

        /**
         * 类似还有
         * getFirst
         * getLast
         * removeFirst
         * removeLast
         */
    }

2.2 底层原理

底层是双向链表实现,空间不连续

虽然有下标,但是不能直接定位元素,是通过位运算判断下标离左边还是右边近,然后再从左边或者右边一个个的挨个查的 —> 所以查询慢

但是又因为空间不连续,插入删除时不影响其他元素,相对于ArrayList更快

image-20231027101219000

2.3 特点

  1. 有序
  2. 允许重复
  3. 查找,更新时效率比较低
  4. 插入,删除时效率比较高

三、Set

Set是Collection集合的子接口,主要特性是不允许重复元素

Set接口中的操作集合的API与Collection中一模一样

Set接口有两个主要的实现类:HashSet,TreeSet

3.1、HashSet[重点]

HashSet类实现了Set接口,也是不允许重复元素

HashSet集合底层是HashMap(哈希表),存储的元素无序,无序是指迭代顺序和插入顺序不一致

不保证线程安全,线程不同步

3.1.1 方法演示

构造方法

  • HashSet() 构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16加载因子是 0.75
  • HashSet(Collection<? extends E> c) 构造一个包含指定 collection 中的元素的新 set
  • HashSet(int initialCapacity) 构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。
  • HashSet(int initialCapacity, float loadFactor) 构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。

方法

HashSet类中的方法与父接口Set接口中的方法一致,即又跟Collection接口中方法一致,无特殊方法,没有关于的下标的方法

    public static void main(String[] args) {
        HashSet<Integer> set = new HashSet<>( );
        boolean r1 = set.add(31);
        System.out.println(r1 );

        boolean r2 = set.add(11);
        System.out.println(r2 );

        // set集合不允许重复
        boolean r3 = set.add(11);
        System.out.println(r3 );

        set.add(41);
        set.add(41);
        set.add(21);

        // 遍历顺序和插入顺序不一致
        for (Integer i : set) {
            System.out.println(i );
        }

        // 自习演示
        // 添加,删除,大小,判断(空,包含),遍历
    }

3.2.2 扩容机制[面试]

HashSet底层HashMap,其实是Hash表,存储数据是散列存储
可以理解为存储进去是随机的

默认初始容量16,加载因子0.75 —> 扩容的阈值= 容量 * 因子 = 16 * 0.75 = 12
即超过12个元素时就要触发扩容,扩容成原来的2倍

(ps: 初始容量和加载因子是可以通过构造方法创建时修改的…)

3.2.3 去重原理[面试]

练习1: 将学生存储到HashSet集合中,如果属性一致则去重

  1. 调用add(E e)方法时,会在底层调用元素e的hashcode方法来获得对象的地址值
  2. 如果地址值不一样,直接存储
  3. 如果地址值一样时,会再调用元素的equals方法判断元素的内容是否一样
  4. 如果equals为false,那么存储 但是如果equals判断值为true,那么去重

总结: 以后只需要使用工具生成hashcode和equals就可以再HashSet中去重!

package com.qf.set;

import java.util.HashSet;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class TestHashSet2 {

    public static void main(String[] args) {

       /**
         * 调用hashcode获得地址值
         *  如果地址值不一样,直接存储
         *  如果地址值一样,也没有直接舍弃不存储,而是再调用
         * equals判断对象内容
         *  如果内容判断不一样,存储
         *  如果内容一样,舍弃不存储
         */
        HashSet<Student> set = new HashSet<>( );
        set.add(new Student(18,"张三"));
        System.out.println("------------------" );
        set.add(new Student(18,"张三"));
        System.out.println("------------------" );
        set.add(new Student(19,"李四"));
        System.out.println("------------------" );
        set.add(new Student(19,"李四"));
        System.out.println("------------------" );
        set.add(new Student(20,"王五"));
        System.out.println("------------------" );

        for (Student student : set) {
            System.out.println(student );
        }
    }
}
// Student类要重写hashcode和equals
package com.qf.set;

import java.util.Objects;

public class Student {
    private int age;
    private String name;
    // idea 生成hashcode和equals方法
    @Override
    public boolean equals(Object o) {
        System.out.println("equals()...." );
        if (this == o) return true;
        if (o == null || getClass( ) != o.getClass( )) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name);
    }

     // setget toString 构造...
}

3.2 TreeSet[了解]

TreeSet基于TreeMap,TreeMap底层是红黑树(一种平衡二叉树),会实现对存储的元素排序

TreeSet是Set集合的实现,也是不允许重复

   public static void main(String[] args) {

        TreeSet<Integer> set = new TreeSet<>( );
        set.add(33); 
        set.add(3);
        set.add(3);// 3 存储不了,去重
        set.add(41);
        set.add(11);
        set.add(12);
        System.out.println(set );// 迭代有顺序,默认是升序
    }

四、Map<K,V>[重点]

Map代表双列集合,一次存储一对键值对(K,V)

Map是接口,代表是键映射到值的对象,一个Map不能包含重复的键,值允许重复

每个键最多只能映射到一个值,

可以通过键找到值,但是不能通过值找键.

方法都是非常常见的方法,但是Map是接口无法演示

Map有两个常用实现类

  • HashMap
  • TreeMap

4.1 HashMap[重点]

HashMap是Map的实现类,现在JDK8及以后底层是由数组+链表+红黑树实现
并允许使用 null 值和 null

HashMap存储的元素是不保证迭代顺序,存储的键不允许重复,值允许重复


除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同


补充: Hashtable是线程安全的map集合(Hashtable是不允许null值null键),效率低 ; HashMap是线程不安全的,效率高
ConcurrentHashMap 即安全又高效的Map集合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

HashMap的容量和扩容: 初始容量16,加载因子0.75 阈值是 16 * 0.75,达到阈值扩容至原来的2倍
ps: 昨天学习的HashSet所有特性,其实就是HashMap的特性,包括去重原理

4.1.1 方法演示

构造方法

HashMap()
构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity)
构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
HashMap(int initialCapacity, float loadFactor)
构造一个带指定初始容量和加载因子的空 HashMap。
HashMap(Map<? extends K,? extends V> m)
构造一个映射关系与指定 Map 相同的新 HashMap。

方法

每个都很重要!!!

    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>( );
        map.put("A",1);
        map.put("B",2);
        map.put("C",3);
        map.put("D",4);
        System.out.println("初始map:"+map );

        // 通过键获得值
        Integer v = map.get("E");// 找不到返回null
        Integer v2 = map.get("B");
        System.out.println("键找值: "+ v2 );

        // 根据键移除整个键值对,返回值
        Integer a = map.remove("A");
        System.out.println("移除键A,返回值 " + a );

        System.out.println("移除后"+map );

        // 大小
        int size = map.size( );
        System.out.println("size:"+size );

        // 判断是否为空
        System.out.println("是否为空: "+map.isEmpty() );
        // 清空
        map.clear();
        System.out.println("是否为空: "+map.isEmpty() );

        // boolean containsKey(Object key)
        // 判断集合是否包含键
        //  boolean containsValue(Object value)
        // 判断集合是否包含值
    }

    private static void show1() {
        HashMap<String, Integer> map = new HashMap<>( );
        System.out.println(map );
        // 存储数据 V put(K k,V v)
        // 返回值是该键之前的值
        Integer old = map.put("A", 1);
        // 存储相同的键,键不保留,但是值会替换
        Integer old2 = map.put("A", 2);
        System.out.println(old +"----"+old2 );

        // 值允许重复,值2可以保留
        map.put("C",2);
        map.put("D",4);
        map.put("B",2);

        // 无序,键不能重复,值允许重复
        System.out.println(map );
    }

4.1.2 迭代/遍历

Map集合本身并没有设计独立的迭代Map的方法,但是

Map 接口提供三种collection 视图,允许以键集、值集或键-值映射关系集的形式查看某个Map的内容

  • Set keySet() 键集,返回一个Set集合,其中只有键
  • Collection values() 值集,返回一个Collection集合,其中只有值
  • Set<Map.Entry<K,V>> entrySet() 键值映射集,返回一个Set集合,其中放着key-value对象

4.1.3 键集

 		// 键集,返回一个集合,只有键
        Set<Integer> keySet = map.keySet();
        Iterator<Integer> iterator = keySet.iterator( );
        while (iterator.hasNext( )) {
            System.out.println(iterator.next() );
        }
        System.out.println("------------" );
        for (Integer key : keySet) {
            System.out.println(key );
        }

4.1.4 值集

       // 值集,返回一个集合,只有值
        Collection<String> values = map.values();
        Iterator<String> iterator1 = values.iterator( );
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next() );
        }
        System.out.println("-------------" );
        for(String value : values) {
            System.out.println(value );
        }

4.1.5 键值映射集 [非常重要]

Entry是Map接口中的内部接口,代表是一个键值对,即包含键和值.
且该Entry接口中提供了关于操作单个键,值的方法

  • K getKey()
  • V getValue()
        // 调用entrySet方法返回Set集合,集合中存储的是Map.Entry
        // Entry是Map的内部接口,代表的是一项(键值对)
        Set<Map.Entry<Integer,String>> entrySet =  map.entrySet();
        Iterator<Map.Entry<Integer,String>> iterator2 = entrySet.iterator();
        while (iterator2.hasNext()) {
            // 从迭代器取出来的是Entry对象
            Map.Entry<Integer,String> entry = iterator2.next();
            // 通过entry对象可以获得键和值
            Integer key = entry.getKey( );
            String value = entry.getValue( );
            System.out.println(key +"-->" +value);
        }

        System.out.println("===============" );
        // 增强for
        for(Map.Entry<Integer,String> entry : entrySet) {
            Integer key = entry.getKey( );
            String value = entry.getValue( );
            System.out.println(key +"-->" +value);
        }

image-20230224151747098

4.1.6 去重原理

HashMap的键去重其实就是之前讲的HashSet的去重,因为HashSet底层就是HashMap

  1. 在创建HashSet时,其实在底层创建了HashMap

    image-20230224152026062
  2. 在向set中添加元素时,其实是向map的key上添加

    image-20230224152119890

所以HashMap的键的去重原理就是

  • 向键存储数据时,先调用键的hashcode()方法
  • 如果hashcode值不一样则直接存储
  • 如果hashcode值一样,再调用元素的equals()方法
    • 如果equals方法返回false,则存储
    • 如果equals方法返回true,则不存储

4.2 HashMap的应用

场景一: 适合有关联映射的场景

  • 电话 110 --> 警察
  • 行政区划 0371 --> 河南
  • 简称 豫 --> 河南
  • 身份 41011111 —> zhangsan
  public static void main(String[] args) {
        HashMap<String, String> m = new HashMap<>( );
        m.put("河南","豫");
        m.put("河北","冀");
        m.put("山西","晋");
        m.put("陕西","陕");
        m.put("安徽","皖");
        
  }

设计方法,传入字符串,输出该字符串中每个字符出现的次数,使用HashMap实现
例如: “abcHelloabcWorld”,输出 a出现2次,b出现2次,l出现3次,H出现1次

    // a --> 2
    // b --> 2
    public static void cishu(String str) {
        // key存字符,value存次数
        HashMap<String, Integer> map = new HashMap<>( );
        // 方案1: split("")
        // 方案2: toCharArray()
        // 方案3: 遍历字符串
        char[] chars = str.toCharArray( );
        for (char c : chars) {
            String s = String.valueOf(c);
            // 判断map是否有改字符
            boolean b = map.containsKey(s);
            if (!b) {// 不包含,则第一次存入
                map.put(s,1);
            }else{ // 之前有过该字符,次数+1
                Integer count = map.get(s);
                count++;
                map.put(s,count);
            }
        }
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet( );
        for (Map.Entry<String, Integer> entry : entrySet) {
            String key = entry.getKey( );
            Integer value = entry.getValue( );
            System.out.println("字符:"+key+"-->"+value+"次" );
        } 
    }

场景二:

Map --> java对象

public class User{
	private int id;
       private String username;
 //,,,
}
User user = new User();
user.setId(1);
user.setUsername("zs");
sout(user); // User{id=1,username=zs}

HashMap map = new HashMap();
map.put("id",1);
map.put("username","zs");
sout(map); // {id=1,username=zs}

五、集合总结

重点

  • ArrayList: 方法(创建,crud,遍历),实现原理,特点
  • HashSet: 方法,实现原理,特点

  • 集合遍历(迭代) 增强for循环一定要熟悉

熟悉了解

  • LinkedList 方法和实现原理
  • TreeSet 会排序

以后如何选择集合

  • 没有任何要求的,只是需要存储多个元素的 --> ArrayList
  • 如果要求插入顺序和遍历顺序一致 --> ArrayList
  • 如果要求保留重复元素 --> ArrayList
  • 如果要求去重 --> HashSet
  • 如果要求排序 --> TreeSet

以后存储的数据有关联的,用HashMap


其实经验上: 最最常用就俩: ArrayList,HashMap

HashMap map = new HashMap();
map.put(“id”,1);
map.put(“username”,“zs”);
sout(map); // {id=1,username=zs}

六、自学TreeMap,Collections

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1140669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity URP14.0 自定义后处理框架

目录 碎碎念一些基础CustomPostProcessing.csCustomPostProcessingFeature.csCustomPostProcessingPass.cs例子&#xff1a;BSC后处理shader&#xff08;BSC&#xff09;后处理cs脚本(BSC) 例子&#xff1a;ColorBlitPostProcessing.hlslColorBlit2.shaderColorBlit.cs文件 其他…

快捷键记录

文章目录 ctrlaltashftwinsWinRCtrlc和CtrlvCtrl -Xshell的复制粘贴ctrlalt&#xff08;鼠标跳出&#xff09;ctrl alt T ctrlalta 这是QQ/TIM的屏幕截图快捷键。截图成功后&#xff0c;会有一栏导航&#xff0c;可以对图片进行勾画、模糊、绘画、标号、撤回、翻译、提取文…

早停止(Early Stopping)-PyTorch版本(代码使用教程)

一、说明 记录自己使用早停法来解决过拟合问题的经历。 这里给出的是pytorch版本&#xff0c;需要tensorflow版本的&#xff0c;可以使用chatgpt转换&#xff0c;也可以自己转换。 二、原理 这个早停法的原理就是&#xff0c;对比你每次的验证loss&#xff0c;如果超过20epoch&…

AQS总结

详细分析地址&#xff1a;跳转 head等于NodeA&#xff0c;NodeA指向NodeB&#xff0c;NodeB指向NodeC&#xff0c; tail等于NodeC。 NodeA也就是持有线程的Node&#xff0c;阻塞队列是指NodeA后面的所有队列&#xff0c;NodeA不属于阻塞队列。 公平锁&#xff1a; A线程先进来…

广西厂家直销建筑模板,工程用木工板,多层胶合板批发

欢迎选购我们的产品&#xff1a;广西厂家直销的建筑模板。作为一家专业厂家&#xff0c;我们提供工程用木工板&#xff0c;采用标准尺寸的多层胶合板制作&#xff0c;具备出色的防潮耐磨性能和高周转次数。 1. 工程用途&#xff1a;我们的建筑模板专为各类工程使用而设计&#…

(echarts)雷达图封装相关总结及使用

(echarts)雷达图封装相关总结及使用 数据结构&#xff1a; 页面&#xff1a; <div id"chart4" style"height:420px;width: 100%;" />//雷达图 echartFour(obj) {var chartDom document.getElementById("chart4");var myChart echarts.i…

浙大做了一个可用于AI领域的学术会议问答LLMs

深度学习自然语言处理 原创作者&#xff1a;wkk 今天介绍一篇来自于浙江大学的一项研究&#xff0c;关于基于LLM进行人工智能领域内7个不同学术会议QA数据集的论文。 论文: Reliable Academic Conference Question Answering: A Study Based on Large Language Model地址: http…

网络攻击的发展

在当今数字化时代&#xff0c;网站被攻击已经成为常态&#xff0c;网络威胁愈演愈烈。这些攻击不仅威胁到企业的安全&#xff0c;还可能导致严重的商业危机。本文将探讨为什么网络流量攻击变得如此普遍和容易&#xff0c;并分析未来可能引发的商业危机。 ​ 网络流量攻击的普遍…

【博士每天一篇文献-算法】iCaRL_ Incremental Classifier and Representation Learning

阅读时间&#xff1a;2023-10-27 1 介绍 年份&#xff1a;2017 作者&#xff1a;Sylvestre-Alvise Rebuffi; Alexander Kolesnikov; Georg Sperl; Christoph H. Lampert &#xff0c;牛津大学 期刊&#xff1a;Proceedings of the IEEE conference on Computer Vision and Pa…

竞赛选题 深度学习图像修复算法 - opencv python 机器视觉

文章目录 0 前言2 什么是图像内容填充修复3 原理分析3.1 第一步&#xff1a;将图像理解为一个概率分布的样本3.2 补全图像 3.3 快速生成假图像3.4 生成对抗网络(Generative Adversarial Net, GAN) 的架构3.5 使用G(z)生成伪图像 4 在Tensorflow上构建DCGANs最后 0 前言 &#…

评比无代码低代码平台时,可以考虑以下几个方面

无代码低代码平台是近年来兴起的一种软件开发工具&#xff0c;它们旨在帮助非技术人员快速创建应用程序&#xff0c;而无需编写大量的代码。这些平台通过提供可视化的界面和预先构建的组件&#xff0c;使用户能够通过拖放和配置的方式来构建应用程序。选择无代码低代码平台时&a…

微信公众号点击打开地图导航

<h3 id"menu-location">地理位置接口</h3><span class"desc">使用微信内置地图查看位置接口</span><button class"btn btn_primary" id"openLocation">openLocation</button> <span class&quo…

发展高质量存储力,中国高科技力量聚浪成潮

中国信息通信研究院指出&#xff0c;在全球数字化转型与产业变革的浪潮下&#xff0c;算力正在成为改变全球竞争格局的关键力量。而根据最新的《算力基础设施高质量发展行动计划》&#xff0c;算力是集信息计算力、数据存储力和网络运载力于一体的新型生产力。当前&#xff0c;…

ORACLE-递归查询、树操作

1. 数据准备 -- 测试数据准备 DROP TABLE untifa_test;CREATE TABLE untifa_test(child_id NUMBER(10) NOT NULL, --子idtitle VARCHAR2(50), --标题relation_type VARCHAR(10) --关系,parent_id NUMBER(10) --父id );insert into untifa_test (CHILD_ID, TITLE, RELATION_TYP…

vite vue3 ts 使用sass 设置样式变量 和重置默认样式

1.安装scss 样式支持依赖 yarn add -D sass 2.使用sass <div><!-- 测试使用sass --><h1>测试使用sass</h1> </div><style scope lang"scss"> div {h1 {color: red;} } </style> 效果&#xff1a; 3.通过npm下载并复制…

MarkDown教程记录

什么是 Markdown? Markdown 是一款轻量级标记语言&#xff0c;不同于HTML (Hypertext Markup Language)&#xff0c;Markdown 的语法非常简单&#xff0c;且容易上手Markdown 以 纯文本格式 编写文档&#xff0c;依赖键盘而非鼠标&#xff0c;专注于写作本身&#xff0c;感受…

为什么把k8s比做操作系统:kubernetes与os的架构对比

你还在背八大件吗&#xff1f;不如把k8s的架构和os一起看&#xff0c;你会发现一些超有趣的事情&#xff01;本文旨在将k8s的架构和os做个对比&#xff0c;帮助读者理解为什么k8s要这么设计。 kubernetes架构 kubernetes架构中由master节点和minion节点组成&#xff0c;maste…

c++ deque 的使用

目录 1. deque 的介绍 2. deque 底层原理 3. deque 的迭代器 4. deque 的接口使用 5. deque 和 vector&#xff0c;list 的比较 1. deque 的介绍 下面是 deque 的介绍&#xff0c;来自于&#xff1a;deque - C Reference (cplusplus.com) 的翻译&#xff0c;您可以不用…

MobPush数智化推送,精准定位万圣节狂欢年轻一族

随着中秋十一黄金周的结束&#xff0c;2023年最后一个法定节假日也一去不复返&#xff0c;但是别急&#xff0c;今年还有另一场不放假的狂欢节日——万圣节&#xff0c;万圣节作为西方国家第四季度最为重要的营销节日之一&#xff0c;在国内年轻人群体中同样具有较大的影响力和…

字节流和处理流的对象反序列化问题

细节&#xff1a; 读写要保持一致 序列对象时&#xff0c;默认将里面的所有属性都进行序列化&#xff0c;但除了static或transient修饰的成员 要求序列化或反序列化对象&#xff0c;需要实现Serializable 序列化对象时&#xff0c;要求里面的属性也要实现序列化接口 序列化…