Java集合(五):Set集
在上一讲中介绍了散列映射表HashMap和树映射表TreeMap,知道了HashMap的底层实现机制。这一讲将介绍Set接口和实现类:HashSet和TreeSet。由于HashSet的实现是基于HashMap的,TreeSet的实现是基于TreeMap的,所以这里不做过多底层的讨论,毕竟这部分已经在Java集合(四):Map映射中讨论过了。
1 散列表与Set接口
链表和数组可以按照人们的意愿排列元素的顺序。但是,如果想要查看某个指定的元素,但却忘了它的位置,就需要访问所有的元素,直到找到为止。如果集合中的元素很多,将会消耗很长时间。如果不在意元素的顺序,可以有几种能够快速查找元素的数据结构。但是缺点是不能控制元素的顺序。它们将按照有利于其操作目的的原则组织数据。
有一种常见的数据结构,就是散列表(hash table)。散列表可以根据每个对象计算一个整数,称为散列码(hash code)。不同的对象产生不同的散列码。
在Java中,散列表用链表数组实现。每个列表称为桶,这个已经在Map映射中介绍了。
散列表的特点就是:元素没有顺序,元素不能重复。
Set接口的定义如下:
public interface java.util.Set<E> extends java.util.Collection<E> {public abstract int size();public abstract boolean isEmpty();public abstract boolean contains(java.lang.Object);public abstract java.util.Iterator<E> iterator();public abstract java.lang.Object[] toArray();public abstract <T> T[] toArray(T[]);public abstract boolean add(E);public abstract boolean remove(java.lang.Object);public abstract boolean containsAll(java.util.Collection<?>);public abstract boolean addAll(java.util.Collection<? extends E>);public abstract boolean retainAll(java.util.Collection<?>);public abstract boolean removeAll(java.util.Collection<?>);public abstract void clear();public abstract boolean equals(java.lang.Object);public abstract int hashCode();public java.util.Spliterator<E> spliterator();
}
这些方法的含义也很简单。
2 HashSet类
Java集合类库中提供了HashSet类实现了Set接口。这个类的底层是使用HashMap实现的:
private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
我们知道,HashMap是一个键值对,而HashSet存储的不是键值对,因此为了使用HashMap存储HashSet的元素,就需要构造一个键值对。可以使用需要存储在HashSet中的元素作为键,而上面的PRESENT作为值,就构成了一个键值对,这样就可以存在HashMap中了。
也就是说,HashSet与HashMap的原理一样,不同的是HashSet的值都一样,都是PRESENT。
由于在前一节中已经详细介绍了HashMap的原理,这里不再叙述了。只说一下HashSet的使用。
下面的代码从System.in中读取单词,然后将它们添加到HashSet中,再打印出所有的单词。由于HashSet中不存储相同的元素,所以打印出来的单词是不重复的。运行这个程序时使用下面的命令行:
java SetTest < alice.txt
这样就把alice.txt作为输入,程序就会读取所有的单词。代码如下:
import java.util.*;public class SetTest
{public static void main(String[] args){Set<String> words = new HashSet<>(); // HashSet implements Setlong totalTime = 0;Scanner in = new Scanner(System.in);while (in.hasNext()){String word = in.next();long callTime = System.currentTimeMillis();words.add(word);callTime = System.currentTimeMillis() - callTime;totalTime += callTime;}Iterator<String> iter = words.iterator();for (int i = 1; i <= 20 && iter.hasNext(); i++)System.out.println(iter.next());System.out.println(". . .");System.out.println(words.size() + " distinct words. " + totalTime + " milliseconds.");}
}
结果如下:
可以看见,一共有5392个不同的单词。
3 TreeSet类
TreeSet和HashSet类似,不过,它比HashSet有所改进。TreeSet是一个有序集合,可以以任意顺序将元素插入到集合中。在对集合进行遍历时,每个值将自动按照排序后的顺序呈现。例如,假设插入三个字符串,然后访问添加的所有元素:
SortedSet<String> sorter=new TreeSet<>();
sorter.add("B");
sorter.add("A");
sorter.add("C");
for(String s:sorter)System.out.println(s);
结果是:A B C
TreeSet的底层是使用TreeMap实现的,是一个红黑树。每次添加一个元素到树中时,都被放置在正确的排序位置上。因此,迭代器总是以排好序的顺序访问每个元素。
将一个元素添加到树中要比添加到一个散列表中要慢,但是,与将元素添加到数组中或链表中要快。如果树中一共有n个元素,将元素插入到正确位置的时间为logn。
与TreeMap一样,构造一个TreeSet也需要一个比较器,可以使用默认的比较器,也可以使用自己的比较器。使用自己的比较器时,需要给TreeSet的构造器传递一个Comparator对象。
下面的程序创建了两个Item对象的树集。第一个按照部件编号排序,这是Item对象的默认顺序。第二个通过使用一个定制的比较器来按照描述信息排序:
import java.util.*;public class TreeSetTest
{ public static void main(String[] args){ SortedSet<Item> parts = new TreeSet<>();parts.add(new Item("Toaster", 1234));parts.add(new Item("Widget", 4562));parts.add(new Item("Modem", 9912));System.out.println(parts);SortedSet<Item> sortByDescription = new TreeSet<>(newComparator<Item>(){ public int compare(Item a, Item b){ String descrA = a.getDescription();String descrB = b.getDescription();return descrA.compareTo(descrB);}});sortByDescription.addAll(parts);System.out.println(sortByDescription);}
}
import java.util.*;/*** An item with a description and a part number.*/
public class Item implements Comparable<Item>
{private String description;private int partNumber;/*** Constructs an item.* * @param aDescription* the item's description* @param aPartNumber* the item's part number*/public Item(String aDescription, int aPartNumber){description = aDescription;partNumber = aPartNumber;}/*** Gets the description of this item.* * @return the description*/public String getDescription(){return description;}public String toString(){return "[\n\tdescripion=" + description + ",\n\tpartNumber=" + partNumber +"\n]\n";}public boolean equals(Object otherObject){if (this == otherObject) return true;if (otherObject == null) return false;if (getClass() != otherObject.getClass()) return false;Item other = (Item) otherObject;return Objects.equals(description, other.description) && partNumber == other.partNumber;}public int hashCode(){return Objects.hash(description, partNumber);}public int compareTo(Item other){return Integer.compare(partNumber, other.partNumber);}
}
结果如下:
Java集合(五):Set集相关推荐
- Java——集合(合集,简单的概括)
JAVA --集合 集合 概念: 1 .Collection接口与Iterator接口 2 .Collection<>接口 3 . List<>接口 3 .1 ArrayLis ...
- java集合面试锦集
Java集合框架(例如基本的数据结构)里包含了最常见的Java常见面试问题.很好地理解集合框架,可以帮助你理解和利用Java的一些高级特性.下面是面试Java核心技术的一些很实用的问题. Q:最常见的 ...
- java基础集合数组间的转换(java集合五)
数组转变成集合 public static void main(String[] args) {// 如果数组中元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素,// 如果数组中的元素 ...
- Java集合(一):Java集合概述
注:本文基于JDK 1.7 1 概述 Java提供了一个丰富的集合框架,这个集合框架包含了许多接口.虚拟类和实现类.这些接口和类提供了丰富的功能,能够满足基本的聚合需求.下图就是这个框架的整体结构图: ...
- java泛型 ppt_第7章-Java集合与泛型-精品课件(PPT)-精品课件(PPT)最新版
<第7章 -Java集合与泛型-精品课件(PPT)-精品课件(PPT).ppt>由会员分享,可免费在线阅读全文,更多与<第7章 -Java集合与泛型-精品课件(PPT)-精品课件(P ...
- java list有序还是无序_牛批!2w字的Java集合框架面试题精华集(2020最新版),赶紧收藏。...
一个多月前,作者和一些小伙伴决定做一系列的 Java 知识点常见重要问题的小册,方便用来夯实基础!小册的标准就一个,那就是:取精华,取重点.每一本小册,我们都会充分关注我们所总结的知识点是否达到这个标 ...
- 「Java面试题精华集」1w字的Java集合框架篇(2022最新版)附PDF版
昨天晚上终于把 Java 集合框架部分的的知识点肝完了,转换成 PDF 一共 25 页,后台回复:"面试突击" 即可免费获取下载地址(同样提供了夜间阅读版本). 集合概述 Java ...
- java集合——树集(TreeSet)+对象的比较
[0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java集合--树集(TreeSet)+对象的比较 的相关知识: 0.2) for full ...
- java集合——数组列表(ArrayList)+散列集(HashSet)
[0]README 0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java集合--数组列表(ArrayList)+散列集(HashSet) 的相关知识: 0.2 ...
最新文章
- JS 正则表达式 0.001 ~99.999
- 算法学习之路|D进制的A+B
- py2数据分析_利用数据
- Keil 汇编窗口无法设置断点,disassembly显示错误,Keil汇编解析错误
- python每隔一段时间保存网页内容_利用Python轻松爬取网页题库答案!教孩子不怕尴尬了!...
- Pytho-SyntaxError: Non-ASCII character '\xe7' in file解决方法
- Latex 经常见到的问题和解决方法
- 什么是用户画像?如何构建用户画像?
- 解决错误:Main application must be in the list of ap...
- Python3有哪几种数据类型?
- 【C++】Visual Studio教程(一)-概述
- java大量浮点数如何作比较,Java如何正确比较浮点数
- java linux命令远程执行_java执行远程服务器上的shell命令
- MYSQL查询近一年 近一月 近一周 今天数据 没有数据返回0 按时间有序返回数据
- a4如何打印双面小册子_小册子打印
- 再启程,Service Mesh 前路虽长,尤可期许
- Spring Cloud Eureka服务注册中心 多节点搭建(学习总结)
- html rgb 颜色转换,将RGBA颜色转换为HTML颜色代码
- php 数据库 编程,php数据库编程(mysql mysqli pdo)
- R费希尔精确检验(Fisher‘s exact test)
热门文章
- Delphi与Windows 7下的用户账户控制(UAC)机制
- HDU-1518 Square dfs+剪枝
- int定义源码 python_python学习(第一章)
- python 三维绘图库_Python第三方库matplotlib(2D绘图库)入门与进阶
- 计算机等级考试试题4,计算机等级考试二级模拟试题4
- firewallD卸载Linux,在Ubuntu 18.04/16.04系统上安装和使用Firewalld的方法
- 乐高计算机发展史教程,【乐高产品发展史特别篇】乐高恐龙发展史
- 求10以内平均数的c语言,求助 给小学生出题,自己选加减乘除 做10题 10以内的数 然后统计分...
- 汇编写java模块_java – maven汇编插件moduleset源指令不包括任何文件,不符合附带的模块...
- NXP KW38开发杂记(一)MCUXpress 运行进入NMI_Handler