《数据结构与算法C#语言描述》笔记13_集合

来源:互联网 发布:淘宝男装好做吗 编辑:程序博客网 时间:2024/05/13 00:49

十三.集合

集合的定义

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

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

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

集合的操作

联合:两个集合的并集

交叉:两个集合的交集

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

集合的属性(性质)

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

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

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

吸收定律

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

德摩根定律

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

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

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

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

内部实现

HashSet类:

 

    public class HashCSet

    {

        private Hashtabledata;

        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 (inti = 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 { returndata.Count; }

        }

        ///<summary>

        ///联合

        ///</summary>

        ///<param name="aSet"></param>

        ///<returns></returns>

        public HashCSetUnion(HashCSet aSet)

        {

           HashCSet tempSet = new HashCSet();

           foreach (ObjecthashObjectin data.Keys)

               tempSet.Add(this.data[hashObject]);

           foreach (ObjecthashObjectin aSet.data.Keys)

               if (!(this.data.ContainsKey(hashObject)))

                   tempSet.Add(aSet.data[hashObject]);

           return tempSet;

        }

        ///<summary>

        ///返回一个和指定集合交叉的集合

        ///</summary>

        ///<param name="aSet"></param>

        ///<returns></returns>

        public HashCSetIntersection(HashCSet aSet)

        {

           HashCSet tempSet = new HashCSet();

           foreach (ObjecthashObjectin 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 (Objectkeyinthis.data.Keys)

                    if(!(aSet.data.Contains(key)))

                        return false;

           return true;

        }

        ///<summary>

        ///差异。返回一个和指定集合的差异集合

        ///</summary>

        ///<param name="aSet"></param>

        ///<returns></returns>

        public HashCSetDifference(HashCSet aSet)

        {

           HashCSet tempSet = new HashCSet();

           foreach (ObjecthashObjectin data.Keys)

               if (!(aSet.data.Contains(hashObject)))

                   tempSet.Add(data[hashObject]);

           return tempSet;

        }

        public override string ToString()

        {

           string s="";

           foreach (Objectkeyin data.Keys)

               s += data[key] + " ";

           return s;

        }

}

使用实现

调用:

           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

 

 

用BitArray实现一个Set集合类

当集合存储的数据是整数时,使用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补集的交集为空)

内部实现

BitArraySet类:

    public class BitArraySet

    {

        private BitArraydata;

        public BitArraySet()

        {

           data = new BitArray(5);

        }

        public void Add(int item)

        {

           data[item] = true;

        }

        public bool IsMember(int item)

        {

            returndata[item];

        }

        public void Remove(int item)

        {

           data[item] = false;

        }

        public BitArraySetUnion(BitArraySet aSet)

        {

           BitArraySet tempSet =newBitArraySet();

           for (inti = 0; i <= data.Count - 1; i++)

               tempSet.data[i] = (this.data[i] ||

               aSet.data[i]);

           return tempSet;

        }

        public BitArraySetIntersection(BitArraySet aSet)

        {

           BitArraySet tempSet =newBitArraySet();

           for (inti = 0; i <= data.Count - 1; i++)

               tempSet.data[i] = (this.data[i]&&

               aSet.data[i]);

           return tempSet;

        }

        public BitArraySetDifference(BitArraySet aSet)

        {

           BitArraySet tempSet =newBitArraySet();

           for (inti = 0; i <= data.Count - 1; i++)

               tempSet.data[i] = (this.data[i]&&

               (!(aSet.data[i])));

           return tempSet;

        }

        public bool IsSubset(BitArraySetaSet)

        {

           BitArraySet tempSet =newBitArraySet();

           for (inti = 0; i <= data.Count - 1; i++)

               if (this.data[i]&& (!(aSet.data[i])))

                    returnfalse;

            return true;

        }

        public override string ToString()

        {

           string s = "";

           for (inti = 0; i <= data.Count - 1; i++)

               if (data[i])

                    s += i+" ";

           return s;

        }

    }

 

