zoukankan      html  css  js  c++  java
  • 14.集合

    1.System.Collections命名空间中的几个接口

    1)IEnumerable可迭代集合中的项;

    2)ICollection(继承于IEnumerable)可以获取集合中项的个数,并把项复制到一个简单的数组中;

    3)IList(继承于IEnumerable和ICollection)提供了集合的项列表,允许访问这些项,并提供一些与项相关的基本功能;

    4)IDictionary(继承于IEnumerable和ICollection)类似IList,但提供了通过键值(而不是索引)访问项的列表;

    以上几个接口提供了基本的集合功能。System.Array类实现了IEnumerable、ICollection和IList接口,但不支持IList的一些更高级的功能,它表示大小固定的项列表。C#中的数组是System.Array类的实例。

    2.使用数组实现扑克牌集合

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Deck d = new Deck();
                for (int i = 0; i < 52; i++)
                {
                    Console.Write(d.GetCard(i));
                    
                }
                Console.WriteLine();
                Console.WriteLine();
                d.Shuffle();
    
                for (int i = 0; i < 52; i++)
                {
                    Console.Write(d.GetCard(i));
                    
                }
                d.GetCard(53);
                Console.WriteLine();
                Console.WriteLine();
                    Console.ReadLine();
            }
        }
    
       
    
        class Card
        {
            private readonly Suit suit;
            private readonly Rank rank;
    
            public Card(Suit suit,Rank rank)
            {
                this.suit = suit;
                this.rank = rank;
            }
    
            public override string ToString()
            {
                return "The "+rank .ToString()+" of "+ suit.ToString()+" s";
            }
        }
    
        /// <summary>
        /// 使用数组实现集合Deck,缺点是集合的大小是固定的
        /// </summary>
        class Deck {
            private Card[] Cars;
    
            public Deck()
            {
                Cars = new Card[52];
                for (int suitVal = 0; suitVal < 4; suitVal++)
                {
                    for (int rankVal = 1; rankVal <= 13; rankVal++)
                    {
                        Cars[suitVal * 13 + rankVal - 1] = new Card((Suit)suitVal, (Rank)rankVal);
                    }
                }
            }
    
            public Card GetCard(int cardNum)
            {
                if (cardNum >= 0 && cardNum <= 51)
                    return Cars[cardNum];
                else
                    throw new ArgumentOutOfRangeException("cardNum", cardNum, "Value must between 0 and 51.");
            }
    
            public void Shuffle()
            {
                Random sourceGen = new Random();
                Card[] newCards = new Card[52];
                bool[] assigned = new bool[52];
                for (int i = 0; i < 52; i++)
                {
                    int destCard = 0;
                    bool foundCard = false;
                    while (!foundCard)
                    {
                        destCard = sourceGen.Next(52);
                        if (assigned[destCard] == false)
                            foundCard = true;
                    }
                    assigned[destCard] = true;
                    Cars[destCard]=newCards[i];
                }
                newCards.CopyTo(Cars ,0);
            }
    
    
        }
    
        public enum Suit
        { 
            Club,//梅花
            Diamond,//方块
            Heart,//红桃
            Spade//黑桃
    
        }
    
        public enum Rank
        { 
            Ace=1,//幺点
            Deuce,//两点
            Three,
            Four,
            Fine,
            Six,
            Seven,
            Eight,
            Nine,
            Ten,
            Jack,
            Queen,
            King
    
        }
    }
    View Code

    数组实现集合的缺点:集合大小是固定的,不能改变。

    3.使用System.Collections.ArrayList实现扑克牌集合

    ArrayList也实现了IEnumerable、ICollection和IList接口,但比System.Array更复杂,和System.Array相比,它的大小是不固定的。

     abstract class Animal
        {
            protected string name;
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
            public Animal()
            {
                name = "The animal has no name.";
            }
    
            public Animal(string newName)
            {
                name = newName;
            }
    
            public void Feed()
            {
                Console.WriteLine("{0}has been fed.", name);
            }
        }
    
        class Cow : Animal
        {
            public void Milk()
            {
                Console.WriteLine("{0}has been milked.", name);
            }
    
            public Cow(string newName)
                : base(newName)
            {
    
            }
        }
    
        class Chicken : Animal {
            public void LagEgg()
            {
                Console.WriteLine("{0}has lag en egg.", name);
            }
    
            public Chicken(string newName)
                : base(newName)
            { 
                
            }
        }
    View Code
    class Program
        {
    
            static void Main(string[] args)
            {
                Animal[] animalArray = new Animal[2];
                Cow myCow1 = new Cow("Deirdre");
                animalArray[0] = myCow1;
                animalArray[1] = new Chicken("Ken");
    
                foreach (Animal myAnimal in animalArray)
                {
                    Console.WriteLine("New {0} object added to collection,Name= {1}",myAnimal.ToString(),myAnimal.Name);
                }
    
                Console.WriteLine("Array collection contains {0} objects", animalArray.Length);
    
                animalArray[0].Feed();
                ((Chicken)animalArray[1]).LagEgg();
    
                ArrayList animalArrayList = new ArrayList();
                Cow myCow2 = new Cow("Hayley");
                animalArrayList.Add(myCow2);
                animalArrayList.Add(new Chicken("Roy"));
    
                foreach (Animal myAnimal in animalArrayList)
                {
                    Console.WriteLine("New {0} object added to ArrayList collection,Name = {1}", myAnimal.ToString(), myAnimal.Name);
                }
                Console.WriteLine("ArrayList collection contains {0} objects", animalArrayList.Count);
    
                ((Animal)animalArrayList[0]).Feed();
                ((Chicken)(animalArrayList[1])).LagEgg();
    
                animalArrayList.RemoveAt(0);
                animalArrayList.AddRange(animalArray);//后加入的排在前面
                ((Cow)animalArrayList[0]).Milk();
    
                Console.WriteLine("The animal called {0} is at index {1}", myCow1.Name, animalArrayList.IndexOf(myCow1));
                myCow1.Name = "Janice";
                Console.WriteLine("The animal is now called {0}", ((Animal)animalArrayList[0]).Name);
    
                Console.ReadLine();
            }
           
        }
    View Code

    数组和ArrayList的比较:

    数组需要用固定大小的常量值来初始化,初始化后大小是固定的,ArrayList有两个构造函数,另一个构造函数可以设置列变的初始大小,如果集合的项个数超过了这个值就增加一倍。ArrayList的大小是变化的。

    Animal[] animalArray = new Animal[2];
    
    ArrayList animalArrayList = new ArrayList();

    数组初始化之后,它的项并没有初始化,需要按照下标给每项分别初始化。ArrayList不能像数组那样初始化,因为他的项还没有添加,需要用Add方法才会添加一个新项,并为这个新项分配内存空间。

                Cow myCow1 = new Cow("Deirdre");
                animalArray[0] = myCow1;
                animalArray[1] = new Chicken("Ken");    
    
                Cow myCow2 = new Cow("Hayley");
                animalArrayList.Add(myCow2);
                animalArrayList.Add(new Chicken("Roy"));

    数组个数使用Length属性,ArrayList使用Count属性

    数组是强类型集合,ArrayList是System.Object的集合,使用时需要把对象强制转换为对应的类型

                animalArray[0].Feed();
                ((Chicken)animalArray[1]).LagEgg();
    
                ((Animal)animalArrayList[0]).Feed();
                ((Chicken)(animalArrayList[1])).LagEgg();

    ArrayList功能更多,比如RemoveAt,Remove,还可以使用AddRange方法把支持ICollection接口的对象加到集合中

    4.使用CollectionBase建立集合

    定制集合可以创建强类型化的集合,可以完全自己写代码创建集合,也可以通过继承现有类创建集合,一般通过继承集合底层的类创建集合。

    CollectionBase类实现了IEnumerable、ICollection和IList接口,但是只提供了一些实现代码,比如IList的Clear()和RemoveAt,以及ICollection的Count属性,需要用到其他功能需要自己实现。

    abstract class Animal
        {
            protected string name;
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
            public Animal()
            {
                name = "The animal has no name.";
            }
    
            public Animal(string newName)
            {
                name = newName;
            }
    
            public void Feed()
            {
                Console.WriteLine("{0}has been fed.", name);
            }
        }
    
    class Animals : CollectionBase
        { 
            public void Add(Animal newAnimal)
            {
                List.Add(newAnimal);
            }
    
            public void Remove(Animal oldAnimal)
            {
                List.Remove(oldAnimal);
            }
    
            /// <summary>
            /// 索引符只能访问已添加的项,超过Count-1会产生超出索引异常
            /// </summary>
            /// <param name="animalIndex"></param>
            /// <returns></returns>
            public Animal this[int animalIndex]
            {
                get { return (Animal)List[animalIndex]; }
                set { List[animalIndex] = value; }
            }
        }
    View Code
        class Program
        {
    
            static void Main(string[] args)
            {
                Animals animalCollection = new Animals();
                Cow myCow1 = new Cow("Deirdre");
                animalCollection.Add(myCow1);
                animalCollection.Add(new Chicken("Ken"));
    
                foreach (Animal myAnimal in animalCollection)
                {
                    Console.WriteLine("New {0} object added to collection,Name= {1}",myAnimal.ToString(),myAnimal.Name);
                }
    
                Console.WriteLine(animalCollection[1].Name);
                Console.ReadLine();
            }
           
        }

    5.使用DictionaryBase创建集合

    DictionaryBase可以创建键值对集合,通过关键字访问项。DictionaryBase实现了IDictionary,IEnumerable、ICollection接口。和CollectionBase一样它提供了部分功能,如Clear()、和Count,但没有RemoveAt()因为它是IList接口上的功能,但是IDictionary接口有Remove功能,可以使用这个实现Remove功能。

    abstract class Animal
        {
            protected string name;
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
            public Animal()
            {
                name = "The animal has no name.";
            }
    
            public Animal(string newName)
            {
                name = newName;
            }
    
            public void Feed()
            {
                Console.WriteLine("{0}has been fed.", name);
            }
        }
    
        class Animals :DictionaryBase
        { 
            public void Add(string newId, Animal newAnimal)
            {
                Dictionary.Add(newId, newAnimal);
            }
    
            public void Remove(string oldId,Animal oldAnimal)
            {
                Dictionary.Remove(oldId);
            }
    
            /// <summary>
            /// 索引符只能访问已添加的项,超过Count-1会产生超出索引异常
            /// </summary>
            /// <param name="animalIndex"></param>
            /// <returns></returns>
            public Animal this[string key]
            {
                get { return (Animal)Dictionary[key]; }
                set { Dictionary[key] = value; }
            }
        }
    
        class Program
        {
    
            static void Main(string[] args)
            {
                Animals animalCollection = new Animals();
                Cow myCow1 = new Cow("Deirdre");
                animalCollection.Add("111",myCow1);
                animalCollection.Add("222",new Chicken("Ken"));
    
                foreach (DictionaryEntry d in animalCollection)
                {
                    Console.WriteLine("New {0} object added to collection,Name= {1}",d.Value.ToString(),((Animal)d.Value).Name);
                }
                Console.WriteLine(animalCollection["111"].Name);
                Console.ReadLine();
            }
           
        }
    View Code

    6.迭代器

    我们知道IEnumerable接口是负责实现foreach循环的,假如循环的方式并不是我们想要的就需要重写循环方式,但是重写循环方式并不是很简单。我们看下在foreach循环中究竟干了什么。

    在foreach循环中,迭代集合collectionObject的过程如下:

    1)调用collectionObject.GetEnumerator(),返回一个IEnumerator引用。这个可以从IEnumerable接口的实现代码获取,但这是可选的,可以在实现IEnumerable接口的情况下创建一个GetEnumerator()用于循环(即下面说的迭代器);

    2)调用IEnumerator的MoveNext方法;

    3)如果MoveNext方法返回true,调用IEnumerator的Current获取对象的一个引用,用于foreach循环;

    4)重复上面两步直到循环结束。

    由此可以看出重写foreach循环方式需要重写几个方法(GetEnumerator(),MoveNext()等),跟踪索引,维护Current属性,以及执行其他一些操作,这需要做很多工作。比较简单的替代方法是使用迭代器。使用迭代器可以有效的在后台生成许多代码,不用我们去实现那么多。

    迭代器是一个代码块,它按顺序提供了要在foreach循环中用到的值

        class Program
        {
    
            static void Main(string[] args)
            {
                foreach(string s in SimpleList())
                {
                    Console.WriteLine(s);
                }
                Console.ReadLine();
            }
    
            static IEnumerable SimpleList()
            {
                yield return "string 1";
                yield return "string 2";
                yield return "string 3";
            }
           
        }

    以上是一个迭代器的例子,在迭代器中使用yield关键字提供在foreach循环中用到的值。迭代器的返回类型有IEnumerable和IEnumerator两种类型,这两个类型使用的场合是:

    1)如果要迭代一个类可以使用GetEnumerator方法,其返回类型是IEnumerator;

    2) 如果要迭代一个类成员,比如一个方法,使用IEnumerable。

    使用迭代器重写Animals foreach循环

    abstract class Animal
        {
            protected string name;
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
            public Animal()
            {
                name = "The animal has no name.";
            }
    
            public Animal(string newName)
            {
                name = newName;
            }
    
            public void Feed()
            {
                Console.WriteLine("{0}has been fed.", name);
            }
        }
    
        class Cow : Animal
        {
            public void Milk()
            {
                Console.WriteLine("{0}has been milked.", name);
            }
    
            public Cow(string newName)
                : base(newName)
            {
    
            }
        }
    
        class Chicken : Animal {
            public void LagEgg()
            {
                Console.WriteLine("{0}has lag en egg.", name);
            }
    
            public Chicken(string newName)
                : base(newName)
            { 
                
            }
        }
    
        class Animals :DictionaryBase
        { 
            public void Add(string newId, Animal newAnimal)
            {
                Dictionary.Add(newId, newAnimal);
            }
    
            public void Remove(string oldId,Animal oldAnimal)
            {
                Dictionary.Remove(oldId);
            }
    
            /// <summary>
            /// 索引符只能访问已添加的项,超过Count-1会产生超出索引异常
            /// </summary>
            /// <param name="animalIndex"></param>
            /// <returns></returns>
            public Animal this[string key]
            {
                get { return (Animal)Dictionary[key]; }
                set { Dictionary[key] = value; }
            }
    
            public new IEnumerator GetEnumerator()
            {
                foreach (DictionaryEntry d in Dictionary)
                {
                    yield return (Animal)d.Value;
                }
            }
    
        class Program
        {
    
            static void Main(string[] args)
            {
                Animals animals = new Animals();
                animals.Add("111", new Cow("myCow1"));
                animals.Add("222", new Chicken("myChicken1"));
    
                foreach (Animal a in animals)
                {
                    a.Feed();
                }
                Console.ReadLine();
            }
        }
    View Code

    属性块用做迭代器

    class People:DictionaryBase
        {
            public void Add(string name, Person p)
            {
                this.Dictionary.Add(name, p);
            }
    
            public void Remove(string name)
            {
                this.Dictionary.Remove(name);
            }
    
            public Person this[string name]
            {
                get { return (Person)this.Dictionary[name]; }
                set { this.Dictionary[name] = value; }
            }
    
            public new IEnumerator GetEnumerator()
            {
                foreach (object d in Dictionary.Values)
                {
                    yield return (Person)d;
                }
    
            }
    
            public IEnumerable Ages
            {
                get {
                    foreach (object d in Dictionary.Values)
                    {
                        yield return ((Person)d).Age;
                    }
                }
            }
       
        }
    
        public class Person:IComparable
        {
            public string Name { get; set; }
            public int Age { get; set; }
    
            [System.Xml.Serialization.XmlElementAttribute("Books")]
            public Books Books { get; set; }
    
    
            public Person(string name, int age)
            {
                Name = name;
                Age = age;
            }
    
            public int CompareTo(object obj)
            {
                return this.Age-((Person)obj).Age;
            }
        }
  • 相关阅读:
    (双指针 二分) leetcode 167. Two Sum II
    (双指针) leetcode 485. Max Consecutive Ones
    (双指针) leetcode 27. Remove Element
    (String) leetcode 67. Add Binary
    (数组) leetcode 66. Plus One
    (N叉树 BFS) leetcode429. N-ary Tree Level Order Traversal
    (N叉树 递归) leetcode 590. N-ary Tree Postorder Traversal
    (N叉树 递归) leetcode589. N-ary Tree Preorder Traversal
    (N叉树 DFS 递归 BFS) leetcode 559. Maximum Depth of N-ary Tree
    (BST 递归) leetcode98. Validate Binary Search Tree
  • 原文地址:https://www.cnblogs.com/lidaying5/p/10539570.html
Copyright © 2011-2022 走看看