首页 > 其他分享 >List、Set与 Map

List、Set与 Map

时间:2023-10-21 23:11:05浏览次数:22  
标签:扩容 Map Set 指向 int List next 数组 节点

目录

1. List接口和常用方法

1.1 List接口基本介绍

1、返回集合长度
int size()
2、添加元素
void add(Object ele), void add(int index, Object ele)
3、添加多个元素
boolean addAll(int index, Collection eles)
4、获取指定index位置的元素
Object get(int index)
5、返回obj在集合中首次出现的位置
int indexOf(Object obj)
6、返回obj在集合中末次出现的位置
int lastIndexOf(Object obj)
7、移除指定index位置的元素,并返回此元素
Object remove(int index)
8、设置指定index位置的元素为ele,相当于替换,索引必须存在
Object set(int index, Object ele)
9、返回从fromIndex到toIndex位置的子集合,前闭后开
List subList(int fromIndex, int toIndex)

1.2 List接口的三种遍历方式

img

2. ArrayList

2.1 注意事项

img

2.2 ArrayList的底层操作机制源码分析(重点)

img

使用无参构造器

img

  • 可以看出elementData一开始是个空数组
    img
    img

  • 执行list.add(i)时,会先把int类型的i转化为Integer类型
    img

  • 然后执行add方法,首先确认数组大小够不够,然后再对数组元素赋值
    img

  • 如何确认数组大小够不够呢

    • 当数组为空时
      • 先设置数组需要的最小长度minCapacity为10
      • 然后判断数组需要的最小长度是否大于数组长度,此时一定大于,因为数组长度为0
      • 大于则扩容
    • 当数组不为空时
      • 先计算数组所需要的最小长度,即索引的位置+1,minCapacity=size+1
      • 然后计算当前数组的长度elementData.length
      • 判断数组所需的最小长度是否大于当前数组长度,大于则扩容(即当索引+1超出数组长度时,扩容)
    • 其中modCount用来记录集合被修改的次数
      img
      img
  • 如何扩容呢-调用grow函数

    • 当第一次扩容,即数组为空时,elementData.length=0
      • 通过位运算计算得到的newCapacity还是0,所以需要加个判断条件,给newCapacity赋值为minCapacity
      • 然后使用Arrays的copyOf方法进行数组扩容
    • 当不是第一次扩容时
      • 根据位运算在原来数组长度上扩大1.5倍得到,向下取整,newCapacity
      • 然后使用Arrays的copyOf方法进行数组扩容

img

使用有参构造器

img

  • 首先创建一个指定大小elementData数组
    img

  • 其它流程在无参构造器中以出现,不再重复

总结

  • 关键是维护一个elementData数组,当new一个对象时,
    • 使用无参构造时,它为空数组
    • 使用有参构造时,它的长度为传入的参数值,并且给elementData new一个长度为参数大小的数组
  • 当使用add方法时,首先会计算容器所需要的最小容量是多少,即minCapacity
    • 如果是空数组,设置最小容量为10
    • 如果不是,最小容量就是索引位置+1(size+1)
  • 然后判断这个最小容量是否大于数组长度
    • 如果大于,就说明要扩容了
    • 如果小于,什么也不干
  • 扩容时,扩容大小使用位操作计算,当前容量+右移一位,(右移一位会小一半),所以扩大1.5倍
    • 但是当容量为0时,0右移一位还是0,所以加了一个判断,给这个容量直接赋值为10

关键是维护一个elementData数组,如果是无参构造,一开始将elementData数组初始化为空数组,当执行添加操作时,需要第一次扩容到10,后面按1.5倍扩容;如果是有参构造,一开始将elementData的大小初始化为参数值,之后每次扩容按1.5倍扩,扩容是创建一个新数组,然后调用一个本地方法将原来数组的值复制到新数组

3. Vector

3.1 基本介绍

img

3.2 Vector与ArrayList的比较

img

3.3 源码分析

