理论:

集合的定义

集合成员是无序的、并且都是只出现一次。

空集合:是不包含任何成员的集合。

全域:是所有可能成员的集合。

集合的操作

联合:两个集合的并集

交叉:两个集合的交集

差异:存在于第一个集合,但不存在于第二个集合,也就是相对补集,A相对B的补集。

集合的属性(性质)

集合与空集合的交叉是空集合。集合与空集合的联合是集合本身。

集合与自身的交叉是自身,与自身的联合还是联合。

联合、交叉满足交换律、结合律、分配律。

吸收定律

集合A联合另一集合B再交叉自身集合A,结果还是集合A。

德摩根定律

集合A差异(集合B交叉集合C)等于(集合A差异集合B)联合(集合A差异集合B)。

集合A差异(集合B联合集合C)等于(集合A差异集合B) 交叉 (集合A差异集合B)。


实例1:


用散列表实现一个Set集合类

用散列表可以存储任何类型的数据项。


散列表/哈希表:  它使用来访问集合中的元素。

当您使用键访问元素时,则使用哈希表,而且您可以识别一个有用的键值。哈希表中的每一项都有一个键/值对。键用于访问集合中的项目。

内部实现

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HashSet
{
    public class HashCSet
{
        private Hashtable data;
        public HashCSet() { data = new Hashtable(); }
        ///<summary>
        ///添加一个数据项。Hashtable的值为item,键为item根据内部散列函数计算的散列值。
        ///</summary>
        ///<param name="item"></param>
        public void Add(Object item)
{
            if (!data.ContainsValue(item))
            { data.Add(item, item); }
}
        ///<summary>
        ///散列函数,数据项字符的ASCII码值来计算散列值
        ///</summary>
        ///<param name="item"></param>
        ///<returns></returns>
        private string Hash(object item)
{
            char[] chars;
            string s = item.ToString();
            int hashvalue = 0;
            chars = s.ToCharArray();
            for (int i = 0; i <= chars.GetUpperBound(0); i++)
{
                hashvalue += (int)chars[i];
}
            return hashvalue.ToString();
}
        public void Remove(object item)
{
            data.Remove(Hash(item));
}
 
        public int Size
{
            get { return data.Count; }
}
        ///<summary>
        ///联合
        ///</summary>
        ///<param name="aSet"></param>
        ///<returns></returns>
        public HashCSet Union(HashCSet aSet)
{
            HashCSet tempSet = new HashCSet();
            foreach (Object hashObject in data.Keys)
                tempSet.Add(this.data[hashObject]);
            foreach (Object hashObject in aSet.data.Keys)
                if (!(this.data.ContainsKey(hashObject)))
            tempSet.Add(aSet.data[hashObject]);
            return tempSet;
}
        ///<summary>
        ///返回一个和指定集合交叉的集合
        ///</summary>
        ///<param name="aSet"></param>
        ///<returns></returns>
        public HashCSet Intersection(HashCSet aSet)
{
            HashCSet tempSet = new HashCSet();
            foreach (Object hashObject in data.Keys)
{
                if (aSet.data.Contains(hashObject))
            tempSet.Add(aSet.data[hashObject]);
}
            return tempSet;
}
        ///<summary>
        ///是否全部包含在一个集合内。判断当前集合是否是指定集合的一个子集
        ///</summary>
        ///<param name="aSet"></param>
        ///<returns></returns>
        public bool Subset(HashCSet aSet)
{
            if (this.Size > aSet.Size)
                return false;
            else
                foreach (Object key in this.data.Keys)
                    if (!(aSet.data.Contains(key)))
                        return false;
            return true;
}
        ///<summary>
        ///差异。返回一个和指定集合的差异集合
        ///</summary>
        ///<param name="aSet"></param>
        ///<returns></returns>
        public HashCSet Difference(HashCSet aSet)
{
            HashCSet tempSet = new HashCSet();
            foreach (Object hashObject in data.Keys)
                if (!(aSet.data.Contains(hashObject)))
            tempSet.Add(data[hashObject]);
            return tempSet;
}
        public override string ToString()
{
            string s = "";
            foreach (Object key in data.Keys)
                s += data[key] + " ";
            return s;
}
}
    class Program
{

        static void Main(string[] args)
{
            //使用实现
            //调用:
            HashCSet setA = new HashCSet();
            HashCSet setB = new HashCSet();
            //A
            setA.Add("milk");
            setA.Add("eggs");
            setA.Add("bacon");
            setA.Add("cereal");
            //B
            setB.Add("bacon");
            setB.Add("eggs");
            setB.Add("bread");
            HashCSet setC = new HashCSet();
            setC = setA.Union(setB);
            Console.WriteLine("A:" + setA.ToString());
            Console.WriteLine("B:" + setB.ToString());
            Console.WriteLine("A union B:" + setC.ToString());
            setC = setA.Intersection(setB);
            Console.WriteLine("A intersect B: " + setC.ToString());
            setC = setA.Difference(setB);
            Console.WriteLine("A diff B:" + setC.ToString());
            setC = setB.Difference(setA);
            Console.WriteLine("B diff A:" + setC.ToString());
            if (setB.Subset(setA))
                Console.WriteLine("b is a subset of a");
            else
                Console.WriteLine("b is not a subset of a");
            ///A:eggs milkcereal bacon
            ///B:eggsbacon bread
            ///A unionB:eggs milk cereal bread bacon
            ///A intersectB: eggs bacon
            ///A diffB:cereal milk
            ///B diffA:bread
            ///b is not asubset of a
            Console.ReadLine();
}
}
}


