文章目录

Set

介绍
Set 继承于 Collection 接口,是一个不允许出现重复元素,并且无序的集合,主要有 HashSet 和 TreeSet 两大实现类。

Set 常用方法
与 List 接口一样,Set 接口也提供了集合操作的基本方法。

但与 List 不同的是, Set 还提供了 ​​equals(Object o)​​​和 ​​hashCode()​​,供其子类重写,以实现对集合中插入重复元素的处理。

public interface Set<E> extends Collection<E> {

A:添加功能
boolean add(E e);
boolean addAll(Collection<? extends E> c);

B:删除功能
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();

C:长度功能
int size();

D:判断功能
boolean isEmpty();
boolean contains(Object o);
boolean containsAll(Collection<?> c);
boolean retainAll(Collection<?> c);

E:获取Set集合的迭代器:
Iterator<E> iterator();

F:把集合转换成数组
Object[] toArray();
<T> T[] toArray(T[] a);

//判断元素是否重复,为子类提高重写方法
boolean equals(Object o);
int hashCode();
}

HashSet

HashSet 内部封装 HashMap 对象,使用 HashMap 的键这一列来存放对象,里边的数据不重复且无序。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的​​hashCode​​​方法来得到该对象的​​hashCode​​​值,然后根据该​​hashCode​​​值决定该对象在​​HashSet​​​中的存储位置。如果有两个元素通过​​equals​​​方法比较 true,但它们的​​hashCode​​​方法返回的值不相等,HashSet 将会把它们存储在不同位置,依然可以添加成功。也就是说。 HashSet 集合判断两个元素的标准是两个对象通过 ​​equals​​​ 方法比较相等,并且两个对象的 ​​hashCode​​ 方法返回值也相等。

靠元素重写 ​​hashCode​​​ 方法和 ​​equals​​ 方法来判断两个元素是否相等,如果相等则覆盖原来的元素,依此来确保元素的唯一性。

创建对象

HashSet set = new HashSet();

hashset 特点
1、不允许出现重复因素;
2、允许插入Null值;
3、元素无序(添加顺序和遍历顺序不一致);
4、线程不安全,若2个线程同时操作HashSet,必须通过代码实现同步;

举例:HashSet 练习

public class Main {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(99);
set.add(55);
set.add(77);
set.add(44);
set.add(88);
set.add(11);
set.add(33);

System.out.println(set.size());//7
System.out.println(set);//[33, 99, 55, 88, 11, 44, 77]
System.out.println(set.contains(99));//true
System.out.println(set.remove(44));//true
System.out.println(set);//[33, 99, 55, 88, 11, 77]

//迭代器遍历
Iterator<Integer> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
//遍历结果:
/*33
99
55
88
11
77*/

//迭代器的另一种写法
for (Iterator<Integer> it2 = set.iterator(); it2.hasNext(); ) {
System.out.println(it2.next());
}
}
}

由于Set集合中并没有角标的概念,所以并没有像 List 一样提供 ​​get()​​​ 方法。当获取 HashSet 中某个元素时,只能通过遍历集合的方式进行 ​​equals()​​ 比较来实现;

TreeSet

介绍
内部封装 TreeMap 对象,使用 TreeMap 的键这一列来存放对象,数据不重复有序。

与 HashSet 不同的是,TreeSet 具有排序功能,分为自然排序(123456)和自定义排序两类,默认是自然排序;在程序中,我们可以按照任意顺序将元素插入到集合中,等到遍历时 TreeSet 会按照一定顺序输出–倒序或者升序。

TreeSet 特点
1、对插入的元素进行排序,是一个有序的集合(主要与HashSet的区别);
2、底层使用红黑树结构,而不是哈希表结构;
3、允许插入Null值;
4、不允许插入重复元素;
5、线程不安全;

创建对象

TreeSet set = new TreeSet();
TreeSet set = new TreeSet(比较器);

