Java中TreeMap集合讲解
1.TreeSet介绍
TreeSet是一个有序集合,可以以任意顺序将元素插入到集合中,在对集合进行遍历的时候,每个元素将自动按照排序后的顺序呈现。底层使用的是二叉树(更具体点是红黑树)实现,对于元素之间排序,如果不指定自定义的比较器Comparator,那么插入的对象必须实现Comparable接口,元素按照实现此接口的compareTo()方法去排序。如果指定了自定义的比较器Comparator,优先使用Comparator去对元素进行排序。比较规则决定了元素是否可以重复,以及元素的排序结果。
2.特点
- 保存的元素按照一定的规则有序
- 可自定义排序规则
- 非线程安全
3.存储Integer类型元素
import java.util.TreeSet;
public class DemoTreeSet {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(1); //自动装箱
ts.add(7);
ts.add(3);
ts.add(5);
ts.add(3); //重复元素
System.out.println(ts);
}
}
输出:[1, 3, 5, 7]
看上面代码的输出,不仅输出元素有序,而且去除了重复元素3,我们在存元素的时候,并不是按照1,3,5,7的顺序存储的,但是遍历却是按照顺序排列的。为什么呢?
前面我们说过,TreeSet在存对象的时候,如果不指定自定义的比较器,那么存储的对象必须实现Comparable接口,好,我们去看下Integer类有没有实现此接口。
public final class Integer extends Number implements Comparable<Integer> {
//省略其他代码
//......
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
}
分析:
通过Integer源码可知,它满足TreeSet的要求,实现了Comparable接口中唯一的抽象方法compareTo(),在此方法内部又调用了一个compare()方法去定义比较规则,返回值是0,1,或者-1。前面说过,TreeSet底层是二叉树实现的,当存储元素的时候,会调用比较规则方法和二叉树上的元素一一比较,如果要插入的元素比当前元素小就到左子树去比较,如果比当前元素大,就到右子树去比较,直到当前元素的左或者右子树为空,就插入此元素。如果在比较过程中,出现当前元素等于要插入的元素,那么此元素不插入,例如上例中最后一个元素3被过滤掉了,这样也就保证了Set的元素唯一性。
自定义比较器
前面说过,如果我们自定义了比较器Comparator,那么集合会优先使用自定义的比较器去对元素进行排序,好,我们现在想让集合中的Integer元素按照倒序排列,应该如何实现呢?先来查看JDK文档:
上图中红框标注的构造方法就是我们需要的,这里需要传入一个Comparator接口类型的对象,我们当然可以自定义一个类然后实现Comparator接口,然后再new一个对象当作参数传入TreeSet()的构造方法,但是为了方便,我们使用匿名类实现。在此之前,我们先看下Comparator接口都有什么抽象方法。
此接口只有两个抽象方法,我们先不用管equals()方法,定义排序规则需要在compare()这个方法。好,我们来实现一下集合中元素倒序排序。
import java.util.Comparator;
import java.util.TreeSet;
public class DemoTreeSet {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
if(o1 == o2) return 0;
return o1 < o2 ? 1 : -1;
}
});
ts.add(1); //自动装箱
ts.add(7);
ts.add(3);
ts.add(5);
ts.add(3);
System.out.println(ts);
}
}
输出:[7, 5, 3, 1]
分析:
1、读者可能发现,Comparator接口明明有两个抽象方法,为什么只实现了compare(),很简单。我们知道匿名类也是一个类,只要是类就会默认继承Object类,那么就会默认继承Object类的equals()方法,所以其实我们已经使用了从Object类继承的方法去实现了Comparator接口的equals()方法。
2、我们在compare()方法中定义了排序规则,和Integer类中实现的方式正好相反,小于返回1,大于返回-1,等于返回0,所以输出的元素就是倒序了。由于我们在TreeSet中自定义了比较器,所以Integer类的比较规则就失效了。
4.存储自定义对象
Student类
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
import java.util.TreeSet;
public class DemoTreeSet {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<>();
ts.add(new Student("张廷玉",43));
ts.add(new Student("纳兰明珠",80));
ts.add(new Student("索额图",79));
System.out.println(ts);
}
}
输出:
[Student [name=张廷玉, age=43], Student [name=索额图, age=79], Student [name=纳兰明珠, age=80]]
首先我们定义了一个Student类,前面说过,如果没有自定义比较器,TreeSet集合存储的对象元素必须实现Comparable接口,这里我们的Student类实现了此接口,并且实现了此接口的唯一抽象方法compareTo(),这里我们是按照学生年龄排序(升序)。如果这里不实现Comparable接口,那么会报 java.lang.ClassCastException异常,意思就是这里存的元素不是Comparable类型的。
自定义比较器
我们用自定义比较器来实现一个小案例。这里我们对学生首先按照年龄进行排序,如果年龄相同,我们再按照名字的长度进行排序,都是升序,来看看我们怎么实现它。
public class Student{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
import java.util.Comparator;
import java.util.TreeSet;
public class DemoTreeSet {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num = o1.getAge() - o2.getAge();
return num == 0 ? o1.getName().length() - o2.getName().length() : num;
}
});
ts.add(new Student("张廷玉",43));
ts.add(new Student("纳兰明珠",80));
ts.add(new Student("索额图",79));
ts.add(new Student("苏麻喇姑",79));
for (Student student : ts) {
System.out.println(student);
}
}
}
输出:
Student [name=张廷玉, age=43]
Student [name=索额图, age=79]
Student [name=苏麻喇姑, age=79]
Student [name=纳兰明珠, age=80]
由于我们在TreeSet中自定义了比较器,这里的Student类不需要实现Comparable接口了。我们来看compare()方法内部,首先计算比较的元素的年龄差num,如果num不等于0,那么我们还是按照年龄排序,如果年龄相同,那么我们返回元素名字长度的差,也就是说年龄相同,我们按照名字长度进行排序。从输出可以看出,索额图和苏麻喇姑的年龄相同,但是索额图名字长度要小于苏麻喇姑,所以索额图排在了苏麻喇姑的前面输出。
至此!如何使用TreeSet去存储对象以及内部的排序原理我们就讲完了,有时间自己动手去实现一下,多思考为什么要这样,眼高手低是程序员一大忌讳。如果不懂的读者可以在下面留言!
Java中TreeMap集合讲解的更多相关文章
- java中TreeMap集合的常用方法
实现Map集合的方法这里就不在讲了 https://www.cnblogs.com/xiaostudy/p/9510763.html public Map.Entry<K,V> ceili ...
- Java中的集合(十一) 实现Map接口的TreeMap
Java中的集合(十一) 实现Map接口的TreeMap 一.TreeMap简介(基于JDK1.8) TreeMap是基于红黑树数据结构,是一个key-value的有序集合,该映射根据其键的自然顺序进 ...
- 万字长文深入理解java中的集合-附PDF下载
目录 1. 前言 2. List 2.1 fail-safe fail-fast知多少 2.1.1 Fail-fast Iterator 2.1.2 Fail-fast 的原理 2.1.3 Fail- ...
- java中treemap和treeset实现(红黑树)
java中treemap和treeset实现(红黑树) TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 Tre ...
- java中的集合操作类(未完待续)
申明: 实习生的肤浅理解,如发现有错误之处.还望大牛们多多指点 废话 事实上我写java的后台操作,我每次都会遇到一条语句:List<XXXXX> list = new ArrayList ...
- Java中的集合概述
Java中的集合类有两个重要的分支,分别是接口Collection(包括List,Set等)和接口Map. 由于HashSet的内部实现原理使用了HashMap,所以我们先来了解Map集合类. 1.H ...
- JAVA中的集合容器操作类
目录 JAVA中的集合容器操作类 List集合 ArrayList的操作方法说明 LinkedList Stack Set Map Queue 总结 JAVA中的集合容器操作类 Java容器类库总共分 ...
- Java中各种集合(字符串类)的线程安全性!!!
Java中各种集合(字符串类)的线程安全性!!! 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读 ...
- Java中的集合框架-Map
前两篇<Java中的集合框架-Commection(一)>和<Java中的集合框架-Commection(二)>把集合框架中的Collection开发常用知识点作了一下记录,从 ...
随机推荐
- mongodb的基本命令操作
mongodb在已经存在管理员的情况下,需要创建一个库 使用管理员进入mongodb的命令行界面 mongo admin -u 管理员名 -p 管理员密码 创建库(进入库) use 库名 创建当前库的 ...
- Python type class metaclass
'type' 是 python built-in metaclass 其他继承自 ‘type’的class都可以是 Metaclass 子类可以继承父类的metaclass 然而 __metaclas ...
- asp.net 图表
感谢csdn深南大道,文章转自http://blog.csdn.net/smartsmile2012/article/details/17356673 前台代码 <div> <asp ...
- [问题记录]Ubuntu下chmsee安装失败的解决
日期:2016年2月26日 一直在找Ubuntu下查看chm的工具但是普遍不理想,发现在deepin中的chmsee相对比较好,但是直接执行网上的sudo apt-get install chmsee ...
- [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...
- Selenium私房菜系列6 -- 深入了解Selenium RC工作原理(1)
前一篇已经比较详细讲述了如何使用Selenium RC进行Web测试,但到底Selenium RC是什么?或者它由哪几部分组成呢?? 一.Selenium RC的组成: 关于这个问题,我拿了官网上的一 ...
- POJ 3133 Manhattan Wiring (插头DP,轮廓线,经典)
题意:给一个n*m的矩阵,每个格子中有1个数,可能是0或2或3,出现2的格子数为2个,出现3的格子数为2个,要求将两个2相连,两个3相连,求不交叉的最短路(起终点只算0.5长,其他算1). 思路: 这 ...
- 11gR2新特性---Gpnp守护进程
在这篇文章中,我们会对11gR2 新的守护进程(资源名称ora.gpnpd)进行介绍,其中包含的gpnp的功能,启动顺序和基本的诊断方法. gpnp全称为grid plug and play,该组件的 ...
- UVA 247 - Calling Circles (Floyd)
互相可以打电话是一个传递关系,所以Floyd求传递封包,dfs找一个尽量大的圈. #include<bits/stdc++.h> using namespace std; ; map< ...
- Objective-C相关Category的收集(更新)
Categories是给你得不到源码的classes增加功能的一种方法.这个页面收集一些相关的Category,并且持续更新,你可以订阅关注.作者是Fille ?str?m,是@ IMGNRY的联合创 ...