HashSet vs. TreeSet vs. LinkedHashSet

本文深入解析了三种Set集合的区别与应用场景,包括HashSet的无序特性、TreeSet的有序特性以及LinkedHashSet的保留插入顺序特性。通过示例代码演示了如何在不同场景下选择合适的Set集合,并探讨了它们的性能表现。

原文: HashSet vs. TreeSet vs. LinkedHashSet

Set中不包含重复的元素。这是使用Set的最主要原因之一。有3种常用的Set,如标题,什么时候用哪一个是个问题。一般来说,如果要求速度快,那就用HashSet,如果要求有序,那就用TreeSet,如果要保留插入的顺序,那就用LinkedHashSet。


1,Set接口

Set接口继承自Collection接口,Set中不允许有元素重复,你尽管往Set中插入元素即可,重复的元素会自动被移除。



2,HashSet vs. TreeSet vs. LinkedHashSet


HashSet是由Hash表实现的,元素无序,add,remove,contain方法的时间复杂度为O(1)。

TreeSet是由Tree(red-black)实现的,元素有序,add,remove,contain方法的时间复杂度为O(log(n))。另外提供了许多和Ordered Set有关的方法,像,first(), last(),headSet() , tailSet().

LinkedHashSet介于HashSet和TreeSet之间,用Linked List和Hash表实现,保留了数据插入的顺序。一般方法的时间复杂度为O(1)。


3,TreeSet 示例

TreeSet<Integer> tree = new TreeSet<Integer>();
tree.add(12);
tree.add(63);
tree.add(34);
tree.add(45);
 
Iterator<Integer> iterator = tree.iterator();
System.out.print("Tree set data: ");
while (iterator.hasNext()) {
    System.out.print(iterator.next() + " ");
}
输出结果:

Tree set data: 12 34 45 63 

现定义一个类Dog

class Dog {
	int size;
 
	public Dog(int s) {
		size = s;
	}
 
	public String toString() {
		return size + "";
	}
}

将Dog对象添加到TreeSet中

import java.util.Iterator;
import java.util.TreeSet;
 
public class TestTreeSet {
	public static void main(String[] args) {
		TreeSet<Dog> dset = new TreeSet<Dog>();
		dset.add(new Dog(2));
		dset.add(new Dog(1));
		dset.add(new Dog(3));
 
		Iterator<Dog> iterator = dset.iterator();
 
		while (iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
	}
}

编译正常,但报运行时错误

Exception in thread "main" java.lang.ClassCastException: collection.Dog cannot be cast to java.lang.Comparable
	at java.util.TreeMap.put(Unknown Source)
	at java.util.TreeSet.add(Unknown Source)
	at collection.TestTreeSet.main(TestTreeSet.java:22)

因为TreeSet是有序的,所以添加到其中的对象需要实现Comparable的compareTo() 方法。

class Dog implements Comparable<Dog>{
	int size;
 
	public Dog(int s) {
		size = s;
	}
 
	public String toString() {
		return size + "";
	}
 