举例:关键词去重

例如输入关键词:
aaa,aaa,bbb,ccc,ccc
返回去除重复的关键词后:
aaa,bbb,ccc

public class Main {
public static void main(String[] args) {
System.out.println("输入关键词列表,用逗号隔开");
String s = new Scanner(System.in).nextLine();
//aa,aa,bb,cc,cc
String[] a = s.split(",");

Set<String> set = new TreeSet<>();
for (int i = 0; i < a.length; i++) {
set.add(a[i]);
}

for (Iterator<String> it = set.iterator(); it.hasNext(); ) {
System.out.println(it.next());
}
}
}

运行结果:
【达内课程】集合之 Set、Collection_迭代器
与HashSet集合相比,TreeSet还提供了几个额外方法:

Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null;
Object first():返回集合中的第一个元素;
Object last():返回集合中的最后一个元素;
Object lower(Object e):返回指定元素之前的元素。
Object higher(Object e):返回指定元素之后的元素。
SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾;
SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成;
SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成

举例:TreeSet 使用练习

TreeSet<String> treeSet = new TreeSet<>();
System.out.println("TreeSet初始化容量大小:" + treeSet.size());//0

//元素添加:
treeSet.add("my");
treeSet.add("name");
treeSet.add("is");
treeSet.add("Errol");
treeSet.add("1");
treeSet.add("2");
treeSet.add("3");
System.out.println("TreeSet容量大小:" + treeSet.size());//7
System.out.println("TreeSet元素顺序为:" + treeSet);//[1, 2, 3, Errol, is, my, name]

//增加for循环遍历:
for (String str : treeSet) {
System.out.println("遍历元素:" + str);
}

//迭代器遍历:升序
Iterator<String> iteratorAesc = treeSet.iterator();
while (iteratorAesc.hasNext()) {
String str = iteratorAesc.next();
System.out.println("遍历元素升序:" + str);
}

//迭代器遍历:降序
Iterator<String> iteratorDesc = treeSet.descendingIterator();
while (iteratorDesc.hasNext()) {
String str = iteratorDesc.next();
System.out.println("遍历元素降序:" + str);
}

System.out.println("TreeSet头节点为:" + treeSet.first());//1

// 获取指定元素之前的所有元素集合:(不包含指定元素)
SortedSet<String> headSet = treeSet.headSet("is");
System.out.println("is节点之前的元素为:" + headSet.toString());//[1, 2, 3, Errol]

//获取给定元素之间的集合:(包含头,不包含尾)
SortedSet subSet = treeSet.subSet("3", "my");
System.out.println("3-my之间节点元素为:" + subSet.toString());//[3, Errol, is]

//集合判断:
System.out.println("TreeSet是否为空:" + treeSet.isEmpty());//false
System.out.println("TreeSet是否包含name元素:" + treeSet.contains("name"));//true

//元素删除:
System.out.println("3元素是否被删除" + treeSet.remove("3"));//true
//集合中不存在的元素,删除返回false
System.out.println("who元素是否被删除" + treeSet.remove("who"));//false

//删除并返回第一个元素:如果set集合不存在元素,则返回null
System.out.println("删除的第一个元素:" + treeSet.pollFirst());//1

//删除并返回最后一个元素:如果set集合不存在元素,则返回null
System.out.println("删除的最后一个元素:" + treeSet.pollLast());//name

//清空集合
treeSet.clear();

其余打印都写在注释中了,循环遍历的结果如下:

遍历元素:1
遍历元素:2
遍历元素:3
遍历元素:Errol
遍历元素:is
遍历元素:my
遍历元素:name

Set 和 List 的区别

  1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
  2. Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 <实现类有 HashSet,TreeSet >。
  3. List 和数组类似,可以动态增长,根据实际存储的数据的长度自动增长 List 的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变。<实现类有ArrayList,LinkedList,Vector> 。

