.net集合类的研究--哈希表(二)--HashSet<T>

.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>的操作方式。

转载于:https://www.cnblogs.com/hkncd/archive/2011/05/09/2040978.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: HashSet<ProductSpuVO> spuSet = new HashSet<>(productSpuVOS) 的作用是将 ProductSpuVO 类型的列表 productSpuVOS 转换为 HashSet 集合 spuSet,并去除重复元素。在 HashSet 中,元素是无序的,因此无法保证它们被放置的顺序。此方法可以用于数据去重,或者在需要快速判断一个元素是否存在于列表中时使用。 ### 回答2: HashSet\<ProductSpuVO> spuSet = new HashSet<>(productSpuVOS) 这行代码的作用是创建一个基于哈希表的集合,并将一个名为productSpuVOS的List类型的对象转换为HashSet类型的对象。 HashSet是Java中提供的集合类之一,它是基于哈希表实现的,不允许重复元素的集合。HashSet的特点是元素的存储顺序是无序的,且不保证元素的顺序不变。 在这行代码中,productSpuVOS是一个List类型的对象,里面存储了一些ProductSpuVO类型的元素。通过将productSpuVOS传入HashSet的构造方法,就可以将List类型的对象转换为HashSet类型的对象。 HashSet的作用是用于存储一组元素,而且元素之间不能有重复。当需要对一组元素进行唯一性判断时,可以使用HashSetHashSet是基于哈希表实现的,其添加、删除、查找元素的性能都很高,可以快速判断元素是否存在于集合中。 在这个例子中,spuSet对象就是用来存储一组ProductSpuVO类型的元素,并且保证元素的唯一性。可以通过spuSet来判断某个ProductSpuVO对象是否在集合中,也可以通过spuSet来进行元素的添加、删除和查找操作。 总的来说,HashSet\<ProductSpuVO> spuSet = new HashSet<>(productSpuVOS) 这行代码将一个List类型的对象转换为HashSet类型的对象,用于存储一组ProductSpuVO类型的元素,并且保证元素的唯一性。 ### 回答3: HashSet<ProductSpuVO> spuSet = new HashSet<>(productSpuVOS)的作用是将一个包含ProductSpuVO对象的列表转换为一个HashSet集合。 HashSet是Java中的一种集合类型,它实现了Set接口。与List不同,HashSet中的元素是不可重复的,并且没有固定的顺序。 在给定的代码中,productSpuVOS是一个包含ProductSpuVO对象的列表。通过将这个列表传递给HashSet的构造函数,我们可以创建一个新的HashSet集合对象,其中包含了相同的元素。 HashSet的作用主要有两个方面: 1. 去重:由于HashSet中的元素不能重复,所以将列表转换为HashSet会自动去除重复的元素。这对于需要保持唯一性的数据集合很有用。 2. 提高查询性能:HashSet是通过散列算法来存储元素的,所以当需要查找某个元素是否存在于集合时,HashSet可以提供比列表更高效的查询性能。 总结起来,HashSet<ProductSpuVO> spuSet = new HashSet<>(productSpuVOS)的作用是将一个包含ProductSpuVO对象的列表转换为一个去重的HashSet集合,并且可以通过散列算法提高对元素的查询性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值