单列集合

news/2025/3/5 16:10:31/文章来源:https://www.cnblogs.com/vvyyds/p/18212661

介绍

集合分为两种,一种是单列集合,一种是双列集合

单列集合中

List系列集合添加元素是有序,可重复,有索引的

set系列集合添加元素是无序,不可重复,无索引的

Collection是单列集合的祖宗接口,所以全部的单列集合都可以使用它的方法

Collection基本方法

add方法,添加元素  如果向List系列中添加元素,则必定返回true,因为List系列允许重复;如果向Set系列中添加,如果里边已经有了该元素,则返回false,反之返回true

clear,清空所有元素

remove,删除元素  因为Collection是接口,里面定义的是共性的方法,所以不能通过索引删除,只能通过元素的对象进行删除,如果有则删除成功,返回true,如果删除的元素不存在,则删除失败返回false

contains 判断当前集合中是否有xx对象,Array List的contains方法底层代码如下

可见,contains方法是依赖于equals方法来进行操作,所以,如果想判断 有没有 与给定的对象 内容相同 的 自定义类型的对象,则需要在javabean类中重写equals方法

Java中equals()方法的使用_java中equals的用法-CSDN博客

isEmpty方法,为空返回true,不为空返回flase

size方法,返回集合长度,即元素个数

迭代器

如果到了最后一位仍然进行it.next(),抛出异常NoSuchElementException

迭代器遍历完毕,指针不会复位

循环中只能用一次next方法,因为hasNext方法只能判断有无下一个,不能判断有没有下一个的下一个,所以下面会抛出NoSuchElementException的异常,如下      所以hasNext和next方法,要一对一的配套使用

迭代器遍历时,不能用集合的方法进行增加或删除(抛出ConcurrentModificationException——并发修改异常),但是可以用迭代器的方法进行删除(添加要用列表迭代器),如下

迭代器执行时底层代码如下        modCount为集合变化次数(增删次数)

 

Collection遍历方式

迭代器遍历

增强for循环遍历

Lambda表达式遍历

增强for遍历

增强for遍历的底层就是迭代器,为了简化迭代器的代码书写的

是在jdk5之后出现的,内部原理是个Iterator迭代器

所有的单列集合和数组才能用增强for遍历

里面的s仅仅是一个临时变量,修改s不会修改原本的集合p,即值的拷贝,(但如果元素是自定义类型,是会改变的————来自弹幕,待考证)

Lambda表达式遍历

JDK8开始

forEach底层如下,它遍历集合,并将每一个元素交给action下的accept方法,所以我们需要自己去写accept方法

而Consumer是个函数接口,所以需要自己去写这个accept方法

大致遍历代码如下

Lambda表达式的格式是  () ->  { }

List

基本方法

包括ArrayList,LinkedList,Vector

特点是,有序,有索引,可重复

remove有两种

1、直接删除 remove(Object o)

2、通过索引删除指定位置的元素 remove(int Index)

比如集合对象为 1、2、3   ,存在元素1,此时remove(1)调用的是删除方法2,删除之后变为 1、3

因为在调用方法时,如果出现了方法重载的情况,优先调用实参和形参类型一致的函数,而第一个删除方法,Object o 的形参,还需要将实参1进行装箱,再删除

但如果想删除元素1,除了remove(0)外,也可以进行手动装箱,再按照 “优先调用实参和形参类型一致的函数” 的原理,删除元素1

set返回的是被修改的元素,也就是修改的位置上,修改之前的元素

遍历方法

迭代器遍历

增强for循环遍历

Lambda表达式遍历

普通for遍历(因为List存在索引)

列表迭代器——————涉及两个函数hasPrevious()和previous()和一个东西  listIterator