	@Override
	public int compareTo(Dog o) {
	        return size - o.size;
	}
}

重新运行之前的代码,返回结果:

1 2 3 

4,HashSet示例

HashSet<Dog> dset = new HashSet<Dog>();
dset.add(new Dog(2));
dset.add(new Dog(1));
dset.add(new Dog(3));
dset.add(new Dog(5));
dset.add(new Dog(4));
Iterator<Dog> iterator = dset.iterator();
while (iterator.hasNext()) {
	System.out.print(iterator.next() + " ");
}
返回结果

5 3 2 1 4 

注意上面的返回顺序并不一定。


5,LinkedHashSet示例

LinkedHashSet<Dog> dset = new LinkedHashSet<Dog>();
dset.add(new Dog(2));
dset.add(new Dog(1));
dset.add(new Dog(3));
dset.add(new Dog(5));
dset.add(new Dog(4));
Iterator<Dog> iterator = dset.iterator();
while (iterator.hasNext()) {
	System.out.print(iterator.next() + " ");
}

顺序是确定的,即插入顺序。

2 1 3 5 4 



6,性能测试

测试add方法。

public static void main(String[] args) {
 
	Random r = new Random();
 
	HashSet<Dog> hashSet = new HashSet<Dog>();
	TreeSet<Dog> treeSet = new TreeSet<Dog>();
	LinkedHashSet<Dog> linkedSet = new LinkedHashSet<Dog>();
 
	// start time
	long startTime = System.nanoTime();
 
	for (int i = 0; i < 1000; i++) {
		int x = r.nextInt(1000 - 10) + 10;
		hashSet.add(new Dog(x));
	}
	// end time
	long endTime = System.nanoTime();
	long duration = endTime - startTime;
	System.out.println("HashSet: " + duration);
 
	// start time
	startTime = System.nanoTime();
	for (int i = 0; i < 1000; i++) {
		int x = r.nextInt(1000 - 10) + 10;
		treeSet.add(new Dog(x));
	}
	// end time
	endTime = System.nanoTime();
	duration = endTime - startTime;
	System.out.println("TreeSet: " + duration);
 
	// start time
	startTime = System.nanoTime();
	for (int i = 0; i < 1000; i++) {
		int x = r.nextInt(1000 - 10) + 10;
		linkedSet.add(new Dog(x));
	}
	// end time
	endTime = System.nanoTime();
	duration = endTime - startTime;
	System.out.println("LinkedHashSet: " + duration);
 
}

返回结果,可见HashSet是最快的,TreeSet是最慢的,因为它是有序的。

HashSet: 2244768
TreeSet: 3549314
LinkedHashSet: 2263320

hashset-treeset-linkedhashset



内容概要:文章以“智能网页数据标注工具”为例,深入探讨了谷歌浏览器扩展在毕业设计中的实战应用。通过开发具备实体识别、情感分类等功能的浏览器扩展,学生能够融合前端开发、自然语言处理(NLP)、本地存储与模型推理等技术,实现高效的网页数据标注系统。文中详细解析了扩展的技术架构,涵盖Manifest V3配置、内容脚本与Service Worker协作、TensorFlow.js模型在浏览器端的轻量化部署与推理流程,并提供了核心代码实现,包括文本选择、标注工具栏动态生成、高亮显示及模型预测功能。同时展望了多模态标注、主动学习与边缘计算协同等未来发展方向。; 适合人群:具备前端开发基础、熟悉JavaScript和浏览器机制,有一定AI模型应用经验的计算机相关专业本科生或研究生,尤其适合将浏览器扩展与人工智能结合进行毕业设计的学生。; 使用场景及目标:①掌握浏览器扩展开发全流程,理解内容脚本、Service Worker与弹出页的通信机制;②实现在浏览器端运行轻量级AI模型(如NER、情感分析)的技术方案;③构建可用于真实场景的数据标注工具,提升标注效率并探索主动学习、协同标注等智能化功能。; 阅读建议:建议结合代码实例搭建开发环境,逐步实现标注功能并集成本地模型推理。重点关注模型轻量化、内存管理与DOM操作的稳定性,在实践中理解浏览器扩展的安全机制与性能优化策略。
基于Gin+GORM+Casbin+Vue.js的权限管理系统是一个采用前后端分离架构的企业级权限管理解决方案,专为软件工程和计算机科学专业的毕业设计项目开发。该系统基于Go语言构建后端服务,结合Vue.js前端框架,实现了完整的权限控制和管理功能,适用于各类需要精细化权限管理的应用场景。 系统后端采用Gin作为Web框架,提供高性能的HTTP服务;使用GORM作为ORM框架,简化数据库操作;集成Casbin实现灵活的权限控制模型。前端基于vue-element-admin模板开发,提供现代化的用户界面和交互体验。系统采用分层架构和模块化设计,确保代码的可维护性和可扩展性。 主要功能包括用户管理、角色管理、权限管理、菜单管理、操作日志等核心模块。用户管理模块支持用户信息的增删改查和状态管理;角色管理模块允许定义不同角色并分配相应权限;权限管理模块基于Casbin实现细粒度的访问控制;菜单管理模块动态生成前端导航菜单;操作日志模块记录系统关键操作,便于审计和追踪。 技术栈方面,后端使用Go语言开发,结合Gin、GORM、Casbin等成熟框架;前端使用Vue.js、Element UI等现代前端技术;数据库支持MySQL、PostgreSQL等主流关系型数据库;采用RESTful API设计规范,确保前后端通信的标准化。系统还应用了单例模式、工厂模式、依赖注入等设计模式,提升代码质量和可测试性。 该权限管理系统适用于企业管理系统、内部办公平台、多租户SaaS应用等需要复杂权限控制的场景。作为毕业设计项目,它提供了完整的源码和论文文档,帮助学生深入理解前后端分离架构、权限控制原理、现代Web开发技术等关键知识点。系统设计规范,代码结构清晰,注释完整,非常适合作为计算机相关专业的毕业设计参考或实际项目开发的基础框架。 资源包含完整的系统源码、数据库设计文档、部署说明和毕
<think>我们被要求回答HashSetLinkedHashSetTreeSet的区别。根据之前的引用内容,我们可以从以下几个方面进行对比: 1. 底层实现 2. 元素唯一性 3. 元素排序/顺序特性 4. 性能比较(插入、删除、查找) 5. 适用场景 此外,我们还需要注意回答的结构,使用适当的标题,并在最后生成相关问题。 根据引用[1][2][3][4]的内容,我们可以总结如下: 1. 底层实现: - HashSet: 基于HashMap实现,使用哈希表(数组+链表/红黑树)。 - LinkedHashSet: 继承自HashSet,底层使用LinkedHashMap,维护了一个双向链表来记录插入顺序。 - TreeSet: 基于TreeMap实现,使用红黑树(自平衡二叉查找树)。 2. 元素唯一性:三者都实现了Set接口,因此都不允许重复元素。 3. 元素排序/顺序特性: - HashSet:无序,不保证元素的任何顺序(迭代顺序可能变化)。 - LinkedHashSet:按照元素插入的顺序进行排序(即插入顺序)。 - TreeSet:按照元素的自然顺序(实现Comparable接口)或者根据提供的Comparator进行排序(树的有序结构保证)。 4. 性能比较: - HashSet:插入、删除和查找操作的时间复杂度通常为$O(1)$(在哈希函数分散均匀的情况下)。 - LinkedHashSet:由于需要维护双向链表,性能略低于HashSet,但迭代顺序可预测,且迭代性能比HashSet好(因为链表连接了所有元素)。 - TreeSet:插入、删除和查找操作的时间复杂度为$O(\log n)$,因为需要维护红黑树的平衡。 5. 允许null值: - HashSetLinkedHashSet允许一个null元素。 - TreeSet不允许null元素(因为需要比较,null无法比较)。 6. 线程安全:三者都不是线程安全的。 7. 适用场景: - HashSet:当不需要维护顺序,只需要高效地添加、删除和判断元素是否存在时使用。 - LinkedHashSet:当需要维护元素的插入顺序时使用。 - TreeSet:当需要元素按照排序顺序(升序或降序)时使用。 我们按照以上要点组织答案。 </think>### HashSetLinkedHashSetTreeSet的核心区别 以下是Java中三种Set实现的对比总结,涵盖底层实现、排序特性、性能表现和适用场景: | **特性** | **HashSet** | **LinkedHashSet** | **TreeSet** | |------------------|--------------------------------|--------------------------------------|--------------------------------| | **底层实现** | 基于`HashMap`(哈希表+链表/红黑树) | 继承`HashSet`,底层为`LinkedHashMap`(哈希表+双向链表) | 基于`TreeMap`(红黑树) | | **元素唯一性** | ✅ 不允许重复元素 | ✅ 不允许重复元素 | ✅ 不允许重复元素 | | **排序特性** | ❌ 完全无序 | ✅ 保留插入顺序 | ✅ 自然排序或自定义排序(`Comparator`) | | **`null`支持** | ✅ 允许1个`null`元素 | ✅ 允许1个`null`元素 | ❌ 禁止`null`(需可比较) | | **时间复杂度** | $O(1)$(理想情况) | $O(1)$(操作略慢于`HashSet`) | $O(\log n)$(所有操作) | | **内存开销** | 较低(仅哈希表) | 较高(额外维护链表指针) | 较高(红黑树结构) | | **线程安全** | ❌ 非线程安全 | ❌ 非线程安全 | ❌ 非线程安全 | #### 详细解析 1. **底层实现与排序差异** - **HashSet**:通过`hashCode()`定位存储桶位置,迭代顺序不可预测(如`[A,C,B]`)。 - **LinkedHashSet**:在`HashSet`基础上增加双向链表,严格保持插入顺序(如`[A,B,C]`)[^1][^4]。 - **TreeSet**:通过红黑树实现自动排序(默认自然顺序,如字母升序`[A,B,C]`),可自定义`Comparator`[^3]。 2. **性能对比** - **插入/查找效率**: - `HashSet` ≈ `LinkedHashSet` > `TreeSet` - 原因:`HashSet`和`LinkedHashSet`基于哈希表(常数时间),`TreeSet`需维护红黑树平衡(对数时间)[^3]。 - **迭代效率**: - `LinkedHashSet` > `TreeSet` > `HashSet` - 原因:`LinkedHashSet`链表遍历直接有序,`TreeSet`中序遍历有序,`HashSet`需扫描全部哈希桶[^2]。 3. **适用场景建议** - **HashSet**:高频读写场景,不关心顺序(如去重统计)。 ```java Set<String> cache = new HashSet<>(); // 网页URL去重缓存 ``` - **LinkedHashSet**:需保留操作历史的场景(如用户操作记录)。 ```java Set<String> userActions = new LinkedHashSet<>(); // 记录用户点击顺序 ``` - **TreeSet**:需动态排序的场景(如排行榜)。 ```java Set<Integer> highScores = new TreeSet<>(Comparator.reverseOrder()); // 游戏分数降序 ``` #### 关键注意事项 - **哈希碰撞影响**:`HashSet`和`LinkedHashSet`性能受`hashCode()`质量影响,碰撞过多会导致退化为$O(n)$[^3]。 - **线程安全方案**:三者均非线程安全,推荐: ```java Set<String> safeSet = Collections.synchronizedSet(new HashSet<>()); // 同步包装 Set<String> concurrentSet = new ConcurrentSkipListSet<>(); // 并发有序集合 ``` - **扩展选择**: - 需线程安全+排序 → `ConcurrentSkipListSet` - 需高并发+无序 → `CopyOnWriteArraySet`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值