使用实现

           BitArraySet BsetA =newBitArraySet();

           BitArraySet BsetB =newBitArraySet();

           ///A

           BsetA.Add(1);

           BsetA.Add(2);

           BsetA.Add(3);

           ///B

           BsetB.Add(2);

           BsetB.Add(3);

           BitArraySet BsetC =newBitArraySet();

           BsetC = BsetA.Union(BsetB);

           Console.WriteLine();

           Console.WriteLine("A:" + BsetA.ToString());

           Console.WriteLine("B:" + BsetB.ToString());

           Console.WriteLine("A Union B:" + BsetC.ToString());

           BsetC = BsetA.Intersection(BsetB);

           Console.WriteLine("A Intersection B:" + BsetC.ToString());

           BsetC = BsetA.Difference(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

 

 

HashSet<T>类和SortedSet<T>类

HashSet<T>类是.Net Framework3.5中新增。表示值的集合。SortedSet<T>类是.Net Framework4.0中新增,表示按排序顺序保持的对象的集合。两者都实现了ISet<T>接口。

ISet<T>接口提供的方法可以创建合集、交集,或者给出一个集是另一个集的超集或子集的信息。

namespace System.Collections.Generic

 

    public class HashSet<T> : ISerializable,IDeserializationCallback,ISet<T>,ICollection<T>,IEnumerable<T>,IEnumerable

 

    public class SortedSet<T> : ISet<T>,ICollection<T>, IEnumerable<T>, ICollection,IEnumerable,ISerializable,IDeserializationCallback

 

 

 

HashSet<T>类

构造器

HashSet<T>()

初始化HashSet<T> 类的一个新实例,该实例为空并使用集类型的默认相等比较器。

HashSet<T>(IEnumerable<T>)

初始化HashSet<T> 类的一个新实例,该实例使用集类型的默认相等比较器,包含从指定的集合复制的元素,并且有足够的容量容纳所复制的这些元素。

HashSet<T>(IEqualityComparer<T>)

初始化HashSet<T> 类的一个新实例,该实例为空并使用集类型的指定相等比较器。

HashSet<T>(IEnumerable<T>,IEqualityComparer<T>)

初始化HashSet<T> 类的一个新实例,该实例使用集类型的指定相等比较器,包含从指定的集合复制的元素,并且有足够的容量容纳所复制的这些元素。

HashSet<T>(SerializationInfo,StreamingContext)

用序列化数据初始化 HashSet<T> 类的新实例。

 

主要属性和方法

S1是S2的超集,则S2是S1的真子集

 

Count属性:获取集中包含的元素数。

 

Add:将指定的元素添加到集中。

Clear:从HashSet<T> 对象中移除所有元素。

Contains:确定HashSet<T> 对象是否包含指定的元素。

CopyTo(T[]):将HashSet<T> 对象的元素复制到数组中。

CopyTo(T[], Int32):从指定数组索引处开始,将 HashSet<T> 对象的元素复制到数组中。

CopyTo(T[], Int32, Int32):从指定数组索引处开始,将 HashSet<T> 对象的指定数目的元素复制到数组中。

CreateSetComparer:返回IEqualityComparer 对象,该对象可用于对HashSet<T> 对象进行相等测试。

ExceptWith:从当前HashSet<T> 对象中移除指定集合中的所有元素。

IntersectWith:修改当前的HashSet<T> 对象,以仅包含该对象和指定集合中存在的元素。

IsProperSubsetOf:确定HashSet<T> 对象是否为指定集合的真子集。

IsProperSupersetOf:确定HashSet<T> 对象是否为指定集合的真超集。

IsSubsetOf:确定HashSet<T> 对象是否为指定集合的子集。

IsSupersetOf:确定HashSet<T> 对象是否为指定集合的超集。

Remove:从HashSet<T> 对象中移除指定的元素。

RemoveWhere:从HashSet<T> 集合中移除与指定的谓词所定义的条件相匹配的所有元素。

SetEquals:确定HashSet<T> 对象与指定的集合中是否包含相同的元素。

SymmetricExceptWith:修改当前的HashSet<T> 对象,以仅包含该对象或指定集合中存在的元素(但不可包含同时在该对象和指定集合中都存在的元素)。

TrimExcess:将HashSet<T> 对象的容量设置为它所包含的元素的实际个数,向上舍入为接近的特定于实现的值。

UnionWith:修改当前的 HashSet<T> 对象,以包含该对象本身、指定集合中存在的所有元素或两者。

 

实例

            HashSet<int>evenNumbers =newHashSet<int>();

            HashSet<int>oddNumbers =newHashSet<int>();

 

            for (int i = 0; i< 5; i++)

            {

                evenNumbers.Add(i* 2);

               oddNumbers.Add((i * 2) + 1);

 

            }

 

            Console.Write("evenNumberscontains {0} elements: ", evenNumbers.Count);

           DisplaySet(evenNumbers);

            ///evenNumbers contains 5elements: { 0 2 4 6 8 }

           

            Console.Write("oddNumberscontains {0} elements: ", oddNumbers.Count);

           DisplaySet(oddNumbers);

            ///oddNumbers contains 5elements: { 1 3 5 7 9 }

 

            HashSet<int>numbers =newHashSet<int>(evenNumbers);

           numbers.UnionWith(oddNumbers);//1.联合,并集

            Console.WriteLine("numbers(evenNumbers)UnionWith oddNumbers...change numbers");

            Console.Write("numberscontains {0} elements: ", numbers.Count);

            DisplaySet(numbers);

            ///numbers(evenNumbers)UnionWith oddNumbers...change numbers

            ///numbers contains 10elements: { 0 2 4 6 8 1 3 5 7 9 }

 

            HashSet<int>numbers0 =newHashSet<int>(numbers);

           numbers0.Remove(5);

           numbers0.Remove(6);

            Console.Write("numbers0contains {0} elements: ", numbers0.Count);

           DisplaySet(numbers0);

            ///numbers0 contains 8elements: { 0 2 4 8 1 3 7 9 }

           

            HashSet<int>numbers1 =newHashSet<int>(numbers0);

           numbers1.ExceptWith(oddNumbers);//2.移除,差异,相对另外一个集合的补集

            Console.WriteLine("numbers1(numbers0)ExceptWith oddNumbers...change numbers1");

            Console.Write("numbers1contains {0} elements: ", numbers1.Count);

           DisplaySet(numbers1);

            ///numbers1(numbers0)ExceptWith oddNumbers...change numbers1

            ///numbers1 contains 4elements: { 0 2 4 8 }

 

 

            HashSet<int>numbers2 =newHashSet<int>(numbers); ;

           numbers2.IntersectWith(oddNumbers);//3.交叉,交集

            Console.WriteLine("numbers2(numbers)IntersectWith oddNumbers...return numbers2");

            Console.Write("numbers2contains {0} elements: ", numbers2.Count);

           DisplaySet(numbers2);

            ///numbers2(numbers)IntersectWith oddNumbers...change numbers2

            ///numbers2 contains 5elements: { 1 3 5 7 9 }

 

 

SortedSet<T>类

构造器

SortedSet<T>()

初始化SortedSet<T> 类的新实例。

SortedSet<T>(IComparer<T>)

初始化使用指定比较器的 SortedSet<T> 类的新实例。

SortedSet<T>(IEnumerable<T>)

初始化SortedSet<T> 类的新实例,该实例包含从指定的可枚举集合中复制的元素。

SortedSet<T>(IEnumerable<T>,IComparer<T>)

初始化SortedSet<T> 类的新实例,该实例包含从指定的可枚举集合中复制的元素并使用指定的比较器。

SortedSet<T>(SerializationInfo,StreamingContext)

初始化包含序列化数据的 SortedSet<T> 类的新实例。

主要属性和方法

Count: 获取 SortedSet<T> 中元素的数目。

Max:按照比较器的定义,获取SortedSet<T> 中的最大值。

Min:按照比较器的定义,获取SortedSet<T> 中的最小值。

 

Add:向集内添加元素,并返回一个指示是否已成功添加元素的值。

Clear:从集内移除所有元素。

Contains:确定集是否包含特定元素。

CopyTo(T[]):将整个SortedSet<T> 复制到兼容的一维数组中(从目标数组的开头开始复制)。

CopyTo(T[],Int32):将整个 SortedSet<T> 复制到兼容的一维目标数组(从指定的数组索引处开始复制)。

CopyTo(T[],Int32, Int32):将指定数量的元素从 SortedSet<T> 复制到兼容的一维数组中(从指定的数组索引处开始复制)。

ExceptWith:从当前SortedSet<T> 对象中移除指定集合中的所有元素。

IntersectWith:修改当前的SortedSet<T> 对象,使该对象仅包含指定集合中也存在的元素。

IsProperSubsetOf:确定SortedSet<T> 对象是否为指定集合的真子集。

IsProperSupersetOf:确定SortedSet<T> 对象是否为指定集合的真超集。

IsSubsetOf:确定SortedSet<T> 对象是否为指定集合的子集。

IsSupersetOf:确定SortedSet<T> 对象是否为指定集合的超集。

Remove:从SortedSet<T> 中移除指定的项。

RemoveWhere:从SortedSet<T> 中移除与指定的谓词所定义的条件相匹配的所有元素。

Reverse:返回一个IEnumerable<T>,它按相反的顺序循环访问 SortedSet<T>。

SetEquals:确定当前的SortedSet<T> 对象与指定的集合中是否包含相同的元素。

SymmetricExceptWith:修改当前的SortedSet<T> 对象,使该对象仅包含当前对象或指定集合中存在的元素(但不可包含两者共有的元素)。

UnionWith:修改当前SortedSet<T> 对象,使其包含存在于当前对象或指定集合的所有元素。

 

实例

            SortedSet<int>ssi =new System.Collections.Generic.SortedSet<int>();

           ssi.Add(3);

           ssi.Add(1);

           ssi.Add(42);

           ssi.Add(2);

           DisplaySSet<int>(ssi);

            ///{ 1 2 3 42 }

            SortedSet<string>sss =new System.Collections.Generic.SortedSet<string>();

           sss.Add("Mike");

           sss.Add("John");

           sss.Add("Ben");

           sss.Add("Terry");

           sss.Add("null");

           DisplaySSet<string>(sss);

            ///{ Ben John Mike nullTerry }


原创粉丝点击