day26--Java集合09
Java集合09
18.TreeSet
- 元素无序:插入顺序和输出顺序不一致
- 可以按照一定的规则进行排序,具体排序方式取决于构造方法:
- TreeSet () :根据其元素的自然排序进行排序
- TreeSet (Comparator comparator) :根据指定的比较器进行排序
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,不包含重复元素
[TreeSet集合的理解(自然排序和比较器排序)-CSDN博客]
例子:
package li.collection.set.treeset;
import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings("all")
public class TreeSet_ {
public static void main(String[] args) {
//TreeSet treeSet = new TreeSet();
TreeSet treeSet = new TreeSet(new Comparator() {//匿名内部类
@Override
public int compare(Object o1, Object o2) {
//下面调用String的compareTo方法进行字符串的小的比较
return ((String)o2).compareTo((String)o1);//从大到小
}
});
//添加数据
treeSet.add("lucy");
treeSet.add("bob");
treeSet.add("smith");
treeSet.add("join");
treeSet.add("mary");
treeSet.add("q");
System.out.println(treeSet);//[smith, q, mary, lucy, join, bob]
}
}
当我们使用无参构造器 创建TreeSet时,会有一个默认的比较器
TreeSet可以对集合中的元素进行排序,在添加元素的时候会自动去调用Comparable接口的compareTo方法
有些泛型类已经写好了排序规则,比如String 和 Integer 都已经实现了Comparable接口,也重写了compareTo方法
现在希望添加的元素按照字符串大小来排序
使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类),并指定排序规则
TreeSet treeSet = new TreeSet(new Comparator() {//匿名内部类
@Override
public int compare(Object o1, Object o2) {
//下面调用String的compareTo方法进行字符串的小的比较
return ((String)o2).compareTo((String)o1);//从大到小
}
});
简单看看源码
4.1 构造器把传入的比较器对象付赋给了TreeSet底层TreeMap的属性this.comparator
4.2在调用
treeSet.add("lucy")时,在底层会执行到:if (cpr != null) {//cpr就是我们的匿名内部类(对象)
do {
parent = t;
cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类(对象)的compareTo方法
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else//如果相等,即返回0,这个key就没有加入
return t.setValue(value);
} while (t != null);
}
思考:如果要求加入的元素按照长度大小排序该怎么写?
package li.collection.set.treeset;
import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings("all")
public class TreeSet_ {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new Comparator() {//匿名内部类
@Override
public int compare(Object o1, Object o2) {
//按照长度大小排序
return ((String)o2).length()-((String)o1).length();//长度从大到小
}
});
treeSet.add("lucy");
treeSet.add("bob");
treeSet.add("q");
System.out.println(treeSet);//[lucy, bob, q]
}
}
问:如果此时再使用add()方法添加一个"jack"字符串,这个字符串可以添加进treeSet吗?

如上图,答案是不能。之前已经说过,在使用add()方法时,底层会调用:
if (cpr != null) {//cpr就是我们的匿名内部类(对象)
do {
parent = t;
cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类(对象)的compareTo方法
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else//如果相等,即返回0,这个key就没有加入
return t.setValue(value);
} while (t != null);
}
由于我们重写了compareTo方法,方法此时返回的是两个元素长度之差。
在do...while循环比较时,因为在加入“jack”之前已经有一个相同长度为4的字符串“lucy”,所以compareTo返回的值为0,即cmp=0,执行语句return t.setValue(value);
即 认为是同一个key,因此“jack”无法加入集合treeSet
19.TreeMap

