JAVA 集合框架(三) Set集合详解和常用方法

JAVA 集合框架(三) Set集合详解和常用方法

Set 是 java.util 包下集合框架中一个接口,它是 Collection 接口的一个子接口,表示不允许包含重复元素的集合。Set 集合的特点是集合内的元素无序,且每个元素都是唯一的。这意味着即使试图添加两个相等的对象(依据 .equals() 方法判断相等),Set 集合只会保存一个对象。

Set集合的特点

无序性:Set 集合中的元素不按任何特定顺序排列,无法通过索引访问元素,即集合内部的元素顺序可能随时间和操作发生变化。

唯一性:Set 集合不允许包含重复的元素。判断元素是否重复的标准是基于元素的 .equals() 方法。如果两个对象在 .equals() 方法下判断为相等,则 Set 集合中只会存储其中一个。

最大容量:理论上,Set 集合可以无限增长,直到受到可用内存限制为止。

Set集合的主要实现类

HashSet:基于哈希表实现,具有良好的插入、删除和查找性能(平均时间复杂度为 O(1)),但不保证元素的迭代顺序。

TreeSet:基于红黑树实现,元素自动排序(要么基于元素自身的自然排序,要么通过自定义 Comparator),插入、删除和查找性能为 O(log n),确保了集合内元素的排序顺序。

LinkedHashSet:结合了 HashSet 和 LinkedList 的特性,它维护元素插入的顺序,同时仍然保证元素的唯一性。

HashSet

HashSet是Java集合框架中一个实现Set接口的类,它使用哈希表(内部一般采用HashMap)作为底层数据结构,主要用于存储不重复的元素集合。

HashSet集合有以下特点:

无序性

唯一性

高效性:由于基于哈希表实现,HashSet插入、删除和查找元素的平均时间复杂度为O(1),前提是哈希函数能够良好地分散冲突。

允许存储null值:HashSet允许存储一个null元素,但仅能存储一个,因为null的哈希码固定为0。

构造函数

HashSet类在Java集合框架中提供了多个构造函数,用于创建不同的HashSet实例。以下是HashSet的主要构造函数及其详细讲解:

无参数构造函数:

HashSet():此构造函数创建一个新的、空的HashSet实例。底层HashMap的初始容量为16,负载因子为0.75。随着元素的添加,HashSet会自动调整容量以容纳更多的元素。

// 创建一个 空的 HashSet 集合

HashSet set = new HashSet<>();

带集合参数的构造函数:

HashSet(Collection c):创建一个新的HashSet,其元素来自于指定的集合c。新创建的HashSet不会包含任何重复的元素,即便原始集合中有重复项

// 创建一个 List 集合

List list = Arrays.asList("Apple", "Banana", "Cherry", "Apple");

// 创建一个 HashSet 集合,传入list集合参数

HashSet set = new HashSet<>(list);

System.out.println(set); // 输出: [Apple, Cherry, Banana]

指定初始容量的构造方法:

HashSet(int initialCapacity):创建一个新的、空的HashSet,其初始容量被设定为指定的数值。负载因子依然默认为0.75。

// 初始化容量为100的 HashSet 集合

HashSet set = new HashSet<>(100);

指定初始容量和负载因子的构造函数:

HashSet(int initialCapacity, float loadFactor):创建一个新的、空的HashSet,允许同时指定初始容量和负载因子。初始容量是你预估的最大元素数量,负载因子是用于确定何时重新调整HashMap容量的阈值,当已存储元素数量超过容量与负载因子的乘积时,HashMap会自动扩容。

// 初始容量为100,负载因子为0.8 的 HashSet 集合

HashSet set = new HashSet<>(100, 0.8f);

注意:

初始容量(initialCapacity)必须是大于0的整数,否则会抛出IllegalArgumentException异常。

负载因子(loadFactor)必须是大于0且不大于1的浮点数,若传入负数或大于等于1的数也会抛出IllegalArgumentException异常。

设置适当的初始容量和负载因子可以帮助优化性能,减少扩容操作带来的开销。过低的初始容量会导致频繁扩容,过高则可能浪费空间。一般来说,负载因子较小意味着更早触发扩容,从而降低冲突概率,但也意味着更高的空间消耗。

示例代码

// 创建一个HashSet实例

Set list = new HashSet<>();

// 添加元素

list.add("Apple");

list.add("Banana");

list.add("Cherry");

// 尝试添加重复元素,不会添加成功

list.add("Apple");

// 输出HashSet中的元素

System.out.println(list);

// 检查元素是否存在

System.out.println("'Banana'是否存在? " + list.contains("Banana"));

// 删除元素

list.remove("Banana");

System.out.println("删除'Banana'后: " + list);

// 清空HashSet

list.clear();

System.out.println("清空操作后: " + list);

TreeSet

TreeSet是Java集合框架中实现Set接口的一个重要类,它基于红黑树(Red-Black Tree)数据结构,提供了一个有序的、不包含重复元素的集合。

TreeSet集合有以下特点:

唯一性

有序性:TreeSet中的元素是有序的,排序规则既可以是元素本身的自然排序(元素类实现了Comparable接口),也可以是由客户端提供的Comparator来决定。

自平衡:由于基于红黑树实现,TreeSet在插入、删除和查找操作后都能保持树的平衡,从而确保这些操作的时间复杂度接近O(log n)。

构造函数

无参数构造函数:

TreeSet():创建一个空的TreeSet,其中的元素将按照它们的自然顺序排序。这意味着元素类型需要实现Comparable接口。

