.Net3.5之后出现了HashSet<T>,硬翻译过来就是“哈希集合”,跟“哈希”两字挂钩说明这种集合的内部实现用到了哈希算法,用Reflector工具就可以发现,HashSet<T>和Dictionary<TKey,TValue>使用了相同的存储方式和哈希冲突算法,那么,它跟Dictionary<TKey,TValue>和Hashtable在使用上到底有什么不同?

HashSet<T>对集合运算的操作

HashSet<T>是一个Set集合,虽然List、Collection也叫集合,但Set集合和它们却大有不同。

HashSet<T>提供了和“Set集合运算”相关的方法,如:

IntersectWith (IEnumerable<T> other) (交集)

public void IntersectWithTest()
{
HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 };
HashSet<int> set2 = new HashSet<int>() { 2, 3, 4 }; set1.IntersectWith(set2); foreach (var item in set1)
{
Console.WriteLine(item);
} //输出:2,3
}

UnionWith (IEnumerable<T> other) (并集)

public void UnionWithTest()
{
HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 };
HashSet<int> set2 = new HashSet<int>() { 2, 3, 4 }; set1.UnionWith(set2); foreach (var item in set1)
{
Console.WriteLine(item);
} //输出:1,2,3,4
}

ExceptWith (IEnumerable<T> other) (排除)

public void ExceptWithTest()
{
HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 };
HashSet<int> set2 = new HashSet<int>() { 2, 3, 4 }; set1.ExceptWith(set2); foreach (var item in set1)
{
Console.WriteLine(item);
} //输出:1
}

这些对集合的操作是List<T>、Hashtable和Dictionary<TKey,TValue>所缺少的,但是伴随着Linq和扩展方法的出现,.net 3.5为泛型集合提供了一系列的扩展方法,使得所有的泛型集合具备了set集合操作的能力。

例如与HashSet的IntersectWith 方法对应的扩展方法是IEnumerable<T> 的Intersect,两者的区别是:

HashSet<T>.IntersectWith 是对当前集合进行修改,没有返回值;

IEnumerable<T>.Intersect并不修改原集合,而是返回了一个新的集合。

实例代码如下:

public void IntersectTest()
{
HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 };
HashSet<int> set2 = new HashSet<int>() { 2, 3, 4 }; IEnumerable<int> set3=set1.Intersect(set2); foreach (var item in set1)
{
Console.WriteLine(item);
} foreach (var item in set3)
{
Console.WriteLine(item);
} //输出:o
//set1 : 1,2,3
//set3 : 2,3
}

IEnumerable<T> 其他的扩展方法也是一样,都是不改变调用方法的数组,而是产生并返回新的IEnumerable<T>接口类型的数组,当然你可以通过ToArray,ToList,ToDictionary将返回值转换成你想要的集合类型。

至于如何使用这两种集合操作方式,要取决于你的习惯和业务需求。

HashSet<T>的特点

在3.5之前,想用哈希表来提高集合的查询效率,只有Hashtable和Dictionary<TKey,TValue>两种选择,而这两种都是键-值方式的存储。但有些时候,我们只需要其中一个值,例如一个Email集合,如果用泛型哈希表来存储,往往要在Key和Value各保存一次,不可避免的要造成内存浪费。而HashSet<T>只保存一个值,更加适合处理这种情况。

此外,HashSet<T>的Add方法返回bool值,在添加数据时,如果发现集合中已经存在,则忽略这次操作,并返回false值。而Hashtable和Dictionary<TKey,TValue>碰到重复添加的情况会直接抛出错误。

从使用上来看,HashSet<T>和线性集合List<T>更相似一些,但前者的查询效率有着极大的优势。假如,用户注册时输入邮箱要检查唯一性,而当前已注册的邮箱数量达到10万条,如果使用List<T>进行查询,需要遍历一次列表,时间复杂度为O(n),而使用HashSet<T>则不需要遍历,通过哈希算法直接得到列表中是否已存在,时间复杂度为O(1),这是哈希表的查询优势,在上一篇中已提到。

HashSet<T>的不能做的事情

HashSet<T>是Set集合,它只实现了ICollection接口,在单独元素访问上,有很大的限制:

跟List<T>相比,不能使用下标来访问元素,如:list[1] 。

跟Dictionary<TKey,TValue>相比,不能通过键值来访问元素,例如:dic[key],因为HashSet<T>每条数据只保存一项,并不采用Key-Value的方式,换句话说,HashSet<T>中的Key就是Value,假如已经知道了Key,也没必要再查询去获取Value,需要做的只是检查值是否已存在。

所以剩下的仅仅是开头提到的集合操作,这是它的缺点,也是特点。

总结

综上可知,HashSet<T>是一个Set集合,查询上有较大优势,但无法通过下标方式来访问单个元素,这点会让用惯了List<T>的人(我就是),用起来很不顺手。

HashSet<T>有别于其他哈希表,具有很多集合操作的方法,但优势并不明显,因为.net 3.5之后扩展方法赋予了泛型集合进行集合操作的能力,但扩展方法的集合操作往往返回新的集合,在使用习惯上,我个人更偏爱HashSet<T>的操作方式。