package List;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.function.Consumer;public class ListDemo3
{public static void main(String[] args){List<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");//普通迭代器遍历Iterator<String> it = list.iterator();while (it.hasNext()){String str = it.next();System.out.println(str);}System.out.println("=========================================");//增强for遍历for (String s:list){System.out.println(s);}System.out.println("=========================================");//forEach遍历list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("=========================================");//简化forEachlist.forEach(s-> System.out.println(s));System.out.println("=========================================");//普通for循环for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}System.out.println("=========================================");//列表迭代器ListIterator<String> it1 = list.listIterator();while (it1.hasNext()){String str =it1.next();if("bbb".equals(str)){it1.add("qqq");}}System.out.println(list);}
}

数据结构

双向链表在查询第N个元素时,可以先比较离头节点近还是尾节点近,进而加快查询速度

ArrayList

addALL是复制另一个ArrayList对象到当前ArrayList对象

底层原理

利用空参创建的集合,在底层创建一个长度为0的数组

添加第一个元素时,底层会创建一个长度为10的数组,过程如下图

jdk8源码      (grow为扩容代码)

如果长度为10的数组已经满了,执行下边的底层代码

比较原有长度/2和所添加的实际所需长度相比较,扩容大的长度,实际是新开一个数组,并将原数组的数据拷贝过去

LinkedList

底层是双向链表,查询慢,增删快

由于是双向链表,所以对首尾操作速度极快,所以多了很多对首尾进行操作的API

当对其添加元素时,涉及的函数和空间如下

泛型类

简介

JDK5引入,可以在编译阶段 约束 操作的数据类型,并进行检查

格式:<数据类型>

泛型只能支持引用数据类型,不能写基本类型

泛型优点

统一数据类型

把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来

泛型擦除

Java中的泛型实际是伪泛型,当添加数据时,编译器会检查添加的数据是否是泛型的数据类型,添加进去后仍然转成Object类,然后强制转换成泛型的数据类型进行各种操作

在.java文件是真的泛型,但编译成.class文件后泛型则不再存在,这个过程叫泛型擦除

细节

不能写基本数据类型

指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型

如果不屑泛型,类型默认是Object

可以用到的地方

泛型类

泛型方法

泛型接口

(代码在Generics2到4)

通配符

泛型不具有继承性,但是数据具有继承性

通配符的符号是‘  ? ’ 

二叉树

二叉树分类

二叉树    每个结点最多有两个分支

二叉查找树  每个结点最多有两个分支  左节点<当前节点<右节点

平衡二叉树  每个结点最多有两个分支  左节点<当前节点<右节点  每个节点的左子树和右子树,两者的高度差不超过1

平衡二叉树的旋转机制

关于平衡二叉树是如何形成的————是通过旋转机制保证  ”平衡“  二字的

旋转机制分为两种,一种是左旋,一种是右旋,旋转时候是当添加节点后,该树不再平衡,然后才旋转

左旋

以下图为例

加入节点12后,平衡二叉树不再平衡

 

如此,变为

例2

加入节点12后,不再平衡,此时从添加的节点依次往上找,第一个不平衡的节点为7,于是左旋,10晋升为新的父节点

然后多出来的节点9,按照平衡二叉树的定义,分给7节点的右节点

模拟动画如下

右旋

与左旋轴对称

需要旋转的四种情况

左左

只需要一次右旋

左右

此时仅仅一次右旋是不行的

此时应该先将紫色部分进行一次左旋,然后再进行整体的一次右旋

右右

右左

先局部右旋,再整体左旋

总结

红黑树

介绍

红黑树是一种自动平衡的二叉查找树,又称平衡二叉B树

每个节点都有自己的颜色——红/黑

红黑树不是高度平衡的,它的平衡是通过红黑规则来实现的

红黑树的增删改查功能都很好

平衡二叉树和红黑树的差异

红黑规则

每个节点是红色或者黑色

根节点必须是黑色

如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)

对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点     (后代,即子树上所有子节点    叶节点(即Nil)    简单路径:最直接就能到达,只能往前走不可回头的路径)

 右侧红色圆圈为每个节点所存储的信息

添加节点的规则

添加节点时,默认是红色的,因为效率高(需要修改的次数少)

具体如下图