例子:
package li.map.treemap;
import java.util.Comparator;
import java.util.TreeMap;
@SuppressWarnings("all")
public class TreeMap_ {
public static void main(String[] args) {
//使用默认的构造器穿件TreeMap,是无序的(也没有排序)
//要求:按照传入的字符串(key)的大小进行排序
//TreeMap treeMap = new TreeMap();
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//按照传入的字符串(key)的大小进行排序
//return ((String)o2).compareTo((String)o1);
//按照key的字符串长度大小排序
return ((String)o2).length()-((String)o1).length();
}
});
treeMap.put("jack","杰克");
treeMap.put("tom","汤姆");
treeMap.put("kristina","克里斯提诺");
treeMap.put("smith","史密斯");
System.out.println(treeMap);//按照key的长度排序
// {kristina=克里斯提诺, smith=史密斯, jack=杰克, tom=汤姆}
}
}
如下图:打上断点,点击debug,点击force step into进入到构造器中

- 把传入的实现了Comparator接口的匿名内部类(对象),传给 了TreeMap的comparator属性

接下来调用put方法:
public V put(K key, V value)
{
// 先以 t 保存链表的 root 节点
Entry<K,V> t = root;
// 如果 t==null,表明是一个空链表,即该 TreeMap 里没有任何 Entry
if (t == null)
{
// 将新的 key-value 创建一个 Entry,并将该 Entry 作为 root
root = new Entry<K,V>(key, value, null);
// 设置该 Map 集合的 size 为 1,代表包含一个 Entry
size = 1;
// 记录修改次数为 1
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
Comparator<? super K> cpr = comparator;
// 如果比较器 cpr 不为 null,即表明采用定制排序
if (cpr != null)
{
do {
// 使用 parent 上次循环后的 t 所引用的 Entry
parent = t;
// 拿新插入 key 和 t 的 key 进行比较
cmp = cpr.compare(key, t.key);
// 如果新插入的 key 小于 t 的 key,t 等于 t 的左边节点
if (cmp < 0)
t = t.left;
// 如果新插入的 key 大于 t 的 key,t 等于 t 的右边节点
else if (cmp > 0)
t = t.right;
// 如果两个 key 相等,新的 value 覆盖原有的 value,
// 并返回原有的 value
else
return t.setValue(value);
} while (t != null);
}
else
{
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
// 使用 parent 上次循环后的 t 所引用的 Entry
parent = t;
// 拿新插入 key 和 t 的 key 进行比较
cmp = k.compareTo(t.key);
// 如果新插入的 key 小于 t 的 key,t 等于 t 的左边节点
if (cmp < 0)
t = t.left;
// 如果新插入的 key 大于 t 的 key,t 等于 t 的右边节点
else if (cmp > 0)
t = t.right;
// 如果两个 key 相等,新的 value 覆盖原有的 value,
// 并返回原有的 value
else
return t.setValue(value);
} while (t != null);
}
// 将新插入的节点作为 parent 节点的子节点
Entry<K,V> e = new Entry<K,V>(key, value, parent);
// 如果新插入 key 小于 parent 的 key,则 e 作为 parent 的左子节点
if (cmp < 0)
parent.left = e;
// 如果新插入 key 小于 parent 的 key,则 e 作为 parent 的右子节点
else
parent.right = e;
// 修复红黑树
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
2.1第一次添加时,把 k-v 封装到Entry对象中,并放入root
// 先以 t 保存链表的 root 节点
Entry<K,V> t = root;
// 如果 t==null,表明是一个空链表,即该 TreeMap 里没有任何 Entry
if (t == null)
{
// 将新的 key-value 创建一个 Entry,并将该 Entry 作为 root
root = new Entry<K,V>(key, value, null);
// 设置该 Map 集合的 size 为 1,代表包含一个 Entry
size = 1;
// 记录修改次数为 1
modCount++;
return null;
}
2.2 之后的添加:
Comparator<? super K> cpr = comparator;
// 如果比较器 cpr 不为 null,即表明采用定制排序
if (cpr != null)
{
do {
// 使用 parent 上次循环后的 t 所引用的 Entry
parent = t;
// 拿新插入 key 和 t 的 key 进行比较
cmp = cpr.compare(key, t.key);
// 如果新插入的 key 小于 t 的 key,t 等于 t 的左边节点
if (cmp < 0)
t = t.left;
// 如果新插入的 key 大于 t 的 key,t 等于 t 的右边节点
else if (cmp > 0)
t = t.right;
// 如果两个 key 相等,新的 value 覆盖原有的 value,
// 并返回原有的 value
else
return t.setValue(value);
} while (t != null);
}
思考:重写了compareTo方法之后,现在比较的是key的长度。如果在treeMap集合中加入K-V,该key与集合中的某个key长度相同,结果会如何?
答案:key不会被替换,但是value值会被最新的替换

20.Collections工具类
20.1排序
- Collections是一个提供操作Set、List和Map等集合的工具类
- Collections中提供了一系列静态的方法,对集合元素进行排序、查询和修改等操作
排序操作:
reverse(List):反转List中元素的顺序
shuffle(List):对List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定List集合元素进行升序排序
sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
swap(List,int,int):将制定List集合中的 i 处元素和 j 处元素进行交换
排序操作例子:
package li.collection.collectionskit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@SuppressWarnings("all")
public class Collections_ {
public static void main(String[] args) {
//创建一个ArrayList集合用于测试
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
//- reverse(List):反转List中元素的顺序
Collections.reverse(list);
System.out.println("reverse:" + list);//[milan, king, smith, tom]
//- shuffle(List):对List集合元素进行随机排序
Collections.shuffle(list);
System.out.println("shuffle:" + list);//每一次输出的顺序都不一样
//- sort(List):根据元素的自然顺序对指定List集合元素进行升序排序
Collections.sort(list);
System.out.println("自然排序后" + list);//自然排序是按照字符串的大小来排的
//- sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
//指定排序规,例如希望按照字符串的长度大小来排序
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String) o1).length() - ((String) o2).length();
}
});
//注意这里可以输出字符串长度相同的字符,因为是list,允许重复,不用比较key
System.out.println("按字符串长度大小排序:" + list);//按照字符串长度大小排序:[tom, king, milan, smith]
//- swap(List,int,int):将制定List集合中的 i 处元素和 j 处元素进行交换
Collections.swap(list,1,3 );
System.out.println("交换后的排序:"+list);
}
}