img

  • 首先通过构造方法设置数组初始容量,并创建一个指定长度的数组

    • 无参构造器默认设置初始容量为10
      • img
    • 有参构造器根据指定数值设置容量,扩容增量默认为0
      • img
    • 还可以自己设置扩容增量
      • img
  • 然后对int类型自动装箱

    • img
  • 接着执行add方法

    • 首先确认当前的容量大小是否需要扩容
      img
      img

    • 如果需要扩容,且设置了扩容增量capacityIncrement的话,就扩容这个值的大小,如果没设置扩容增量,就扩容原来的两倍
      img

  • 最后将数据添加到Vector集合中

3.4 总结

  • 如果是无参构造,直接默认创建一个初始容量为10的数组,之后每次需要扩容时,扩大两倍
  • 如果是有参构造,创建初始容量为指定值的数组,如果设置了扩容增量,之后每次扩容时,扩容后的大小等于当前容量+扩容增量,如果没设置扩容增量,则扩容两倍。

4. LinkedList

基本介绍

img
img

源码分析

add()函数

img

  • 首先通过无参构造方法初始化属性
    img
    img

  • 对int类型自动装箱后,执行add方法
    img

  • 其中最关键的方法是linkLast方法

    • 当linkList中没有元素时
      • 首先创建临时节点,使用l记录last的位置
      • 然后创建新节点,让它的pre指向临时节点、next指向null
      • 更新双指针的位置,将last和first都指向该新节点
    • 当linkList中有元素时
      • 首先创建临时节点,使用l记录last的位置
      • 然后创建新节点,让它的pre指向临时节点、next指向null
      • 然后让临时节点的next指针指向新节点
      • 大概思路是更新新节点和原来最后一个节点之间的pre和next指针指向
        img

remove()函数

  • 删除节点默认删除第一个节点
    img
    img
  1. 首先它直接调用了removeFirst()方法
    img
    img

  2. 真正删除第一个节点的方法是unLinkFirst()
    img

  • 首先使用临时变量保存原来first指向的节点 的元素值和next指针
  • 清空原来first指向的节点 的元素值和next指针
  • 改变first指针指向临时变量保存的next指针(即原来第二个节点)
    • 但next可能为null(即原list只有一个节点的情况)
      • 此时将last指针也指向null
    • 当next不为null
      • 将next指针(即新的第一个节点)的prev指向null
  • 此时已实现first指向原第二个节点,如果第二个节点为null,first和last都指向null
  • 最后返回删除的节点的元素值

总结:

  • 新增节点:先用临时变量记录最后一个节点,然后创建一个新节点,将新节点连接到原来链表上(新节点的pre指针指向临时节点,next指针指向null,最后临时节点的next指针指向新节点),更新last的位置,如果原来为空,还要将first也指向这个节点
  • 删除节点:先用临时节点保存第一个节点,然后清空第一个节点next指针和元素值,将firs指向第二个节点,如果这个节点为空,将last也指向它;
  • 总结:先用临时变量保存需要处理的节点,然后再处理该节点,特殊情况是只有一个节点或没有节点的时候,此时两个指针都要移动。

5. List集合选择

img

  • ArrayList可以通过索引直接定位
  • linkedlist通过遍历查找
    注意:线程都是不安全的
    补充:
    Alt+7:查看当前类的所有方法

Set接口


  • 常用方法和遍历方式

  • 存放顺序和取出顺序不一致,但是取出顺序是固定的

  • set接口对象不能通过索引获取,它没有get方法

HashSet


  • 注意:是当一条链表的个数达到8个,同时table元素达到64个,才会树化
  • 当一条链表达到8个了,但是元素少数64个,table会扩容

  • 扩容时,不是数组里的元素达到阈值才扩容,而是所有元素数量(包括链表上的)达到阈值就会扩容

HashSet的底层就是HashMap,只是在HashSet里,value是存放的一个常量对象,平时的操作只用key
当添加元素时,

Map接口

Node实现了Entry接口,Entry接口里有getKey和getValue方法,然后EntrySet集合里存放着Node类型的对象(多态)

遍历方式

  • 第一组:先取出所有的key,通过key取出对应的value
  • 第二组:把所有的value取出
  • 第三组:通过EntrySet 来获取 k-v

小结

HashMap底层

HashMap扩容机制