上图中,“将XX设置为当前节点再进行其他判断”————指的是,将这个节点当作你新添加的节点,然后重新来一遍此图的流程

Set

特点

无序(存进去的顺序和在里面存储的顺序不同,比如你先存的2,再存进去1,在里面1在2前面)

不重复

无索引

实现类

HashSet  无序,不重复,无索引

LinkedHashSet  有序,不重复,无索引

TreeSet  可排序,不重复,无索引

方法

Set是个接口,而且Set接口继承于Collection接口,里面的方法基本上与Collection的API一致

HashSet

底层是用哈希表来存储数据

哈希表

哈希表对于增删改查的性能都挺好

JDK8之前是  数组 链表  来实现哈希表

JDK8之后是  数组 链表 红黑树 来实现哈希表

哈希值

哈希值————对象的整数表现形式

往哈希表里存元素,元素的索引(元素在表里的位置)是根据哈希值来决定————int index = (数组长度 - 1)& 哈希值

哈希值是根据hashCode方法计算出的int类型的整数,该方法定义在Object类中,所有对象都可以调用

hashCode方法默认使用地址值进行计算哈希值,所以一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希表

对象的哈希值特点

如果没有重写hashCode方法,不同对象计算出的哈希值是不同的,因为每个对象地址值是不一样的

如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的

在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)

哈希表底层创建原理

底层使用的数据结构

JDK8之前是  数组 链表  来实现哈希表

JDK8之后是  数组 链表 红黑树 来实现哈希表

创建——填充元素步骤

HashSet<String> hm = new HashSet<>();

1、创建一个默认长度为16,默认加载因子为0.75的名为table的一个数组

2、根据元素的哈希值跟数组的长度计算出应存入的位置    int index = (数组长度 - 1)& 哈希值

3、计算得出的索引index,如果此位置没有元素,为NULL,则直接把元素放进去

   但如果此索引上已经有元素了,就会调用equals方法去比较对象内部的属性值

4、如果比较结果一样,则不存,如果不一样,则存进去,存的位置见下图

(挂在下面————即两者/多者形成链表,JDK8之前是插入链表头部——头插,JKD8之后是插入链表尾部——尾插链表头部地址即为数组的那个索引的地址

扩容步骤

当存入了数组长度*加载因子个元素时,数组长度会扩容到原来长度的两倍

比如最开始是默认长度为16,默认加载因子为0.75,当里边有16*0.75=12个元素时,数组长度会从16变为32

当链表长度>8,而且数组长度 >= 64时,链表会自动转成红黑树,从而提高查找效率

注意点

JDK8以后,当链表长度超过8而且数组长度大于等于64时,自动转换为红黑树

如果集合中存储的是自定义对象,必须要重写hashCode和equals方法

HashSet为什么存和取顺序不一样

HashSet为什么没有索引

HashSet是利用什么机制保证数据去重的

利用HashCode方法和equals方法

一个是获取哈希值,一个是去比较内容是否相同

LinkHashSet

特点

有序(存储和取出的顺序一致),不重复,无索引

原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制 用来 记录存储的顺序

TreeSet

特点

不重复

无索引

可排序(按照元素的默认规则从小到大排序)——————对于默认数据类型可以这样,但对于自定义数据类型需要自己去写比较大小的规则

依次是  this<o  this>o  this==o

底层

基于红黑树实现排序,增删改查性能都很好

自定义数据类型的比较规则

一般使用默认排序,不符合需求才使用比较器排序

默认排序/自然排序

Javabean类实现Comparable接口,进而指定比较规则

this表示当前节点,o表示红黑树上每个节点,即当你在增加节点时,需要对每个节点都去调用这个方法,从而在最后判断出当前节点该放在红黑树的哪个地方,再然后进行红黑规则

比较器排序

创建TreeSet集合时,自定义Comparator比较器对象,指定比较规则

两者同时存在

如果默认排序和比较器排序都存在,排序时按比较器排序进行排序

使用场景

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黄河流域水土保持生态效应AI一体化评价平台

黄河流域作为我国北方重要的生态屏障,其生态保护和高质量发展一直是国家战略的重点。随着人工智能技术的飞速发展,黄河流域水土保持生态效应AI一体化评价平台的建设,标志着生态保护工作进入了一个新的阶段。本文将对这一平台的建设内容进行深度分析。1. 平台建设背景与意义黄…

使用PHP+HTML集成DeepSeek API,实现一个简单的聊天对话项目

项目效果预览1. 准备工作PHP环境:确保你的开发环境中安装了PHP。 DeepSeek API密钥:注册并获取DeepSeek API的访问密钥。2. 创建PHP文件,编写API调用脚本 创建一个PHP脚本(api.php),用于调用DeepSeek API。假设API密钥为YOUR_API_KEY。 <?php header(Content-Type: a…

(15)事件处理,表单绑定

可以参考官网https://cn.vuejs.org/guide/essentials/event-handling.html来学习 添加事件,处理事件,传递参数 监听事件​ 我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。 用法:v-on:click="handler" 或 @click=&quo…

nginx + lua + kafka实现日志监控

nginx + lua + kafka实现日志监控 前言 1)架构图:2)方案:1:线上请求打向nginx后,使用lua完成日志整理:如统一日志格式,过滤无效请求,分组等。 2:根据不同业务的nginx日志,划分不同的topic。 3:lua实现producter异步发送到kafka集群。 4:对不同日志感兴趣的业务组实时消费…