TreeSet treeSet = new TreeSet<>();

// 自动按照字符串字典顺序排序

treeSet.add("Apple");

treeSet.add("Banana");

treeSet.add("Cherry");

System.out.println(treeSet);// 输出: [Apple, Banana, Cherry]

使用Comparator构造函数:

TreeSet(Comparator comparator):创建一个空的TreeSet,其中的元素将按照指定的Comparator进行排序。

public class Demo05_TreeSet {

public static void main(String[] args) {

// 定义一个自定义的比较器

Comparator comparator = new Comparator() {

@Override

public int compare(Person p1, Person p2) {

// 按照年龄排序,年龄小的在前

return Integer.compare(p1.getAge(), p2.getAge());

}

};

// 使用自定义的比较器创建TreeSet

TreeSet peopleByAge = new TreeSet<>(comparator);

// 添加一些Person对象

peopleByAge.add(new Person("Alice", 30));

peopleByAge.add(new Person("Bob", 25));

peopleByAge.add(new Person("Charlie", 35));

// 输出排序后的Person对象

for (Person person : peopleByAge) {

System.out.println(person.getName() + ": " + person.getAge());

}

}

// 简单的Person类示例

public static class Person {

private String name;

private int age;

public Person(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public int getAge() {

return age;

}

}

}

包含集合元素的构造函数:

TreeSet(Collection c):创建一个包含指定集合元素的新TreeSet,元素按照其自然顺序排序。

// 创建一个 List 集合

List list = Arrays.asList("Banana", "Apple", "Cherry");

// 创建一个 TreeSet 实例

TreeSet treeSet = new TreeSet<>(list);

System.out.println(treeSet);// 输出: [Apple, Banana, Cherry]

特有方法

first(): 返回此集合中的第一个(按自然排序顺序或根据构造集合时提供的 Comparator)元素的返回值。

public E first();

last(): 返回此集合中的最后一个元素,与 first() 方法相反。

public E last();

headSet(E toElement): 返回一个从集合的第一个元素到指定元素(不包括)的视图。

public SortedSet headSet(E toElement);

tailSet(E fromElement): 返回一个从指定元素(包括)到集合的最后一个元素的视图。

public SortedSet tailSet(E fromElement);

subSet(E fromElement, E toElement): 返回一个从 fromElement(包括)到 toElement(不包括)的视图。

public SortedSet subSet(E fromElement, E toElement);

descendingIterator(): 返回一个按照降序遍历集合的迭代器。

public Iterator descendingIterator();

descendingSet(): 返回一个按照降序排列的此集合的视图。

public NavigableSet descendingSet();

代码示例:

public static void main(String[] args) {

TreeSet treeSet = new TreeSet<>();

treeSet.add(10);

treeSet.add(20);

treeSet.add(30);

treeSet.add(40);

// 使用 first() 和 last() 方法

System.out.println("第一个元素: " + treeSet.first());

System.out.println("最后一个元素: " + treeSet.last());

// 使用 headSet() 方法

System.out.println("Head set to 30: " + treeSet.headSet(30));

// 使用 tailSet() 方法

System.out.println("Tail set from 30: " + treeSet.tailSet(30));

// 使用 subSet() 方法

System.out.println("Sub set from 10 to 30: " + treeSet.subSet(10, 30));

// 使用 descendingIterator() 方法

System.out.println("Descending iterator:");

treeSet.descendingIterator().forEachRemaining(System.out::println);

}

LinkedHashSet

LinkedHashSet 是 Java 集合框架中的一个类,它继承自 HashSet 并实现了 Set 接口。LinkedHashSet 集合是一种哈希表和链表的组合,它具有以下特点:

无序性:与 HashSet 类似,LinkedHashSet 也不允许集合中有重复的元素。

有序性:与 HashSet 不同的是,LinkedHashSet 维护了一个双向链表,使得迭代它时可以按照插入顺序访问集合中的元素。

性能:LinkedHashSet 在大多数情况下提供与 HashSet 相同的时间和空间复杂度,即添加、删除和查找元素的时间复杂度为 O(1)。

线程不安全:与 HashSet 一样,LinkedHashSet 也是线程不安全的。如果需要线程安全的集合,可以使用 Collections.synchronizedSet(new LinkedHashSet<>()) 包装一个 LinkedHashSet,或者使用 ConcurrentHashMap 作为底层实现。

构造函数:LinkedHashSet 提供了多种构造函数,允许你指定初始容量和加载因子,或者使用另一个集合的元素来创建 LinkedHashSet。

LinkedHashSet 的使用场景

当你需要一个不允许重复元素的集合,并且希望迭代时能够按照元素的插入顺序进行时,可以使用 LinkedHashSet。

LinkedHashSet 可以作为 HashMap 的键集合,因为它提供了快速的查找和迭代性能。

相关尊享内容

肺炎疫情:新冠病毒能在物体表面存活多久
365bet亚洲官方网址

肺炎疫情:新冠病毒能在物体表面存活多久

📅 08-27 👑 647
孙颖莎身高是多少
365bet信誉怎么样

孙颖莎身高是多少

📅 09-07 👑 127
模工坊2023年5月号:模型喷笔全面使用教程
365bet开户网

模工坊2023年5月号:模型喷笔全面使用教程

📅 07-21 👑 314
灯具常见的十类材质盘点 照明用灯具十大材质有哪些
365bet亚洲官方网址

灯具常见的十类材质盘点 照明用灯具十大材质有哪些

📅 11-10 👑 252