源码

  1. 执行构造器 new HashMap()
  2. 执行put,调用hash方法
  3. 执行putVal
  4. 关于转成红黑树

HashTable





集合选择

标签:扩容,Map,Set,指向,int,List,next,数组,节点
From: https://www.cnblogs.com/cheyaoyao/p/17779732.html

相关文章

  • 关于原始typescript实现todolist(装饰器模式)
    前言我是歌谣最好的种树是十年前其次是现在今天继续给大家带来的是原始typescript的讲解环境配置npminit-yyarnaddvite-D修改page.json配置端口{"name":"react_ts","version":"1.0.0","description":"","main":"index.......
  • Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法
    Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,此处测试代码如下,这里使用add方法:1publicclassmain{2publicstaticvoidmain(String[]args){3int[]num={1,2,3};4Listlist=Arrays.asList(num);5list.add(4);......
  • ioremap函数
    一、 ioremap()函数基础概念    几乎每一种外设都是通过读写设备上的相关寄存器来进行的,通常包括控制寄存器、状态寄存器和数据寄存器三大类,外设的寄存器通常被连续地编址。根据CPU体系结构的不同,CPU对IO端口的编址方式有两种:a--I/O映射方式(I/O-mapped)    ......
  • Java基础 File 常见的成员方法(获取并遍历)—— listFiles ()
    public File[] listFiles()  →  获取当前该路径文件夹下所有内容,把所有的内容放到数组中返回Filef=newFile("E:\\Java基础资料");File[]files=f.listFiles();for(Filefile:files){//file依次表示Java基础资料文件夹里面的每一个文件或者文件夹Sys......
  • Codeforces Round 857 (Div. 2) B. Settlement of Guinea Pigs
    你非常喜欢豚鼠。每个笼子可以住两只豚鼠,且你不想把每个笼子放入不同性别的豚鼠。豚鼠只有两种性别。假设你买到豚鼠时并不知道性别,只有医生能够分辨。接下来的\(n\)天方案中,若第\(i\)天为\(1\),你买入一只豚鼠;若为\(2\),你请医生分辨你的豚鼠性别。给出方案,你最少需要准......
  • Java List数据结构底层实现与常用实现类解析
    一、JavaList数据结构的底层实现原理List是Java中最常用的数据结构之一,它可以按照元素的插入顺序有序存储一组对象。在Java中,List接口有多种不同的实现方式,每种方式都有自己的底层实现机制。1.1数组实现ArrayList是List接口最常用的实现类之一,它使用数组作为底层数据结构。ArrayL......
  • 【大揭秘】美团面试题:ConcurrentHashMap和Hashtable有什么区别?一文解析!
    正文亲爱的小伙伴们,大家好!我是小米,一个热爱技术分享的程序员,今天我为大家带来了一篇有关美团面试题的热门话题:ConcurrentHashMap和Hashtable有什么区别。这个问题在Java面试中常常被拿来考察对多线程编程的理解,所以务必认真学习,不仅仅是为了通过面试,更是为了提高自己在多线程编......
  • You must reset your password using ALTER USER statement before executing this st
    安装mysql-5.7.32数据库时,初次登陆MySQL,执行如下命令获取临时密码,/var/log/mysqld.log为my.cnf中log-error配置项的内容:grep'temporarypassword'/var/log/mysqld.log获取临时密码:!.IRoNewC7xq,执行结果如下: 初次使用临时密码登录MySQL,查看MySQL数据库时......
  • 慎用智能指针的reset方法
    背景使用智能指针指向class的成员变量会导致指针Segmentationfault.复现直接看代码https://godbolt.org/z/Tnx45jraP#include<iostream>#include<memory>structHandler{intnum=7;};intmain(){Handlerhandler;std::shared_ptr<int>ptr=null......
  • Mysql FIND_IN_SET()用法
    MySQL中的FIND_IN_SET函数用于在逗号分隔的字符串列表中查找指定字符串的位置。它接受两个参数:要查找的字符串和逗号分隔的字符串列表。语法如下:FIND_IN_SET(string,string_list)其中,string是要查找的字符串,string_list是逗号分隔的字符串列表。返回值为待查找字符串......