Java深入了解TreeSet,和迭代器遍历方法
Map集合:链接: Map集合的五种遍历方式及Treemap方法
Set集合:链接: Java中遍历Set集合的三种方法
TreeSet集合:链接: Java深入了解TreeSet,和迭代器遍历方法
LIst集合:链接: Java中List集合的三种遍历方式(全网最详)
集合区别:链接: java中list,set,map集合的区别,及面试要点
Java中的TreeSet是Set的一个子类,TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一。
那TreeSet为什么能保证元素唯一,它是怎样排序的呢?先看一段代码:
public static void demo() {TreeSet<Person> ts = new TreeSet<>();ts.add(new Person("张三", 23));ts.add(new Person("李四", 13));ts.add(new Person("周七", 13));ts.add(new Person("王五", 43));ts.add(new Person("赵六", 33));System.out.println(ts);}
执行结果:
出错,会抛出一个异常:java.lang.ClassCastException
显然是出现了类型转换异常。原因在于我们需要告诉TreeSet如何来进行比较元素,如果不指定,就会抛出这个异常
如何解决:
如何指定比较的规则,需要在自定义类(Person)中实现Comparable
接口,并重写接口中的compareTo方法
复制代码
public class Person implements Comparable<Person> {private String name;private int age;...public int compareTo(Person o) {return 0; //当compareTo方法返回0的时候集合中只有一个元素return 1; //当compareTo方法返回正数的时候集合会怎么存就怎么取return -1; //当compareTo方法返回负数的时候集合会倒序存储}
}
复制代码
为什么返回0,只会存一个元素,返回-1会倒序存储,返回1会怎么存就怎么取呢?原因在于TreeSet底层其实是一个二叉树机构,且每插入一个新元素(第一个除外)都会调用compareTo()
方法去和上一个插入的元素作比较,并按二叉树的结构进行排列。
- 如果将
compareTo()
返回值写死为0,元素值每次比较,都认为是相同的元素,这时就不再向TreeSet中插入除第一个外的新元素。所以TreeSet中就只存在插入的第一个元素。 - 如果将
compareTo()
返回值写死为1,元素值每次比较,都认为新插入的元素比上一个元素大,于是二叉树存储时,会存在根的右侧,读取时就是正序排列的。 - 如果将
compareTo()
返回值写死为-1,元素值每次比较,都认为新插入的元素比上一个元素小,于是二叉树存储时,会存在根的左侧,读取时就是倒序序排列的。
利用上述规则,我们就可以按照年龄来排序了。代码如图
public int compareTo(Person o) {int num = this.age - o.age; //年龄是比较的主要条件return num == 0 ? this.name.compareTo(o.name) : num;//姓名是比较的次要条件}按照姓名排序(依据Unicode编码大小),代码如下:public int compareTo(Person o) {int num = this.name.compareTo(o.name); //姓名是主要条件return num == 0 ? this.age - o.age : num; //年龄是次要条件}
按照姓名长度排序,代码如下:
public int compareTo(Person o) {int length = this.name.length() - o.name.length(); //比较长度为主要条件int num = length == 0 ? this.name.compareTo(o.name) : length; //比较内容为次要条件return num == 0 ? this.age - o.age : num; //比较年龄为次要条件}
以上是TreeSet如何比较自定义对象,接下来我们再来看一下TreeSet如何利用比较器比较元素。
需求:现在要制定TreeSet中按照String长度比较String。
复制代码
//定义一个类,实现Comparator接口,并重写compare()方法,
class CompareByLen /*extends Object*/ implements Comparator<String> {@Overridepublic int compare(String s1, String s2) { //按照字符串的长度比较int num = s1.length() - s2.length(); //长度为主要条件return num == 0 ? s1.compareTo(s2) : num; //内容为次要条件}
}
复制代码
复制代码public static void demo4() {//需求:将字符串按照长度排序TreeSet<String> ts = new TreeSet<>(new CompareByLen()); //Comparator c = new CompareByLen();ts.add("aaaaaaaa");ts.add("z");ts.add("wc");ts.add("nba");ts.add("cba");System.out.println(ts);}
复制代码
总结
特点
TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
使用方式
a.自然顺序(Comparable)
TreeSet类的add()方法中会把存入的对象提升为Comparable类型
调用对象的compareTo()方法和集合中的对象比较
根据compareTo()方法返回的结果进行存储
b.比较器顺序(Comparator)
创建TreeSet的时候可以制定 一个Comparator
如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
add()方法内部会自动调用Comparator接口中compare()方法排序
调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
c.两种方式的区别
TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
TreeSet如果传入Comparator, 就优先按照Comparator
Java中 TreeMap和TreeSet算是java集合类里面比较有难度的数据结构。和普通的HashMap不一样,普通的HashMap元素存取的时间复杂度一般是O(1)的范围,而TreeMap内部对元素的操作复杂度为O(logn)。
虽然在元素的存取方面TreeMap并不占优,但是它内部的元素都是排序的,当需要查找某些元素以及顺序输出元素的时候它能够带来比较理想的结果。可以说,TreeMap是一个内部元素排序版的HashMap。同样,TreeSet是一个封装了一个HashSet的成员变量来实现的,底层运用了红黑树的数据结构。
这里主要展现TreeSet的两种常用方法:
示例一:
public class TreeSetTest {public static void main(String[] args) {Set<String> set = new TreeSet<String>();set.add("abc");set.add("xyz");set.add("rst");System.out.println(set);//可以直接输出Iterator itSet = set.iterator();//也可以遍历输出while(itSet.hasNext())System.out.print(itSet.next() + "\t");System.out.println();}
}
输出结果为:
[abc, rst, xyz]
abc rst xyz
示例二:
//自定义数据类型,并在自定义的数据类型中实现CompareTo方法
class Teacher implements Comparable { int num; String name; Teacher(String name, int num) { this.num = num; this.name = name; } public String toString() { return "学号:" + num + " 姓名:" + name; } public int compareTo(Object o) { Teacher ss = (Teacher) o; int result = num > ss.num ? 1 : (num == ss.num ? 0 : -1); if (result == 0) { result = name.compareTo(ss.name); } return result; }
} public class TreeSetTest { public static void main(String[] args) { Set<Teacher> treeSet = new TreeSet<Teacher>(); treeSet.add(new Teacher("zhangsan", 2)); treeSet.add(new Teacher("lisi", 1)); treeSet.add(new Teacher("wangwu", 3)); treeSet.add(new Teacher("mazi", 3)); System.out.println(treeSet);//直接输出Iterator itTSet = treeSet.iterator();//遍历输出while(itTSet.hasNext()) System.out.print(itTSet.next() + "\t"); System.out.println(); }
}
输出结果为:
[学号:1 姓名:lisi, 学号:2 姓名:zhangsan, 学号:3 姓名:mazi, 学号:3 姓名:wangwu]
学号:1 姓名:lisi 学号:2 姓名:zhangsan 学号:3 姓名:mazi 学号:3 姓名:wangwu
HashSet与TreeSet的区别
1、HashSet与TreeSet接口的一点不同,HashSet 保存的数据是无序的,TreeSet保存的数据是有序的,所以如果要想保存的数据有序应该使用TreeSet子类。
2、利用TreeSet保存自定义类对象的时候,自定义所在的类一定要实现Comparable接口,如果没有实现这个接口那么就无法区分大小关系,而且在TreeSet中如果要进行排序,那么就要将所有的字段都进行比较,就是说在TreeSet中是依靠comparato()方法返回的是不是0来判断是不是重复元素的。
3、如果是HashSet子类,那么其判断重复数据的方式不是依靠的comparable接口而是Object类之中的两个方法:(1)取得对象的哈希码 hashCode();(2)对象比较:equals(); 这俩个方法均不需要自己编写,在eclipse里面可以使用右键source 选择自动生成。就像生成Getter 和Setter 方法一样。
总结:TreeSet 依靠的是Comparable 来区分重复数据;
HashSet 依靠的是hashCode()、equals()来区分重复数据
Set 里面不允许保存重复数据。
Java深入了解TreeSet,和迭代器遍历方法相关推荐
- 完全二叉树的JAVA实现(以及非递归遍历方法)
一个用于实现初始化指定个数的完全二叉树,以及两个非递归的深度优先遍历,和广度优先遍历 package fifth; import java.util.Random; public class Tool ...
- java从1到9构建完全二叉树_Java完全二叉树的创建与四种遍历方法分析
Java完全二叉树的创建与四种遍历方法分析 发布时间:2020-10-01 11:58:56 来源:脚本之家 阅读:87 作者:泡0沫 本文实例讲述了Java完全二叉树的创建与四种遍历方法.分享给大家 ...
- 打印完全二叉树java_java 完全二叉树的构建与四种遍历方法示例
本来就是基础知识,不能丢的太干净,今天竟然花了那么长的时间才写出来,记一下. 有如下的一颗完全二叉树: 先序遍历结果应该为:1 2 4 5 3 6 7 中序遍历结果应该为:4 2 5 ...
- Set的创建和遍历方法
package SetTest;import java.util.*; //Set的创建和遍历方法 public class Set2 {public static void main(String[ ...
- java取set中的元素个数_java中的Set的使用以及各种遍历方法(较为全面)
1. 概述 Java 中的Set和正好和数学上直观的集(set)的概念是相同的.Set最大的特性就是不允许在其中存放的元素是重复的.根据这个特点,我们就可以使用Set 这个接口来实现前面提到的关于商品 ...
- java set遍历方式_java中的Set的使用以及各种遍历方法(较为全面)
1. 概述 Java 中的Set和正好和数学上直观的集(set)的概念是相同的.Set最大的特性就是不允许在其中存放的元素是重复的.根据这个特点,我们就可以使用Set 这个接口来实现前面提到的关于商品 ...
- 第三次学JAVA再学不好就吃翔(part77)--迭代器遍历
学习笔记,仅供参考,有错必纠 文章目录 集合 迭代器遍历 Iterator类 Collection类的iterator方法 迭代器原理 举个例子 集合 迭代器遍历 迭代器概述 集合是用来存储元素的,存 ...
- java的List三种遍历方法汇总
java的List遍历方法有三种,分别为iterator迭代器,增强for循环,普通for循环,分别如下: package com.zhang.List;import java.util.ArrayL ...
- java集合的遍历_java集合遍历方法总结
java集合遍历方法总结 一.for循环遍历集合 使用条件: ①能否确定集合中的元素个数 ②集合是否可以通过整数索引值来精确位置 public static void forTraversal(){ ...
最新文章
- Android RSA加密对象数据
- 怎样使用OpenCV进行人脸识别
- Angular 默认的Change detection策略及缺陷
- php存密码,php 登录验证的代码(基于文件保存的密码)
- Java 基础【09】你的多继承纳?
- 附005.Docker Compose文件详解
- (已解决)利用LiveReload插件实现vscode和谷歌浏览器实时刷新
- android图片的透明度变化,Android如何实现改变图片的透明度
- 阿里云企业邮箱标准版多域名绑定
- python中string什么意思_Python:string是什么意思
- 戴尔台式计算机主板型号,如何查看戴尔主板型号_查看戴尔主板型号的步骤-系统城...
- html图片自动在div里放大,HTML5+CSS3实现图片的放大/缩小
- 公众号创建菜单报错40001及菜单出现在先前公众号上的问题
- 开独立网店需要哪些步骤
- 1.3【展讯平台】Android 驱动(Kernel)、系统(framework) 定制,调试日志
- Linux 下怎么查看服务器的cpu和内存的硬件信息
- 把计算机器显示桌面,怎样将电脑显示器和桌面匹配
- angularjs全栈开发知乎_双剑合璧Laravel,AngularJS全栈开发知乎
- 极客编程c语言,C语言教程
- 径向基网络(RBF)实现函数插值(拟合)
热门文章
- 惠普服务器G8系列做raid,hp g8服务器设置raid5
- 大数据开发笔记(九):Flink基础
- HDFS写入HBase
- 常用的五种大数据分析方法
- 大数据分析有哪些分析方式
- 如何降低BI系统建设的风险
- android space边框,Android中的图片视图的边框?
- c语言结构体调用成员函数,c语言结构体函数调用参数如何设置
- quartz 2.0持久化到mysql_SpringBoot2.0整合Quartz定时任务(持久化到数据库,更为简单的方式)...
- 基于遗传算法自动化集装箱码头多载AGV调度(一)—模型搭建