20.2查找、替换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
- Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素
- Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
例子:
package li.collection.collectionskit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@SuppressWarnings("all")
public class Collections_ {
public static void main(String[] args) {
//创建一个ArrayList集合用于测试
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
//1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("自然顺序最大元素:" + Collections.max(list));//自然顺序最大元素:tom
//2. Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
//比如返回长度最大的元素
Object maxObject = Collections.max(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String) o1).length() - ((String) o2).length();
}
});
System.out.println("长度最大的元素:"+maxObject);//长度最大的元素:smith
//3. Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素
System.out.println("自然顺序最小元素:" + Collections.min(list));//自然顺序最小元素:king
//4. Object min(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最小元素
//比如返回长度最大的元素
Object minObject = Collections.min(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String) o1).length() - ((String) o2).length();
}
});
System.out.println("长度最小的元素:"+minObject);//长度最小的元素:tom
//5. int frequency(Collection,Object):返回指定集合中指定元素的出现次数
System.out.println(""+Collections.frequency(list,"tom"));// 1
//6. void copy(List dest,List src):将src中的内容复制到dest中
//拷贝:注意如果要拷贝的集合大于新的集合,就会抛出异常--Source does not fit in dest
//因此我们需要先给dest赋值,使元素个数和 list.suze()一样
ArrayList dest = new ArrayList();
for (int i = 0; i < list.size(); i++) {
dest.add("");
}
Collections.copy(dest,list);
System.out.println("dest:"+dest);//dest:[tom, smith, king, milan]
//7. boolean replaceAll(List list,Object oldVal,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
//例如,如果集合中有tom,就替换成 汤姆
Collections.replaceAll(list,"tom","汤姆");
System.out.println("替换后:"+list);//替换后:替换后:[汤姆, smith, king, milan]
}
}

