• 转载《 .NET 4 新增的 SortedSet 类 》


    微软在 .NET 3.5 新增了一个 HashSet 类,在 .NET 4 新增了一个 SortedSet 类,本文介绍他们的特性,并比较他们的异同。

    .NET Collection 函数库的 HashSet、SortedSet 这两个泛型的类,都实现了 System.Collections.Generic.ISet 接口;但 Java 早在 1.2 (或更早) 之前的版本,即已提供了实现这两种数据结构的同名类 [10],且还有更严谨的 TreeSet (里面存储的项,连类型都必须一致。当年还没有泛型)。


    Set 是「集合」的意思,其在数学上的定义,是里面元素的存放没有特定的顺序,且不允许重复。我们先看以下 HashSet、SortedSet 的示例:

    ISet<int> set = new HashSet<int>() { 59212237499 };

    foreach (int element in set)
        Response.Write(
    string.Format(" {0}", element)); 

     执行结果:


    图 1 重复的元素自动被移除


    同样的代码,把 HashSet 改成 SortedSet,如下:

    ISet<int> set = new SortedSet<int>() { 59212237499 };

    foreach (int element in set)
        Response.Write(
    string.Format(" {0}", element)); 

     执行结果:


    图 2 重复的元素自动被移除,且内部会自动做排序


    我们看到 HashSet、SortedSet 这两个类,确实都不允许重复,但前者是按照元素加入的顺序存储,后者会再将加入的元素做排序,且能够在插入、删除和搜索元素时,仍维护数据的排列顺序。因此若您有耐心读到这里,就多学了一招:若平常编程时想过滤重复的项的话,就可以用这两个 Set 类,因为集合是不允许重复元素的。在 SortedSet 还没出现的 .NET 3.5 时代,我们必须用 HashSet 先移除重复的项,然后再排序;而现在的 .NET 4,我们就可以改用 SortedSet 一步实现移除重复并排序。

    当然,若您的需求不同 (暂不考虑性能差别),不希望默认自动排序,或不需要去除重复元素,可改用 List 类的 Sort 方法。此外,您也可把 HashSet 当作 key/value 配对的 Dictionary 类之中,只有 key 没有 value 来使用,因为 Dictionary (泛型的 HashTable) 其特性,和 HastSet 类似,元素也是没有特定的顺序,且不允许重复 (key 必须为唯一)。

    ------------------------------------------------------------------------


    以下分别列出 .NET 平台上,HashSet、SortedSet 这两个类各自的一些特性:


    HastSet 的特性 [11]

    • 它的 Contains 方法 (确定 HashSet 对象是否包含指定的元素) 执行速度很快,因其为基于「哈希」的查找 (hash-based lookup)。
      (另 Dictionary 类的检索速度也是非常快的,其「算法」的 Time Complexity 接近于 O(1),这是因为 Dictionary 类是以一个哈希表来实现的)
    • 它的 Add 方法 (将指定的元素添加到 HashSet 对象中),如果 Count 小于内部数组的容量,则此方法的运算复杂度为 O(1)。如果必须调整 HashSet<T> 对象的大小,则此方法的运算复杂度将为 O(n)。[4]
    • 它不能存储重复的元素,而且当插入的元素有重复时,也会自动被忽略。
    • 无法从特定的位置,访问其中某个元素。


    SortedSet 的特性 [6]

    • 它的 Contains 方法 (确定 HashSet 对象是否包含指定的元素) 执行速度很快,因其为基于「哈希」的查找 (hash-based lookup)。
    • 它的 Add 方法 (将指定的元素添加到 HashSet 对象中),如果 Count 小于内部数组的容量,则此方法的运算复杂度为 O(1)。如果必须调整 HashSet<T> 对象的大小,则此方法的运算复杂度将为 O(n)。(数据结构中的「红黑树 (Red-Black tree」) [3], [8]
    • 它的 Add 方法,若添加了已存在的项时会被忽略,并且返回 False。
    • 它不能存储重复的元素,而且当插入的元素有重复时,也会自动被忽略。
    • 无法从特定的位置,访问其中某个元素。

    ------------------------------------------------------------------------


    以下我们来看 .NET 里 HashSet 的一些示例:


    示例一 - 测试查找的功能:

    var set = new HashSet<char>("我爱编程");

    Response.Write(
    set.Contains(''));  //True
    Response.Write(set.Contains(''));  //False

     上述示例中,我们能够将字符串,甚至中文字,传入 HashSet<char> 的构造函数,是因为 string 实现了 IEnumerable<char> 接口,而 HastSet 类也实现了 IEnumerable<T>。


    示例二 - 测试 HashSet 内置的一些好用方法:

    1. SymmetricExceptWith: 仅包含该对象或指定集合中存在的元素(但不可同时包含两者中的元素)。
    2. UnionWith: 包含该对象本身和指定集合中存在的所有元素。
    3. ExceptWith: 从当前 HashSet<T> 对象中移除指定集合中的所有元素。
    4. IntersectWith: 仅包含该对象和指定集合中存在的元素。
    using System;
    using System.Collections.Generic;

    class HashSetDemo
    {
        
    static void Main()
        {
            HashSet
    <char> setA = new HashSet<char>();
            HashSet
    <char> setB = new HashSet<char>();

            setA.Add(
    'A');
            setA.Add(
    'B');
            setA.Add(
    'C');

            setB.Add(
    'C');
            setB.Add(
    'D');
            setB.Add(
    'E');

            Show(
    "Initial content of setA: ", setA);
            Show(
    "Initial content of setB: ", setB);

            setA.SymmetricExceptWith(setB);   
    //把 setA、setB 各自特有、对方没有的元素列出来
            Show("setA after Symmetric difference with SetB: ", setA);

            setA.UnionWith(setB);       
    //把 setA、setB 的全部元素列出来 (union 并集)
            Show("setA after union with setB: ", setA);

            setA.ExceptWith(setB);      
    //把 setA 中,所拥有的 setB 元素移除
            Show("setA after subtracting setB: ", setA);

            setA.IntersectWith(setB);   
    //把 setA 中,所拥有的 setB 元素列出
            Show("setA after intersect with setB: ", setA);

            Console.WriteLine();
            Console.Read();
        }

        
    static void Show(string msg, HashSet<char> set)
        {
            Console.Write(msg);
            
    foreach (char ch in set)
                Console.Write(ch 
    + " ");
            Console.WriteLine();
        }
    }

    执行结果:



    图 3


    由于 HastSet<T> 实现了 IEnumerable<T> 接口,因此我们可把其他任何 set 当作参数,传入其他 set 类的运算方法里。


    此外,LINQ 也有类似上述示例的 Intersect、Except、Union、Distinct 的 set 运算功能,有兴趣比较两者特性的网友,可参考 msdn 或网络上的文章 [5]。主要的差别在于,LINQ set 运算始终返回新的 IEnumerable<T> 集合,而 HashSet<T> 是修改当前的集合,且 HashSet 提供了比较多的 set 相关算符。

    ------------------------------------------------------------------------


    到了 .NET 4 才新建的 SortedSet 类,除了有前述 HashSet 类所拥有的 SymmetricExceptWith、UnionWith、ExceptWith、IntersectWith 等好用的方法外,还有「GetViewBetween (制定范围)」、「Max (取最大值)」、「Min (取最小值)」等新增的好用方法。


    以下我们来看 SortedSet 这三个方法的示例:


    例三 - 测试 GetViewBetween、Max、Min 方法:

    using System;
    using System.Collections.Generic;
    using System.Linq;    //此为 Max()、Min() 方法的必要引用

    var 
    set = new SortedSet<int>() { 59212237499 };

    foreach (int element in set)
        Response.Write(
    string.Format(" {0}", element));

    Response.Write(
    "<p>");
    Response.Write(
    "Max: " + set.Max() + "<br>");
    Response.Write(
    "Min: " + set.Min() + "<br>");

    Response.Write(
    "<br>取 2 ~ 5 之间的值: <br>");

    //只取值为 2 ~ 5 之间的元素
    var subSet = set.GetViewBetween(25);
    foreach (int i in subSet)
    {            
        Response.Write(i 
    + ",");
    }

    执行结果:


    图 4


    此 GetViewBetween() 方法,也适用于 SortedSort 里元素为字符串、字符的处理 [6]。 - ------------------------------------------------------------------------


    参考资料:

    [1] SortedSet<T> 类
    http://msdn.microsoft.com/zh-cn/library/dd412070.aspx

    [2] HashSet<T> 类
    http://msdn.microsoft.com/zh-cn/library/bb359438.aspx

    [3] SortedSet<T> 成员
    http://msdn.microsoft.com/zh-cn/library/dd382202.aspx

    [4] HashSet<T> 成员
    http://msdn.microsoft.com/zh-cn/library/bb341004.aspx

    [5] HashSet 和 LINQ Set 运算
    http://msdn.microsoft.com/zh-cn/library/bb397728.aspx
    http://www.dotblogs.com.tw/kirkchen/archive/2010/06/12/15836.aspx

    [6] C# 4.0/BCL 4 Series:SortedSet<T> in Framework 4
    http://samgentile.com/Web/vs2010-and-net-framework-4-0/c-4-0-bcl-4-series-sortedset-lt-t-gt-in-framework-4/

    [7] SortedSet Collection Class in .NET 4.0
    http://www.codeproject.com/KB/cs/SortedSet_T__Collection.aspx

    [8] Add to SortedSet<T> and its complexity
    http://stackoverflow.com/questions/2533007/add-to-sortedsett-and-its-complexity

    [9] Net4.0---Framwork新增特性
    http://www.cnblogs.com/oec2003/archive/2010/05/26/1744495.html

    [10] 用 Java 的 SortedSet 实现过滤重复字符串并排序
    http://www.cnblogs.com/fzzl/archive/2009/04/01/1427344.html
    http://www.cnblogs.com/fzzl/archive/2009/04/01/1427336.html


    参考书籍:

    [11] C# 3.0 in a Nutshell, chapter 7
    http://www.amazon.com/3-0-Nutshell-Desktop-Reference-OReilly/dp/0596527578
    http://www.albahari.com/nutshell/

    [12] C# 3.0 THE COMPLETE REFERENCE, chapter 24
    http://www.amazon.com/3-0-COMPLETE-REFERENCE-Herbert-Schildt/dp/0071588418/ref=sr_1_11?ie=UTF8&s=books&qid=1276701548&sr=1-11


    相关资料:

    [13] 程序员真情忏悔录
    http://www.cnblogs.com/WizardWu/archive/2009/01/29/1381275.html

    当你在使用 Java (或 .NET) 提供的 Collection Framework 时,你了解 ArrayList、LinkedList、TreeSet、HashSet 之间的差别吗?
    你知道他们的优缺点吗?你知道他的特性吗?不了解 ArrayList 和 LinkedList 的差异,用任一种去写程序,执行结果都一样,可是性能差很多。大多数的人连了解特性都谈不上,更别说很多每天想发展自己的语言、自己的编译器、自己的操作系统的人。没有基础学问的了解,如何去设计一个 Collection Framework 或 STL?你说数据结构和算法没有用,你去做看看现在 IDE 中普遍有的 code insight 功能看看 ?以 C++ Builder 来说,要在短时间内搜寻所有的标头文件,并找出某函数的 prototype,如果没有对数据结构和算法有充分了解,一样做得出来,只是产品会卖不出去罢了。

  • 相关阅读:
    Steve Jobs 2005年于 Stanford University 毕业典礼上的演讲
    欧姆龙血糖仪HEA214换购备忘
    (转载)2011年高考作文之《时间在流逝》(安徽考生)
    2012年部分节假日安排(转载)
    乔布斯语录(转载)
    欢乐谷一日游
    上海公交投诉电话:12319
    中国公路“买路钱”应该怎么管?(转载)
    C#操作excel
    SQL Server数据库对列的操作
  • 原文地址:https://www.cnblogs.com/flish/p/1759345.html
Copyright © 2020-2023  润新知