当前位置: 首页 > news >正文

C#基础--集合

文章目录

  • 集合
    • 集合接口和类型
    • 列表
      • 创建列表
        • 集合初始值设定项
      • 添加元素
      • 插入元素
      • 访问元素
      • 删除元素
      • 搜索元素
      • 排序
    • 队列
    • 链表
    • 有序列表
    • 字典
      • 字典初始化器
      • 键的类型
      • Lookup 类
      • 有序字典
    • 性能

集合

集合接口和类型

大多数集合类都可在System.Collections和System.Collections.Generic名称空间中找到。泛型集合类位于
System.Collections.Generic名称空间中;专用于特定类型的集合类位于System.Collections. Specialized名称空间中。 线程安全的集合类位于System.Collections.Concurrent名称空间中。不可变的集合类在System.Collections.Immutable 名称空间中。当然,组合集合类还有其他方式。集合可以根据集合类实现的接口组合为列表、集合和字典。
在这里插入图片描述

列表

.NET Framework 为动态列表提供了泛型类 List。这个类实现了 IList、ICollection、 IEnumerable、IList、 ICollection和 IEnumerable接口。

public class Racer : IComparable<Racer>, IFormattable
{
    public Racer(int id, string firstName, string lastName, string country, int wins)
    {
        Id = id;
        FirstName = firstName;
        LastName = lastName;
        Country = country;
        Wins = wins;
    }

    public Racer(int id, string firstName, string lastName, string country)
      : this(id, firstName, lastName, country, wins: 0)
    { }

    public int Id { get; }
    public string FirstName { get; }
    public string LastName { get; }
    public string Country { get; }
    public int Wins { get; set; }

    public override string ToString() => $"{FirstName} {LastName}";


    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (format == null) format = "N";
        switch (format.ToUpper())
        {
            case null:
            case "N": // name
                return ToString();
            case "F": // first name
                return FirstName;
            case "L": // last name
                return LastName;
            case "W": // Wins
                return $"{ToString()}, Wins: {Wins}";
            case "C": // Country
                return $"{ToString()}, Country: {Country}";
            case "A": // All
                return $"{ToString()}, Country: {Country} Wins: {Wins}";
            default:
                throw new FormatException(String.Format(formatProvider,
                      "Format {0} is not supported", format));
        }
    }

    public string ToString(string format) => ToString(format, null);

    public int CompareTo(Racer other)
    {
        int compare = LastName?.CompareTo(other?.LastName) ?? -1;
        if (compare == 0)
        {
            return FirstName?.CompareTo(other?.FirstName) ?? -1;
        }
        return compare;
    }
}

创建列表

使用默认的构造函数创建一个空列表。

var intList = new List<int>(); 
var racers = new List<Racer>();

如果列表的容量改变了,整个集合就要重新分配到一个新的内存块中。在型类的实现代码中,
使用了一个T类型的数组。通过重新分配内存,创建一个新数组,Array.CopyO方法将旧数组中的元素复制到新
数组中。为节省时间,如果事先知道列表中元素的个数,就可以用构造函数定义其容量。

List<int> intList = new List<int>(10);

使用Capacity属性可以获取和设置集合的容量。

intList.Capacity = 20;

容量与集合中元素的个数不同。集合中的元素个数可以用Count属性读取。当然,容量总是大于或等于元
素个数。只要不把元素添加到列表中,元素个数就是0。

Console.WriteLine(intList.Count);

如果己经将元素添加到列表中,且不希望添加更多的元素,就可以调用TrimExcessO方法,去除不需要的 容量。但是,因为重新定位需要时间,所以如果元素个数超过了容量的90%, TrimExcessO方法就什么也不做。

intList.TrimExcess();

集合初始值设定项

还可以使用集合初始值设定项给集合赋值。集合初始化器的语法类似于数组初始化器。使用
集合初始值设定项,可以在初始化集合时,在花括号中给集合赋值:

var intList = new List<int>()  {1, 2};
var stringList = new List<string>()  {   "one", "two" };

注意:
集合初始值设定项没有反映在已编译的程序集的IL代码中。编译器会把集合初始值设定项转换成对初始值 设定项列表中的每一项调用AddO方法。

添加元素

使用Add()方法可以给列表添加元素,如下所示。实例化的泛型类型定义了 Add()方法的参数类型:

var intList = new List<int>(); 
intList.Add(1);
intList.Add(2);
var stringList = new List<string>(); 
stringList.Add(*'oneM);
stringList.Add("two*');

把racers变量定义为List类型。使用new运算符创建相同类型的一个新对象。因为类List用具
体类Racer来实例化,所以现在只有Racer对象可以用Add()方法添加。

var graham = new Racer(7,  "Graham",   "Hill", "UK", 14);
var emerson = new Racer(13, "Emerson",   "Fittipaldi", "Brazil", 14);
var mario = new Racer(16, "Mario", "Andretti", "USA", 12);
var racers = new List<Racer>(20)  {graham, emerson, mario};
racers.Add(new Racer(24, "Michael", *'Schumacher"Germany**, 91)); 
racers.Add(new Racer(27, "Mika", "Hakkinen", "Finland", 20));

使用List类的AddRange()方法,可以一次给集合添加多个元素。因为AddRange()方法的参数是
IEnumerable类型的对象,所以也可以传递一个数组

racers.AddRange(new Racer[]  {
new Racer(14, "Niki", "Lauda", "Austria", 25), 
new Racer(21, "Alain", "Prost", "France", 51)});

注意:
集合初始值设定项只能在声明集合时使用。AddRange()方法则可以在初始化集合后调用。如果在创建集合 后动态获取数据,就需要调用AddRange()。

var racers = new List<Racer>( 
new Racer[]  {
new Racer(12, "Jochen”, "Rindt”,"Austria",   6), 
new Racer(22,"Ayrton", ”Senna”,"Brazil", 41)  });
 

插入元素

使用Insert()方法可以在指定位置插入元素

racers.Insert (3,  new Racer(6,  "Phil”,"Hill", "USA”,3));

方法InsertRange()提供了插入大量元素的功能,类似于前面的AddRange()方法。
如果索引集大于集合中的元素个数,就抛出ArgumentOutOfRangeException类型的异常。

访问元素

实现了 IList和 IList接口的所有类都提供了一个索引器,所以可以使用索引器,通过传递元素号来访问元素。第一个元素可以用索引值0来访问。指定racers[3],可以访问列表中的第4个元素:

Racer rl = racers[3];

注*:
可以通过索引访问的集合类有ArrayList、StringCollection和List。
因为List集合类实现了正IEnumerable接口,所以也可以使用foreach语句遍历集合中的元素

foreach (var r in racers)
{
    Console.WriteLine(r);
}

删除元素

删除元素时,可以利用索引,也可以传递要删除的元素。下面的代码把3传递给RemoveAt()方法,删除第4个元素

racers.RemoveAt(3);

也可以直接将Racer对象传送给Remove()方法,来删除这个元素。按索引删除比较快,因为必须在集合中 搜索要删除的元素。Remove()方法先在集合中搜索,用IndexOf()方法获取元素的索引,再使用该索引删除元素。

搜索元素

有不同的方式在集合中搜索元素。可以获得要查找的元素的索引,或者搜索元素本身。可以使用的方法有
IndexOf()、LastlndexOf()、Findlndex()> FindLastIndex()、Find()和 FindLast()。如果只检查元素是否存在,List 类就提供了 Exists()方法。
IndexOf()方法需要将一个对象作为参数,如果在集合中找到该元素,这个方法就返回该元素的索引。如果没 有找到该元素,就返回-1。IndexOf()方法使用正quatable接口来比较元素

ListSamples/Program.cs)int indexl = racers.IndexOf(mario);

使用IndexOf()方法,还可以指定不需要搜索整个集合,但必须指定从哪个索引开始搜索以及比较时要迭代 的元素个数。除了使用IndexOf()方法搜索指定的元素之外,还可以搜索有某个特性的元素,该特性可以用Findlndex() 方法来定义。Findlndex()方法需要一个Predicate类型的参数:

public int Findindex(Predicate<T> match);

Predicate型是一个委托,该委托返回一个布尔值,并且需要把类型T作为参数。如果返回true,就表示有一个匹配元素,并且找到了相应的元素。如果它返回false,就表示没有找到元素,搜索 将继续。

public delegate bool Predicate<T>(T obj);
public class FindCountry
{
    public FindCountry(string country) => _country = country;

    private readonly string _country;

    public bool FindCountryPredicate(Racer racer) => racer?.Country == _country;
}

排序

List^可以使用SortO方法对元素排序。Sort()方法使用快速排序算法,比较所有的元素,直到整个列表排好序为止。
Sort()方法使用了几个重载的方法。可以传递给它的参数有泛型委托Comparison和泛型接口
IComparer,以及一个范围值和泛型接口 IComparer。

public void List<T>.Sort();
public void List<T>.Sort(Comparison<T>);
public void List<T>.Sort(IComparer<T>);
public void List<T>.Sort(Int32, Int32, IComparer<T>);

只有集合中的元素实现了 IComparable接口,才能使用不带参数的Sort()方法。

public enum CompareType
{
    FirstName,
    LastName,
    Country,
    Wins
}

public class RacerComparer : IComparer<Racer>
{
    private CompareType _compareType;
    public RacerComparer(CompareType compareType) =>
      _compareType = compareType;

    public int Compare(Racer x, Racer y)
    {
        if (x == null && y == null) return 0;
        if (x == null) return -1;
        if (y == null) return 1;

        int result;
        switch (_compareType)
        {
            case CompareType.FirstName:
                result = string.Compare(x.FirstName, y.FirstName);
                break;
            case CompareType.LastName:
                result = string.Compare(x.LastName, y.LastName);
                break;
            case CompareType.Country:
                result = string.Compare(x.Country, y.Country);
                if (result == 0)
                {
                    result = string.Compare(x.LastName, y.LastName);
                }
                break;
            case CompareType.Wins:
                result = x.Wins.CompareTo(y.Wins);
                break;
            default:
                throw new ArgumentException("Invalid Compare Type");
        }
        return result;
    }
}

队列

队列是其元素以先进先出(Firstln, FirstOut, FIFO)的方式来处理的集合。先放入队列中的元素会先读取。队 列的例子有在机场排的队列、人力资源部中等待处理求职信的队列和打印队列中等待处理的打印任务,以及按 循环方式等待CPU处理的线程。另外,.还常常有元素根据其优先级来处理的队列。

队列使用System.Collections.Generic名称空间中的泛型类Queue实现。在内部,Queue类使用T类 型的数组,这类似于List类型。它实现ICollection和IEnumerable ,但没有实现ICollection接口, 因为这个接口定义的Add()和Remove()方法不能用于队列。

  • 因为Queue类没有实现IList接口,所以不能用索引器访问队列。
  • 队列只允许在队列中添加元素,

该元素会放在队列的尾部(使用Enqueue()方法),从队列的头部获取元素(使用Dequeue()方法)。
在这里插入图片描述
在这里插入图片描述

public class Document
{
    public Document(string title, string content)
    {
        Title = title;
        Content = content;
    }

    public string Title { get; }
    public string Content { get; }
}

public class DocumentManager
{
    private readonly object _syncQueue = new object();

    private readonly Queue<Document> _documentQueue = new Queue<Document>();

    public void AddDocument(Document doc)
    {
        lock (_syncQueue)
        {
            _documentQueue.Enqueue(doc);
        }
    }

    public Document GetDocument()
    {
        Document doc = null;
        lock (_syncQueue)
        {
            doc = _documentQueue.Dequeue();
        }
        return doc;
    }

    public bool IsDocumentAvailable => _documentQueue.Count > 0;
}

public class ProcessDocuments
{
    public static Task StartAsync(DocumentManager dm) =>
        Task.Run(new ProcessDocuments(dm).Run);

    protected ProcessDocuments(DocumentManager dm) =>
        _documentManager = dm ?? throw new ArgumentNullException(nameof(dm));

    private DocumentManager _documentManager;

    protected async Task Run()
    {
        while (true)
        {
            if (_documentManager.IsDocumentAvailable)
            {
                Document doc = _documentManager.GetDocument();
                Console.WriteLine($"Processing document {doc.Title}");
            }
            await Task.Delay(new Random().Next(20));
        }
    }
}

class Program
{
    static async Task Main()
    {
        var dm = new DocumentManager();

        Task processDocuments = ProcessDocuments.StartAsync(dm);

        for (int i = 0; i < 1000; i++)
        {
            var doc = new Document($"Doc {i}", "content");
            dm.AddDocument(doc);
            Console.WriteLine($"Added document {doc.Title}");
            await Task.Delay(new Random().Next(20));
        }
        await processDocuments;

        Console.ReadLine();
    }
}

栈是与队列非常类似的另一个容器,只是要使用不同的方法访问栈。最后添加到栈中的元素会最先读取。
栈是一个后进先出(Lastin, FirstOut, LIFO)的容器。
在这里插入图片描述
与 Queue类相似,Stack类实现 IEnumerable和 ICollection 接口。
在这里插入图片描述

class Program
{
    static void Main()
    {
        var alphabet = new Stack<char>();
        alphabet.Push('A');
        alphabet.Push('B');
        alphabet.Push('C');

        Console.Write("First iteration: ");
        foreach (char item in alphabet)
        {
            Console.Write(item);
        }
        Console.WriteLine();

        Console.Write("Second iteration: ");
        while (alphabet.Count > 0)
        {
            Console.Write(alphabet.Pop());
        }
        Console.WriteLine();
    }
}

链表

LinkedList是一个双向链表,其元素指向它前面和后面的元素。这样一来,通过移动到下一个元素可以正向遍历整个链表,通过移动到前一个元素可以反向遍历整个链表。
在这里插入图片描述

链表的优点是,如果将元素插入列表的中间位置,使用链表就会非常快。在插入一个元素时,只需要修改 上一个元素的Next引用和下一个元素的Previous引用,使它们引用所插入的元素。在List类中,插入一个 元素时,需要移动该元素后面的所有元素。

链表也有缺点。链表的元素只能一个接一个地访问,这需要较长的时间来查找位于链表中间或尾部
的元素。链表不能在列表中仅存储元素。存储元素时,链表还必须存储每个元素的下一个元素和上一个元素的信息。
在这里插入图片描述

public class Document
{
  public Document(string title, string content, byte priority)
  {
    Title = title;
    Content = content;
    Priority = priority;
  }

  public string Title { get;  }
  public string Content { get; }
  public byte Priority { get; }
}

public class PriorityDocumentManager
{
    private readonly LinkedList<Document> _documentList;

    private readonly List<LinkedListNode<Document>> _priorityNodes;

    public PriorityDocumentManager()
    {
        _documentList = new LinkedList<Document>();
        _priorityNodes = new List<LinkedListNode<Document>>(10);
        for (int i = 0; i < 10; i++)
        {
            _priorityNodes.Add(new LinkedListNode<Document>(null));
        }
    }

    public void AddDocument(Document d)
    {
        if (d is null) throw new ArgumentNullException(nameof(d));
        AddDocumentToPriorityNode(d, d.Priority);
    }

    private void AddDocumentToPriorityNode(Document doc, int priority)
    {
        if (priority > 9 || priority < 0)
            throw new ArgumentException("Priority must be between 0 and 9");

        if (_priorityNodes[priority].Value == null)
        {
            --priority;
            if (priority >= 0)
            {
                AddDocumentToPriorityNode(doc, priority);
            }
            else 
            {
                _documentList.AddLast(doc);
                _priorityNodes[doc.Priority] = _documentList.Last;
            }
            return;
        }
        else 
        {
            LinkedListNode<Document> prioNode = _priorityNodes[priority];
            if (priority == doc.Priority)
            {
                _documentList.AddAfter(prioNode, doc);

                // set the priority node to the last document with the same priority
                _priorityNodes[doc.Priority] = prioNode.Next;
            }
            else
            {
                LinkedListNode<Document> firstPrioNode = prioNode;

                while (firstPrioNode.Previous != null &&
                   firstPrioNode.Previous.Value.Priority == prioNode.Value.Priority)
                {
                    firstPrioNode = prioNode.Previous;
                    prioNode = firstPrioNode;
                }

                _documentList.AddBefore(firstPrioNode, doc);
                _priorityNodes[doc.Priority] = firstPrioNode.Previous;
            }
        }
    }

    public void DisplayAllNodes()
    {
        foreach (Document doc in _documentList)
        {
            Console.WriteLine($"priority: {doc.Priority}, title {doc.Title}");
        }
    }
    public Document GetDocument()
    {
        Document doc = _documentList.First.Value;
        _documentList.RemoveFirst();
        return doc;
    }
}

class Program
{
    static void Main()
    {
        var pdm = new PriorityDocumentManager();
        pdm.AddDocument(new Document("one", "Sample", 8));
        pdm.AddDocument(new Document("two", "Sample", 3));
        pdm.AddDocument(new Document("three", "Sample", 4));
        pdm.AddDocument(new Document("four", "Sample", 8));
        pdm.AddDocument(new Document("five", "Sample", 1));
        pdm.AddDocument(new Document("six", "Sample", 9));
        pdm.AddDocument(new Document("seven", "Sample", 1));
        pdm.AddDocument(new Document("eight", "Sample", 1));

        pdm.DisplayAllNodes();
    }
}

有序列表

如果需要基于键对所需集合排序,就可以使用SortedList<TKey,TValue>类。这个类按照键给元素排序。这 个集合中的值和键都可以使用任意类型。

class Program
{
    static void Main()
    {
        var books = new SortedList<string, string>();
        books.Add("Professional WPF Programming", "978–0–470–04180–2");
        books.Add("Professional ASP.NET MVC 5", "978–1–118-79475–3");

        books["Beginning C# 6 Programming"] = "978-1-119-09668-9";
        books["Professional C# 6 and .NET Core 1.0"] = "978-1-119-09660-3";

        foreach (KeyValuePair<string, string> book in books)
        {
            Console.WriteLine($"{book.Key}, {book.Value}");
        }

        foreach (string isbn in books.Values)
        {
            Console.WriteLine(isbn);
        }

        foreach (string title in books.Keys)
        {
            Console.WriteLine(title);
        }

        {
            string title = "Professional C# 8";
            if (!books.TryGetValue(title, out string isbn))
            {
                Console.WriteLine($"{title} not found");
            }
        }
    }
}

字典

字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素。字典也称为映射或散列表。
字典的主要特性是能根据键快速查找值。也可以自由地添加和删除元素,这有点像List类,但没有在内存 中移动后续元素的性能开销。
在这里插入图片描述

字典初始化器

C#提供了一个语法,在声明时初始化字典。带有int键和string值的字典可以初始化如下

var diet = new Dictionary<int, string>()
{
	[3] = Mthree", 
	[7] = "seven"
}

键的类型

用作字典中键的类型必须重写Object类的GetHashCodeO方法。只要字典类需要确定元素的位置,它就要 调用GetHashCode()方法。
GetHashCodeO方法的实现代码必须满足如下要求:

  • 相同的对象应总是返回相同的值。
  • 不同的对象可以返回相同的值。
  • 它不能抛出异常。
  • 它应至少使用一个实例字段。
  • 散列代码最好在对象的生存期中不发生变化。

除了 GetHashCodeO方法的实现代码必须满足的要求之外,最好还满足如下要求:

  • 它应执行得比较快,计算的开销不大。
  • 散列代码值应平均分布在int可以存储的整个数字范围上。
public class Employee
{
    private readonly string _name;
    private readonly decimal _salary;
    private readonly EmployeeId _id;

    public Employee(EmployeeId id, string name, decimal salary)
    {
        _id = id;
        _name = name;
        _salary = salary;
    }

    public override string ToString() => $"{_id.ToString()}: {_name, -20} {_salary :C}";
}

public class EmployeeIdException : Exception
{
    public EmployeeIdException(string message) : base(message) { }
}

public struct EmployeeId : IEquatable<EmployeeId>
{
    private readonly char _prefix;
    private readonly int _number;

    public EmployeeId(string id)
    {
        if (id == null) throw new ArgumentNullException(nameof(id));

        _prefix = (id.ToUpper())[0];
        int numLength = id.Length - 1;
        try
        {
            _number = int.Parse(id.Substring(1, numLength > 6 ? 6 : numLength));
        }
        catch (FormatException)
        {
            throw new EmployeeIdException("Invalid EmployeeId format");
        }
    }

    public override string ToString() => _prefix.ToString() + $"{_number,6:000000}";

    public override int GetHashCode() => (_number ^ _number << 16) * 0x1505_1505;

    public bool Equals(EmployeeId other) => _prefix == other._prefix && _number == other._number;

    public override bool Equals(object obj) => Equals((EmployeeId)obj);

    public static bool operator ==(EmployeeId left, EmployeeId right) => left.Equals(right);

    public static bool operator !=(EmployeeId left, EmployeeId right) => !(left == right);
}

class Program
{
    static void Main()
    {
        var idJimmie = new EmployeeId("C48");
        var jimmie = new Employee(idJimmie, "Jimmie Johnson", 150926.00m);

        var idJoey = new EmployeeId("F22");
        var joey = new Employee(idJoey, "Joey Logano", 45125.00m);

        var idKyle = new EmployeeId("T18");
        var kyle = new Employee(idKyle, "Kyle Bush", 78728.00m);

        var idCarl = new EmployeeId("T19");
        var carl = new Employee(idCarl, "Carl Edwards", 80473.00m);

        var idMatt = new EmployeeId("T20");
        var matt = new Employee(idMatt, "Matt Kenseth", 113970.00m);

        var employees = new Dictionary<EmployeeId, Employee>(31)
        {
            [idJimmie] = jimmie,
            [idJoey] = joey,
            [idKyle] = kyle,
            [idCarl] = carl,
            [idMatt] = matt
        };

        foreach (var employee in employees.Values)
        {
            Console.WriteLine(employee);
        }

        while (true)
        {
            Console.Write("Enter employee id (X to exit)> ");
            var userInput = Console.ReadLine();
            userInput = userInput.ToUpper();
            if (userInput == "X") break;

            EmployeeId id;
            try
            {
                id = new EmployeeId(userInput);

                if (!employees.TryGetValue(id, out Employee employee))
                {
                    Console.WriteLine($"Employee with id {id} does not exist");
                }
                else
                {
                    Console.WriteLine(employee);
                }
            }
            catch (EmployeeIdException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Lookup 类

Dictionary<TKey, TValue>类支持每个键关联一个值。Lookup<TKey, TElement>类非常类似于
Dictionary<TKey, TValue>类,但把键映射到一个值集合上。这个类在程序集System.Core中实现,用System.Linq 名称空间定义。
Lookup<TKey, TElement>类不能像一般的字典那样创建,而必须调用ToLookup()方法,该方法返回一个
Lookup<TKey,TElement>对象。ToLookup()方法是一个扩展方法,它可以用于实现IEnumerable接口的所有类。

class Program
{
    static void Main()
    {
        var racers = new List<Racer>();
        racers.Add(new Racer(26, "Jacques", "Villeneuve", "Canada", 11));
        racers.Add(new Racer(18, "Alan", "Jones", "Australia", 12));
        racers.Add(new Racer(11, "Jackie", "Stewart", "United Kingdom", 27));
        racers.Add(new Racer(15, "James", "Hunt", "United Kingdom", 10));
        racers.Add(new Racer(5, "Jack", "Brabham", "Australia", 14));

        var lookupRacers = racers.ToLookup(r => r.Country);

        foreach (Racer r in lookupRacers["Australia"])
        {
            Console.WriteLine(r);
        }
    }
}

有序字典

SortedDictionary<TKey, TValue>是一个二叉搜索树,其中的元素根据键排序。该键类型必须实现IComparable口。如果键的类型不能排序,则还可以创建一个实现了 IComparer接口的比较器, 将比较器用作有序字典的构造函数的一个参数。
如前所述,SortedDictionary<TKey, TValue>和 SortedList<TKey; TValue>的功能类似。但因为 SortedList <TKey, TValue>实现为一个基于数组的列表,而SortedDictionary<TKey, TValue>实现为一个字典,所以它们有不同的
特征。

  • SortedList<TKey, TValue>使用的内存比SortedDictionary<TKey, TValue>少。
  • SortedDictionary<TKey, TValue>的元素插入和删除操作比较快。
  • 在用己排好序的数据填充集合时,若不需要修改容量,SortedList<TKey, TValue>就比较快。
  • SortedList使用的内存比SortedDictionary少,但SortedDictionary在插入和删除未排序的数据时比较快。

包含不重复元素的集合称为集(set)。.NET Core包含两个集(HashSet<!>和SortedSet),它们都实现
ISet接口。HashSet集包含不重复元素的无序列表,SortedSet集包含不重复元素的有序列表。
ISet<!>接口提供的方法可以创建合集、交集,或者给出一个集是另一个集的超集或子集的信息。

class Program
{
    static void Main()
    {
        var companyTeams = new HashSet<string>() { "Ferrari", "McLaren", "Mercedes" };
        var traditionalTeams = new HashSet<string>() { "Ferrari", "McLaren" };
        var privateTeams = new HashSet<string>() { "Red Bull", "Lotus", "Toro Rosso", "Force India", "Sauber" };

        if (privateTeams.Add("Williams"))
            Console.WriteLine("Williams added");
        if (!companyTeams.Add("McLaren"))
            Console.WriteLine("McLaren was already in this set");

        if (traditionalTeams.IsSubsetOf(companyTeams))
        {
            Console.WriteLine("traditionalTeams is subset of companyTeams");
        }

        if (companyTeams.IsSupersetOf(traditionalTeams))
        {
            Console.WriteLine("companyTeams is a superset of traditionalTeams");
        }


        traditionalTeams.Add("Williams");
        if (privateTeams.Overlaps(traditionalTeams))
        {
            Console.WriteLine("At least one team is the same with traditional and private teams");
        }

        var allTeams = new SortedSet<string>(companyTeams);
        allTeams.UnionWith(privateTeams);
        allTeams.UnionWith(traditionalTeams);

        Console.WriteLine();
        Console.WriteLine("all teams");
        foreach (var team in allTeams)
        {
            Console.WriteLine(team);
        }

        allTeams.ExceptWith(privateTeams);
        Console.WriteLine();
        Console.WriteLine("no private team left");
        foreach (var team in allTeams)
        {
            Console.WriteLine(team);
        }
    }
}

性能

0(1)表示无论集合中有多少数据项,这个操作需要的时间都不变。例如,AirayList类的AddO方法就具有
0(1)行为。无论列表中有多少个元素,在列表末尾添加一个新元素的时间都相同。Count属性会给出元素个数, 所以很容易找到列表末尾。

O(n)表示对于集合执行一个操作需要的时间在最坏情况时是N。如果需要重新给集合分配内存,AmyList
类的Add()方法就是一个0(n)操作。改变容量,需要复制列表,复制的时间随元素的增加而线性增加。

O(logn)表示操作需要的时间随集合中元素的增加而增加,但每个元素需要增加的时间不是线性的,而是呈 对数曲线。在集合中执行插入操作时,SortedDictionaiy<TKey,TValue>集合类具有O(log n)行为,而
SortedList<TKey,TValue>^合类具有0(n)行为。这里 SortedDictionary <TKey,TValue>集合类要快得多,因为它 在树型结构中插入元素的效率比列表高得多。
在这里插入图片描述

相关文章:

  • 【css】svg修改图标颜色
  • RHEL入门之系统角色
  • “50万以内最好SUV”G9上市2天即调价,何小鹏被用户拿捏了吗?
  • Matlab科研绘图颜色补充(特别篇7)—206种欧洲传统颜色
  • C# 异常捕获
  • 【Vue】列表动画
  • 实现一个简单的Database2(译文)
  • COMSOL中事件接口介绍
  • Python基础语法
  • 前端学习——Echarts5开发技术
  • 一个基于.Net Core+Vue+Element Ui开发的OA系统
  • Linux服务器性能监控,首选Zabbix6
  • SAP 系统银行账户管理
  • ElasticSearch学习笔记记录5【图灵Fox】
  • Mybatis练习(持续更新)
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • [笔记] php常见简单功能及函数
  • 【React系列】如何构建React应用程序
  • Android框架之Volley
  • angular组件开发
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • canvas 高仿 Apple Watch 表盘
  • css系列之关于字体的事
  • ERLANG 网工修炼笔记 ---- UDP
  • JAVA SE 6 GC调优笔记
  • Java的Interrupt与线程中断
  • java第三方包学习之lombok
  • mac修复ab及siege安装
  • Markdown 语法简单说明
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • overflow: hidden IE7无效
  • SQLServer之创建显式事务
  • Vue2 SSR 的优化之旅
  • 聊聊redis的数据结构的应用
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 那些年我们用过的显示性能指标
  • 区块链技术特点之去中心化特性
  • 说说动画卡顿的解决方案
  • 为什么要用IPython/Jupyter?
  • 无服务器化是企业 IT 架构的未来吗?
  • 一份游戏开发学习路线
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​queue --- 一个同步的队列类​
  • #HarmonyOS:Web组件的使用
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (26)4.7 字符函数和字符串函数
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (SpringBoot)第二章:Spring创建和使用
  • (二)学习JVM —— 垃圾回收机制
  • (二十四)Flask之flask-session组件
  • (附源码)springboot教学评价 毕业设计 641310
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式