哈希表--HashSet<T>的更多相关文章

  1. HashMap/HashSet,hashCode,哈希表

    hash code.equals和“==”三者的关系 1) 对象相等则hashCode一定相等: 2) hashCode相等对象未必相等. == 是比较地址是否相等,JAVA中声明变量都是引用嘛,不同 ...

  2. Junit 注解 类加载器 .动态代理 jdbc 连接池 DButils 事务 Arraylist Linklist hashset 异常 哈希表的数据结构,存储过程 Map Object String Stringbufere File类 文件过滤器_原理分析 flush方法和close方法 序列号冲突问题

    Junit 注解 3).其它注意事项: 1).@Test运行的方法,不能有形参: 2).@Test运行的方法,不能有返回值: 3).@Test运行的方法,不能是静态方法: 4).在一个类中,可以同时定 ...

  3. stl vector、红黑树、set、multiset、map、multimap、迭代器失效、哈希表(hash_table)、hashset、hashmap、unordered_map、list

    stl:即标准模板库,该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法 六大组件: 容器.迭代器.算法.仿函数.空间配置器.迭代适配器 迭代器:迭代器(iterator)是一种抽象的设计 ...

  4. Java学习:Set接口与HashSet集合存储数据的结构(哈希表)

    Set接口 java.util.Set接口 extends Collection接口 Set接口的特点: 不允许存储重复的元素 没有索引,没有带索引的方法,也不能使用普通的for循环遍历 java.u ...

  5. HashSet集合存储数据的结构(哈希表)和Set集合存储㢝不重复的原理

    HashSet集合存储数据的结构(哈希表) Set集合存储㢝不重复的原理 前提:存储的元素必须重写hashCode方法和equals方法

  6. Java学习笔记31(集合框架五:set接口、哈希表的介绍)

    set接口的特点: 1.不包含重复元素 2.set集合没有索引,只能用迭代器或增强for循环遍历 3.set的底层是map集合 方法和Collection的方法基本一样 set接口的实现类HashSe ...

  7. Java List集合和哈希表

    List集合和Set集合,先来看List集合. List集合存储元素的特点: 1.有序(List集合中的元素有下标):存进去是什么样,取出来还是什么样 2.可重复 可以结合以下的简单代码来看一看. i ...

  8. 《数据结构与算法分析:C语言描述》复习——第七章“哈希”——哈希表

    2014.06.22 12:36 简介: 哈希是一种数学思想,将不定长数据通过函数转换为定长数据.不定长数据通常意味着碎片化,动态分配内存等等影响存储和性能的因素.当这个定长数据是一个无符号整数时,可 ...

  9. 算法与数据结构基础 - 哈希表(Hash Table)

    Hash Table基础 哈希表(Hash Table)是常用的数据结构,其运用哈希函数(hash function)实现映射,内部使用开放定址.拉链法等方式解决哈希冲突,使得读写时间复杂度平均为O( ...

随机推荐

  1. Socket 多线程FTP软件开发

    Socket具体还可见360云中文档记载 Socket是一个非常古老的协议了 1970年 Socket.AF_Unix======AF意思是  addressFamily 地址簇 Import os ...

  2. php面试题之三——PHP语言基础(基础部分)

    三.PHP语言基础 1. strlen( )与 mb_strlen( )的作用分别是什么(新浪网技术部) strlen和mb_strlen都是用于获取字符串长度. strlen只针对单字节编码字符,也 ...

  3. 成为Android高手必须掌握的28大项内容和10个建议

    (一)成为Android高手必须掌握的8项基本要求 [1] Android操作系统概述1. Android系统架构.           2. Android利用设计理念.           3. ...

  4. [codeforces 325]B. Stadium and Games

    [codeforces 325]B. Stadium and Games 试题描述 Daniel is organizing a football tournament. He has come up ...

  5. win10 x64下安装oracle 12c出现[INS-30131]报错的解决方案

    解决方案: 第一步:控制面板>所有控制面板项>管理工具>服务>SERVER 启动 第二步:控制面板>所有控制面板项>管理工具>计算机管理>系统工具> ...

  6. 暑假热身 E. 无聊的LSY

    LSY大牛没事就爱玩游戏,包括很多很无聊的游戏.某日,LSY大牛又找到了一个无聊的游戏:每一局游戏的开始,LSY大牛将代表自己的棋子放在一个线性棋盘的最左端(第0个格子,可以认为向右端无限延伸),接着 ...

  7. Linux 查看网络连接状态

    CLOSED:无连接是活动的或正在进行ESTABLISED:已建立连线的状态:SYN_SENT:发出主动连线 (SYN 标志) 的连线封包:SYN_RECV:接收到一个要求连线的主动连线封包:FIN_ ...

  8. python 最佳入门实践

    勿在浮沙筑高台,无论什么技术,掌握核心精神和api,是很重要的. 但是入门过程也可能不是一帆风顺的,这里有八个入门任务,看看你完成了没有: http://code.tutsplus.com/artic ...

  9. Python配合BeautifulSoup读取网络图片并保存在本地

    本例为Python配合BeautifulSoup读取网络图片,并保存在本地. BeautifulSoup可代替正则表达式,更好地解析Html文本,获取其中的指定内容,如Tag.Property等 # ...

  10. shell笔记-local、export用法 、declare、set

    local一般用于局部变量声明,多在在函数内部使用.     1.    Shell脚本中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止.     2. ...