day26--Java集合09的更多相关文章
- Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java集合框架练习-计算表达式的值
最近在看<算法>这本书,正好看到一个计算表达式的问题,于是就打算写一下,也正好熟悉一下Java集合框架的使用,大致测试了一下,没啥问题. import java.util.*; /* * ...
- Java 集合系列目录(Category)
下面是最近总结的Java集合(JDK1.6.0_45)相关文章的目录. 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 03. Java 集合系 ...
- Java集合的10个最常见问题
以下是一些在Stackoverflow上经常被问起的与Java集合相关的问题.在你查阅这些问题之前,最好先去看看[Simple Java]Java集合框架的接口和类层次关系结构图. 什么时候优先选择L ...
- Java 集合系列08之 List总结(LinkedList, ArrayList等使用场景和性能分析)
概要 前面,我们学完了List的全部内容(ArrayList, LinkedList, Vector, Stack). Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例 Ja ...
- Java 集合系列 10 Hashtable详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java 集合系列 17 TreeSet
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java 集合系列 16 HashSet
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java 集合系列 15 Map总结
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java 集合系列 14 hashCode
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
随机推荐
- [奶奶看了都会]ChatGPT接入企业微信成为聊天机器人
1.聊天效果 上次给大家讲了ChatGPT接入个人微信的方法,但是个人微信容易被封号.这次就教大家接入企业微信,不会再被封号哦~ 话不多说,直接看机器人的聊天效果.基本能实现ChatGPT的聊天效果了 ...
- 覆盖第三方jar包中的某一个类。妙!!
在我们日常的开发中,经常需要使用第三方的jar包,但是很多时候总是会发现第三方的jar包中的某一个类,有问题,但是又无法继承,因为你继承后 变成了你自己的,jar包中 调用的 还是 他自己内部包含的, ...
- ThinkPHP 6.0 SQL注入漏洞修复
公司买的官网被政府网安检测出SQL注入漏洞: 隐患描述 SQL漏洞证明语句: python3 sqlmap.py -u "http://xxxx?keywords=1" -p ke ...
- 《ASP.NET Core 微服务实战》-- 读书笔记(第9章)
第 9 章 微服务系统的配置 微服务系统中的配置需要关注更多其他方面的因素,包括: 配置值的安全读写 值变更的审计能力 配置信息源本身的韧性和可靠性 少量的环境变量难以承载大型.复杂的配置信息 应用要 ...
- 探索C语言的内存魔法:动态内存管理解析
欢迎大家来到贝蒂大讲堂 养成好习惯,先赞后看哦~ 所属专栏:C语言学习 贝蒂的主页:Betty's blog 1. 静态开辟内存 通过前面的学习,我们已经掌握了两种开辟内存的方法,分别是: #incl ...
- OI中的一些数学小技巧
在OI比赛中,如果能够灵活地运用一些数学小技巧,是能够很好地优化计算的时间和正确性的. 既然说了是小技巧,那么这些指的都是一些技巧,一般是不会单独成题的. 本博客或会随着作者的见识而更新 Better ...
- NC20272 [SCOI2009]生日快乐
题目链接 题目 题目描述 windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕.现在包括windy ,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积 ...
- ARM指针寄存器——堆栈指针寄存器SP、程序计数器PC、连接寄存器LR详解
堆栈的实现方法 在随机存储器区划出一块区域作为堆栈区,数据可以一个个顺序地存入(压入)到这个区域之中,这个过程称为'压栈'(push ).通常用一个指针(堆栈指针 SP-StackPointer ...
- Springboot集成Swagger实战
1.介绍 本文将通过实战介绍Springboot如何集成swagger2,以用户管理模块为例,实现项目接口文档的在线管理. 项目源码 本文只列出核心部分,详细请看源码: https://gitee.c ...
- SpringBoot+MybatisPlus实现关联表查询
1.说明 最近写代码用到了mybatisPlus涉及到关联表查询.需求是这样的: 我有一个专业表major其中有个字段是所属院系dept_id,我需要通过这个dept_id关联院系表departmen ...