Iterator接口

Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。一般遍历数组都是采用 for 循环或者增强 for,这两个方法也可以用在集合框架,但我们也可以采用迭代器遍历集合框架,实现了 Iterator 接口或 ListIterator 接口。可用于迭代 ArrayList 和 HashSet 等集合。

方法

​hasNext()​​​//用于检测集合中是否还有元素
​​​next()​​​//返回迭代器的下一个元素,并且更新迭代器的状态。
​​​remove()​​//将迭代器返回的元素删除。

我们之前的代码中也用到了,现在再举个例子看一下

List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("!");
Iterator<String> it = list.iterator();
//判断下一个元素之后是否有值
while(it.hasNext()){
System.out.println(it.next());
}

运行结果如下:

Hello
World
!

iterator 和 for 循环的区别
从数据结构角度分析,for 循环适合访问顺序结构,可以根据下标快速获取指定元素。而 Iterator 适合访问链式结构,因为迭代器是通过 next() 来定位的,可以访问没有顺序的集合。

Collections 工具类

​集合之 LinkedList​​中我们提到了 Collection。

排序操作

Collections 提供以下方法对 List 进行排序操作

​void reverse(List list)​​:反转

​void shuffle(List list)​​:随机排序

​void sort(List list)​​:按自然排序的升序排序

​void sort(List list, Comparator c)​​:定制排序,由 Comparator 控制排序逻辑

​void swap(List list, int i , int j)​​:交换两个索引位置的元素

​void rotate(List list, int distance)​​:旋转。当 distance 为正数时,将 list 后 distance 个元素整体移到前面。当 distance 为负数时,将 list 的前 distance 个元素整体移到后面。

查找,替换操作

​int binarySearch(List list, Object key)​​ :对 List 进行二分查找,返回索引,注意 List 必须是有序的

​int max(Collection coll)​​:根据元素的自然顺序,返回最大的元素。 类比 int min(Collection coll)

​int max(Collection coll, Comparator c)​​:根据定制排序,返回最大元素,排序规则由 Comparatator 类控制。类比 int min(Collection coll, Comparator c)

​void fill(List list, Object obj)​​:用元素 obj 填充 list 中所有元素

​int frequency(Collection c, Object o)​​:统计元素出现次数

​int indexOfSubList(List list, List target)​​:统计 targe 在 list 中第一次出现的索引,找不到则返回 -1,类比 int lastIndexOfSubList(List source, list target).

​boolean replaceAll(List list, Object oldVal, Object newVal)​​ :用新元素替换旧元素

​addAll(Collection,值1,值2,值3...)​​:向指定集合,加入多个数据

栗子

public static void main(String[] args) {
List<String> list = new ArrayList<>();

Collections.addAll(
list,
"8",
"11",
"5",
"4364",
"8",
"215",
"21",
"41029",
"20",
"6",
"1162");
System.out.println(list);
System.out.println("-----------");
Collections.sort(list);
System.out.println(list);
}

输出结果

[8, 11, 5, 4364, 8, 215, 21, 41029, 20, 6, 1162]


[11, 1162, 20, 21, 215, 41029, 4364, 5, 6, 8, 8]

虽然已经排序了,但是排序是根据字符串排序的,并不是按照数字从小到大排序的,如果需要按照数字从小到大排序,可以外接一个比较器

//外接比较器
Collections.sort(list,new Comparator<String>(){
@Override
public int compare(String arg0, String arg1) {
int a = Integer.parseInt(arg0);
int b = Integer.parseInt(arg1);
//为了防止溢出,直接用大小比较
if(a>b){
return 1;
}else if(a<b){
return -1;
}else{
return 0;
}
}
});
System.out.println(list);

输出结果

[5, 6, 8, 8, 11, 20, 21, 215, 1162, 4364, 41029]

参考
​​​Java中的Set总结​​​​java中的Set集合​​​​JAVA基础知识之Collections工具类​