day 17思维导图

图上有知识的补充!

Causal learning

简单来看:Causal learning = To learn causal models/features from dataCausal research 里包括两种重要问题,一种是Causal learning,另一种是Causal reasoning(不同的文献有不同的分法和叫法,这里用Jonas Peters等人的书里的)。简单的说,前者想解决如何从数据中发现因…

AI科研到底能做什么?看完你就懂了!

0 前言 本专栏目标:能做什么? 要怎么做? 效果如何?本质: 多Agent实现从数据采集到可视化全流程 AIGC数据应用: 数据采集 通过编写爬虫代码、访问数据库、读取文件、调用API等方式,采集社交媒体数据、数据库内容、文本数据、接口数据等。 数据处理 通过数据清洗、数据集成…

gitlab+jenkins+harbor+k8s安装操作流程之gitlab

GitLab的安装及使用教程GitLab简介GitLab,是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目安装。 它拥有与GitHub类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏…

fastadmin视图文件调用common.php的公共函数

╰︶﹉⋛⋋⊱⋋๑๑⋌⊰⋌⋚﹉︶╯

linux内核编译输出文件:vmlinux/Image/zImage/uImage区别

当前目录 ./ 为linux kernel编译输出根目录: ./vmlinux是编译输出的原始elf文件,可用于调试; ./arch/arm/boot/Image是二进制文件,可用于烧录,文件较大,使用工具链objcopy从./vmlinux生成; ./arch/arm/boot/compressed/vmlinux是elf文件,先将./arch/arm/boot/Image用gz…

AI 造游戏,3 小时开发、9 天狂赚 12 万,这波风口你跟不跟?

​故事要从这个上海程序员说起​ 有个叫Pieter Levels的码农,之前在全球最大的远程办公平台Remote OK工作过。去年某天,他突然想做个能在线玩、还能赚钱的小游戏。结果他和AI搭档,只用了三个小时就捣鼓出了一个能手机玩的飞机大战游戏,上线十天狂揽28万人民币,连马斯克都发…

通义灵码上新推理模型,快来体验数学和编程双冠王 Qwen2.5-Max

近期,通义灵码上新了模型选择功能,除新增 DeepSeek 满血版 V3 和 R1 外, Qwen2.5-Max 也正式上线,它使用了超过 20 万亿 token 的预训练数据及精心设计的后训练方案进行训练。近期,通义灵码上新了模型选择功能,除新增 DeepSeek 满血版 V3 和 R1 外, Qwen2.5-Max 也正式上…