实例2:

用BitArray实现一个Set集合类


BitArray : 它代表了一个使用值 1 和 0 来表示的二进制数组。

当您需要存储位,但是事先不知道位数时,则使用点阵列。您可以使用整型索引从点阵列集合中访问各项,索引从零开始。



当集合存储的数据是整数时,使用BitArray内部实现的Set类,能有更好的性能。

BitArray只存储布尔数值,并且集合的四个操作(联合、交叉、差异、求子集)都可以利用布尔运算符(And、Or和Not)来实现。这些实现比散列表要快许多。

策略

用BitArray来创建整数集合的存储策略如下:

1. 添加数据1到集合中,即为索引位置为1的数组元素为true。

2. 判断数据1是否在集合内,即判断索引位置为1的数组元素是否为true。

3. 两个集合的联合,即两个BitArray的对应索引位置的两个布尔值的”a||b”。(A与B的并集)

4. 两个集合的交叉,即两个BitArray的对应索引位置的两个布尔值的”a&&b”。(A与B的交集)

5. 两个集合的差异,即两个BitArray的对应索引位置的两个布尔值的”a && !b”。(A与B补集的交集)

6. 判断集合A是否是集合B的子集,即两个BitArray的对应索引位置的两个布尔值的”a && !b”有存在ture。(A与B补集的交集为空)


内部实现:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BitArraySet
{
    public class BitArraySet
{
        private BitArray data;
        public BitArraySet()
{
            data = new BitArray(5);
}
        public void Add(int item)
{
            data[item] = true;
}
        public bool IsMember(int item)
{
            return data[item];
}
        public void Remove(int item)
{
            data[item] = false;
}
        public BitArraySet SetUnion(BitArraySet aSet)
{
            BitArraySet tempSet = new BitArraySet();
            for (int i = 0; i <= data.Count - 1; i++)
                tempSet.data[i] = (this.data[i] ||aSet.data[i]);
            return tempSet;
}
        public BitArraySet SetIntersection(BitArraySet aSet)
{
            BitArraySet tempSet = new BitArraySet();
            for (int i = 0; i <= data.Count - 1; i++)
                tempSet.data[i] = (this.data[i] &&aSet.data[i]);
            return tempSet;
}
        public BitArraySet SetDifference(BitArraySet aSet)
{
            BitArraySet tempSet = new BitArraySet();
            for (int i = 0; i <= data.Count - 1; i++)
                tempSet.data[i] = (this.data[i] &&(!(aSet.data[i])));
            return tempSet;
}
        public bool IsSubset(BitArraySet aSet)
{
            BitArraySet tempSet = new BitArraySet();
            for (int i = 0; i <= data.Count - 1; i++)
                if (this.data[i] && (!(aSet.data[i])))
                    return false;
            return true;
}
        public override string ToString()
{
            string s = "";
            for (int i = 0; i <= data.Count - 1; i++)
                if (data[i])
                    s += i + " ";
            return s;
}
}
    class Program
{

        static void Main(string[] args)
{
            //使用实现:
            //调用:
            BitArraySet BsetA = new BitArraySet();
            BitArraySet BsetB = new BitArraySet();
            ///A
            BsetA.Add(1);
            BsetA.Add(2);
            BsetA.Add(3);
            ///B
            BsetB.Add(2);
            BsetB.Add(3);
            BitArraySet BsetC = new BitArraySet();
            BsetC = BsetA.SetUnion(BsetB);
            Console.WriteLine();
            Console.WriteLine("A:" + BsetA.ToString());
            Console.WriteLine("B:" + BsetB.ToString());
            Console.WriteLine("A Union B:" + BsetC.ToString());
            BsetC = BsetA.SetIntersection(BsetB);
            Console.WriteLine("A Intersection B:" + BsetC.ToString());
            BsetC = BsetA.SetDifference(BsetB);
            Console.WriteLine("A Difference B:" + BsetC.ToString());
            bool flag = BsetB.IsSubset(BsetA);
            if (flag)
                Console.WriteLine("b is a subset of a");
            else
                Console.WriteLine("b is not a subset of a");
            ////A:1 2 3 
            ////B:2 3 
            ////A Union B:1 2 3 
            ////A Intersection B:2 3  
            ////A Difference B:1  
            ////b is a subset of a
            Console.ReadLine();
}
}
}

参考:
https://msdn.microsoft.com/zh-cn/library/7y3x785f 
http://blog.csdn.net/maths_bai/article/details/8046590#t16 
http://blog.csdn.net/maths_bai/article/details/8046493#_Toc337377703 
http://outofmemory.cn/csharp/tutorial/csharp-collection.html