C#规范整理·集合和Linq

LINQ(Language Integrated Query,语言集成查询)提供了类似于SQL的语法,能对集合进行遍历、筛选和投影。一旦掌握了LINQ,你就会发现在开发中再也离不开它。
  开始!

640?wx_fmt=png

前言

  C#中的集合表现为数组和若干集合类。不管是数组还是集合类,它们都有各自的优缺点。如何使用好集合是我们在开发过程中必须掌握的技巧。不要小看这些技巧,一旦在开发中使用了错误的集合或针对集合的方法,应用程序将会背离你的预想而运行。

正文

1.元素数量可变的情况下不应使用数组

  在C#中,数组一旦被创建,长度就不能改变。如果我们需要一个动态且可变长度的集合,就应该使用ArrayList或List<T>来创建。而数组本身,尤其是一维数组,在遇到要求高效率的算法时,则会专门被优化以提升其效率。一维数组也称为向量,其性能是最佳的,在IL中使用了专门的指令来处理它们(如newarr、ldelem、ldelema、ldlen和stelem)。

  从内存使用的角度来讲,数组在创建时被分配了一段固定长度的内存。如果数组的元素是值类型,则每个元素的长度等于相应的值类型的长度;如果数组的元素是引用类型,则每个元素的长度为该引用类型的IntPtr.Size。数组的存储结构一旦被分配,就不能再变化。而ArrayList是数组结构,可以动态地增减内存空间,如果ArrayList存储的是值类型,则会为每个元素增加12字节的空间,其中4字节用于对象引用,8字节是元素装箱时引入的对象头。List<T>是ArrayList的泛型实现,它省去了拆箱和装箱带来的开销。

注意 

由于数组本身在内存上的特点,因此在使用数组的过程中还应该注意大对象的问题。所谓“大对象”,是指那些占用内存超过85 000字节的对象,它们被分配在大对象堆里。大对象的分配和回收与小对象相比,都不太一样,尤其是回收,大对象在回收过程中会带来效率很低的问题。所以,不能肆意对数组指定过大的长度,这会让数组成为一个大对象。

  1. 如果一定要动态改变数组的长度,一种方法是将数组转换为ArrayList或List<T>,需要扩容时,内部数组将自动翻倍扩容

  2. 还有一种方法是用数组的复制功能。数组继承自System.Array,抽象类System.Array提供了一些有用的实现方法,其中就包含了Copy方法,它负责将一个数组的内容复制到另外一个数组中。无论是哪种方法,改变数组长度就相当于重新创建了一个数组对象。

2.多数情况下使用foreach进行循环遍历

采用foreach最大限度地简化了代码。它用于遍历一个继承了IEmuerable或IEmuerable<T>接口的集合元素。借助于IL代码可以看到foreach还是本质就是利用了迭代器来进行集合遍历。如下:

Copy

List<object>list=new List<object>();
using(List<object>.Enumerator CS$5$0000=list.GetEnumerator())
{
while(CS$5$0000.MoveNext())
{
object current=CS$5$0000.Current;
}
}

除了代码简洁之外,foreach还有两个优势

  • 自动将代码置入try-finally块

  • 若类型实现了IDispose接口,它会在循环结束后自动调用Dispose方法。

3.foreach不能代替for

  • foreach存在的一个问题是:它不支持循环时对集合进行增删操作。 取而代之的方法是使用for循环。

    不支持原因:

  1. foreach循环使用了迭代器进行集合的遍历,它在FCL提供的迭代器内部维护了一个对集合版本的控制。那么什么是集合版本?简单来说,其实它就是一个整型的变量,任何对集合的增删操作都会使版本号加1。foreach循环会调用MoveNext方法来遍历元素,在MoveNext方法内部会进行版本号的检测,一旦检测到版本号有变动,就会抛出InvalidOperationException异常。

  2. 如果使用for循环就不会带来这样的问题。for直接使用索引器,它不对集合版本号进行判断,所以不存在因为集合的变动而带来的异常(当然,超出索引长度这种情况除外)。

Copy

public bool MoveNext()
{
List<T>list=this.list;
if((this.version==list._version)&&(this.index<list._size))
{
this.current=list._items[this.index];
this.index++;
return true;
}
return this.MoveNextRare();
}

无论是for循环还是foreach循环,内部都是对该数组的访问,而迭代器仅仅是多进行了一次版本检测。事实上,在循环内部,两者生成的IL代码也是差不多的。

4.使用更有效的对象和集合初始化

举例:

Copy

class Program {
static void Main(string[]args)
{
Person person=new Person(){Name="Mike",Age=20};
}
}

class Person
{
public string Name{get;set;}
public int Age{get;set;}
}

对象初始化设定项支持在大括号中对自动实现的属性进行赋值。以往只能依靠构造方法传值进去,或者在对象构造完毕后对属性进行赋值。现在这些步骤简化了,初始化设定项实际相当于编译器在对象生成后对属性进行了赋值。

集合初始化也同样进行了简化:

Copy

List<Person>personList=new List<Person>( )
{
new Person() {Name="Rose",Age=19},
mike,
null
};

重点:初始化设定项绝不仅仅是为了对象和集合初始化的方便,它更重要的作用是为LINQ查询中的匿名类型进行属性的初始化。由于LINQ查询返回的集合中匿名类型的属性都是只读的,如果需要为匿名类型属性赋值,或者增加属性,只能通过初始化设定项来进行。初始化设定项还能为属性使用表达式。
举例

Copy

List<Person>personList2=new List<Person>()
{
new Person(){Name="Rose",Age=19},
new Person(){Name="Steve",Age=45},
new Person(){Name="Jessica",Age=20}
};

var pTemp=from p in personList2
select new {p.Name, AgeScope=p.Age>20?"Old":"Young"};

foreach(var item in pTemp)
{
Console.WriteLine(string.Format("{0}:{1}",item.Name,item.AgeScope));
}

5.使用泛型集合代替非泛型集合

注意,非泛型集合在System.Collections命名空间下,对应的泛型集合则在System.Collections.Generic命名空间下。

泛型的好处不言而喻,,如果对大型集合进行循环访问、转型或拆箱和装箱操作,使用ArrayList这样的传统集合对效率的影响会非常大。鉴于此,微软提供了对泛型的支持。泛型使用一对<>括号将实际的类型括起来,然后编译器和运行时会完成剩余的工作。

6.选择正确的集合

要选择正确的集合,首先需要了解一些数据结构的知识。所谓数据结构,就是相互之间存在一种或多种特定关系的数据元素的集合
640?wx_fmt=png

说明

  1. 直接存储结构的优点是:向数据结构中添加元素是很高效的,直接放在数据末尾的第一个空位上就可以了。它的缺点是:向集合插入元素将会变得低效,它需要给插入的元素腾出位置并顺序移动后面的元素。
    如果集合的数目固定并且不涉及转型,使用数组效率高,否则就使用List<T>(该使用数组的时候,还是要使用数组)

  2. 顺序存储结构,即线性表。线性表可动态地扩大和缩小,它在一片连续的区域中存储数据元素。线性表不能按照索引进行查找,它是通过对地址的引用来搜索元素的,为了找到某个元素,它必须遍历所有元素,直到找到对应的元素为止。所以,线性表的优点是插入和删除数据效率高,缺点是查找的效率相对来说低一些。

  3. 队列Queue<T>遵循的是先入先出的模式,它在集合末尾添加元素,在集合的起始位置删除元素。

  4. 栈Stack<T>遵循的是后入先出的模式,它在集合末尾添加元素,同时也在集合末尾删除元素。

  5. 字典Dictionary<TKey, TValue>存储的是键值对,值在基于键的散列码的基础上进行存储。字典类对象由包含集合元素的存储桶组成,每一个存储桶与基于该元素的键的哈希值关联。如果需要根据键进行值的查找,使用Dictionary<TKey, TValue>将会使搜索和检索更快捷。

  6. 双向链表LinkedList<T>是一个类型为LinkedListNode的元素对象的集合。当我们觉得在集合中插入和删除数据很慢时,就可以考虑使用链表。如果使用LinkedList<T>,我们会发现此类型并没有其他集合普遍具有的Add方法,取而代之的是AddAfter、AddBefore、AddFirst、AddLast等方法。双向链表中的每个节点都向前指向Previous节点,向后指向Next节点。

  7. 在FCL中,非线性集合实现得不多。非线性集合分为层次集合和组集合。层次集合(如树)在FCL中没有实现。组集合又分为集和图,集在FCL中实现为HashSet<T>,而图在FCL中也没有对应的实现。
    集的概念本意是指存放在集合中的元素是无序的且不能重复的。

  8. 除了上面提到的集合类型外,还有其他几个要掌握的集合类型,它们是在实际应用中发展而来的对以上基础类型的扩展:SortedList<T>、SortedDictionary<TKey, TValue>、Sorted-Set<T>。它们所扩展的对应类分别为List<T>、Dictionary<TKey, TValue>、HashSet<T>,作用是将原本无序排列的元素变为有序排列。

  9. 除了排序上的需求增加了上面3个集合类外,在命名空间System.Collections.Concurrent下,还涉及几个多线程集合类。它们主要是:

  • ConcurrentBag<T>对应List<T>

  • ConcurrentDictionary<TKey, TValue>对应Dictionary<TKey, TValue>

  • ConcurrentQueue<T>对应Queue<T>

  • ConcurrentStack<T>对应Stack<T>

FCL集合图如下:640?wx_fmt=png

7.确保集合的线程安全

集合线程安全是指在多个线程上添加或删除元素时,线程之间必须保持同步。
泛型集合一般通过加锁来进行安全锁定,如下:

Copy

static object sycObj=new object();
static void Main(string[]args)
{

Thread t1=new Thread(()=>{


autoSet.WaitOne();
lock(sycObj)
{
foreach(Person item in list)
{
Console.WriteLine("t1:"+item.Name);
Thread.Sleep(1000);
}
}
}

8.避免将List<T>作为自定义集合类的基类

如果要实现一个自定义的集合类,不应该以一个FCL集合类为基类,而应该扩展相应的泛型接口。FCL集合类应该以组合的形式包含至自定义的集合类,需扩展的泛型接口通常是IEnumer-able<T>和ICollection<T>(或ICollection<T>的子接口,如IList<T>),前者规范了集合类的迭代功能,后者则规范了一个集合通常会有的操作。

List<T>基本上没有提供可供子类使用的protected成员(从object中继承来的Finalize方法和Member-wiseClone方法除外),也就是说,实际上,继承List<T>并没有带来任何继承上的优势,反而丧失了面向接口编程带来的灵活性。而且,稍加不注意,隐含的Bug就会接踵而至。

9.迭代器应该是只读的

FCL中的迭代器只有GetEnumerator方法,没有SetEnumerator方法。所有的集合类也没有一个可写的迭代器属性。

原因有二

  1. 这违背了设计模式中的开闭原则。被设置到集合中的迭代器可能会直接导致集合的行为发生异常或变动。一旦确实需要新的迭代需求,完全可以创建一个新的迭代器来满足需求,而不是为集合设置该迭代器,因为这样做会直接导致使用到该集合对象的其他迭代场景发生不可知的行为。

  2. 现在,我们有了LINQ。使用LINQ可以不用创建任何新的类型就能满足任何的迭代需求。

10.谨慎集合属性的可写操作

如果类型的属性中有集合属性,那么应该保证属性对象是由类型本身产生的。如果将属性设置为可写,则会增加抛出异常的几率。一般情况下,如果集合属性没有值,则它返回的Count等于0,而不是集合属性的值为null。

11.使用匿名类型存储LINQ查询结果(最佳搭档)

从.NET 3.0开始,C#开始支持一个新特性:匿名类型。匿名类型由var、赋值运算符和一个非空初始值(或以new开头的初始化项)组成。匿名类型有如下的基本特性:

  • 既支持简单类型也支持复杂类型。简单类型必须是一个非空初始值,复杂类型则是一个以new开头的初始化项;

  • 匿名类型的属性是只读的,没有属性设置器,它一旦被初始化就不可更改;

  • 如果两个匿名类型的属性值相同,那么就认为两个匿名类型相等;

  • 匿名类型可以在循环中用作初始化器;

  • 匿名类型支持智能感知;

  • 还有一点,虽然不常用,但是匿名类型确实也可以拥有方法。

11. 在查询中使用Lambda表达式

LINQ实际上是基于扩展方法和Lambda表达式的,理解了这一点就不难理解LINQ。任何LINQ查询都能通过调用扩展方法的方式来替代,如下面的代码所示:

Copy

foreach(var item in personList.Select(person=>new{PersonName= person.Name,CompanyName=person.CompanyID==0?"Micro":"Sun"}))
{

Console.WriteLine(string.Format("{0}\t:{1}",item.PersonName, item.CompanyName));
}

针对LINQ设计的扩展方法大多应用了泛型委托。System命名空间定义了泛型委托Action、Func和Predicate。可以这样理解这三个委托:Action用于执行一个操作,所以它没有返回值;Func用于执行一个操作并返回一个值;Predicate用于定义一组条件并判断参数是否符合条件。Select扩展方法接收的就是一个Func委托,而Lambda表达式其实就是一个简洁的委托,运算符“=>”左边代表的是方法的参数,右边的是方法体。

12.理解延迟求值和主动求值之间的区别

样例如下:

Copy

List<int>list=new List<int>(){0,1,2,3,4,5,6,7,8,9};
var temp1=from c in list where c>5 select c;
var temp2=(from c in list where c>5 select c).ToList<int>();

在使用LINQ to SQL时,延迟求值能够带来显著的性能提升。举个例子:如果定义了两个查询,而且采用延迟求值,CLR则会合并两次查询并生成一个最终的查询。

13.区别LINQ查询中的IEnumerable<T>和IQueryable<T>

LINQ查询方法一共提供了两类扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合类进行扩展;Queryable类,它针对继承了IQueryable<T>接口的集合类进行扩展。稍加观察我们会发现,接口IQueryable<T>实际也是继承了IEnumerable<T>接口的,所以,致使这两个接口的方法在很大程度上是一致的。那么,微软为什么要设计出两套扩展方法呢?

我们知道,LINQ查询从功能上来讲实际上可分为三类:LINQ to OBJECTS、LINQ to SQL、LINQ to XML(本建议不讨论)。设计两套接口的原因正是为了区别对待LINQ to OBJECTS、LINQ to SQL,两者对于查询的处理在内部使用的是完全不同的机制。针对LINQ to OBJECTS时,使用Enumerable中的扩展方法对本地集合进行排序和查询等操作,查询参数接受的是Func<>。Func<>叫做谓语表达式,相当于一个委托。针对LINQ toSQL时,则使用Queryable中的扩展方法,它接受的参数是Ex-pression<>。Expression<>用于包装Func<>。LINQ to SQL引擎最终会将表达式树转化成为相应的SQL语句,然后在数据库中执行。

那么,到底什么时候使用IQueryable<T>,什么时候使用IEnumerable<T>呢?简单表述就是:本地数据源用IEnumer-able<T>,远程数据源用IQueryable<T>。

注意

在使用IQueryable<T>和IEnumerable<T>的时候还需要注意一点,IEnumerable<T>查询的逻辑可以直接用我们自己所定义的方法,而IQueryable<T>则不能使用自定义的方法,它必须先生成表达式树,查询由LINQ to SQL引擎处理。在使用IQueryable<T>查询的时候,如果使用自定义的方法,则会抛出异常。

13.使用LINQ取代集合中的比较器和迭代器

LINQ提供了类似于SQL的语法来实现遍历、筛选与投影集合的功能。借助于LINQ的强大功能,我们通过两条语句就能实现上述的排序要求。

Copy

var orderByBonus=from s in companySalary orderby s.Bonus select s;

foreach实际会隐含调用的是集合对象的迭代器。以往,如果我们要绕开集合的Sort方法对集合元素按照一定的顺序进行迭代,则需要让类型继承IEnumerable接口(泛型集合是IEnumerable<T>接口),实现一个或多个迭代器。现在从LINQ查询生成匿名类型来看,相当于可以无限为集合增加迭代需求。

有了LINQ之后,我们是否就不再需要比较器和迭代器了呢?答案是否定的。我们可以利用LINQ的强大功能简化自己的编码,但是LINQ功能的实现本身就是借助于FCL泛型集合的比较器、迭代器、索引器的。LINQ相当于封装了这些功能,让我们使用起来更加方便。在命名空间Sys-tem.Linq下存在很多静态类,这些静态类存在的意义就是为FCL的泛型集合提供扩展方法

  • 强烈建议你利用LINQ所带来的便捷性,但我们仍需掌握比较器、迭代器、索引器的原理,以便更好地理解LINQ的思想,写出更高质量的代码。最好是能看懂Linq源码。

Copy

public static IOrderedEnumerable<TSource>OrderBy<TSource,TKey>(this IEnumerable<TSource>source,Func<TSource,TKey>keySelector){ //省略}

14.在LINQ查询中避免不必要的迭代

  1. 比如常使用First()方法,First方法实际完成的工作是:搜索到满足条件的第一个元素,就从集合中返回。如果没有符合条件的元素,它也会遍历整个集合。

  2. 与First方法类似的还有Take方法,Take方法接收一个整型参数,然后为我们返回该参数指定的元素个数。与First一样,它在满足条件以后,会从当前的迭代过程直接返回,而不是等到整个迭代过程完毕再返回。如果一个集合包含了很多的元素,那么这种查询会为我们带来可观的时间效率。

    会运用First和Take等方法,都会让我们避免全集扫描,大大提高效率。

总结

如有需要, 上一篇的《c#规范整理·语言要素》也可以看看!

原文地址:https://www.cnblogs.com/zhan520g/p/11018163.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 
640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/315394.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UVA - 11361 Investigating Div-Sum Property(数位dp/记忆化搜索板子)

题目&#xff1a;https://vjudge.net/problem/UVA-11361 思路&#xff1a;数位dp&#xff0c;用记忆化搜索写&#xff0c;dp[pos][i][j][limit] 代表剩余有pos位&#xff0c;每位上的数字和模k 等于i&#xff0c; 当前总数值模k等于j&#xff0c;limit代表限制位。 本题还要注意…

C#并发编程之异步编程(三)

写在前面本篇是异步编程系列的第三篇&#xff0c;本来计划第三篇的内容是介绍异步编程中常用的几个方法&#xff0c;但是前两篇写出来后&#xff0c;身边的朋友总是会有其他问题&#xff0c;所以决定再续写一篇&#xff0c;作为异步编程(一)和异步编程(二)的补充。本篇内容主要…

UVA - 10253 Series-Parallel Networks(递推式、记忆化搜索写法)

题目&#xff1a;UVA-10253 题目翻译&#xff08;来自蓝书&#xff09;&#xff1a; 串并联网络有两个端点&#xff0c;一个叫源&#xff0c;一个叫汇&#xff0c;递归定义如下&#xff1a; &#xff08;1&#xff09; 一条单独的边是串并联网络。 &#xff08;2&#xff09;…

C#规范整理·泛型委托事件

基于泛型&#xff0c;我们得以将类型参数化&#xff0c;以便更大范围地进行代码复用。同时&#xff0c;它减少了泛型类及泛型方法中的转型&#xff0c;确保了类型安全。委托本身是一种引用类型&#xff0c;它保存的也是托管堆中对象的引用&#xff0c;只不过这个引用比较特殊&a…

Abp v0.18.0 新版本: MVC Module 启动模板

0.18.0将于近期发布, 本文内容针对于0.18.0版本.MVC模块启动模板可用此模板开发基于模块开发最佳实践和约定的可复用 应用程序模块 . 它同样适用于开发微服务.如何开始?你可以使用ABP CLI创建基于此启动模板的新项目,或者你也可以在入门页面创建并下载项目. 在这里我们使用CLI…

Consul-template+nginx实现自动负载均衡

前言consul-template 是 Consul 的一个守护程序&#xff0c;使用 consul-template 可以方便快速的实现对 Consul Key/Value 存储系统的访问&#xff0c;可以从 KV 系统中读取数据、监视变动、同步本地文件&#xff1b;还可以在执行模板更新的同时&#xff0c;执行本地系统命令&…

Codeforces Round #613 (Div. 2) E. Delete a Segment 离散化

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 我们考虑将区间内的位置都111&#xff0c;之后求区间段数就可以转换成求&#xff0c;连续不为000的区间段数&#xff0c;由于范围有[−1e9,1e9][-1e9,1e9][−1e9,1e9]的级别&#xff0c;所…

是时候挥别 SQL Server 2008 了

微软 宣布将于 2019 年 7 月终止对 SQL Server 2008 和 2008 R2 的支持&#xff0c;使用 SQL Server 2008 的公司应该认真开始考虑下一步了。本文引用了一家数字化转型咨询公司高级顾问对此的分析&#xff0c;并提供了一些解决方案和注意事项。如果你还在使用 微软 2008 版的 S…

领域驱动设计,让程序员心中有码(八)

领域驱动是十五年前&#xff0c;由Eric Evans提出的解决软件工程复杂性问题的方法&#xff0c;作者从自己多年软件开发的角度出发&#xff0c;通过引入领域驱动设计的概念以及一系列战略设计模式和战术方法&#xff0c;为混沌的软件开发领域带来了一缕阳光。在过去的许多年&…

H - Great Cells Gym - 101194H(数学推导/思维)

VJ地址 ps&#xff1a;在训练时写这道题 差点被送走了 我们可以发现给出的公式可以转化这样 这个就不说了&#xff0c;就是k^(nm)所以排列的可能; 然后我们要重点观察这个公式&#xff0c;可以发现g * Ag&#xff08;方案数 * good点的数量&#xff09; 可以意味这组成一个…

基于Dapper的开源Lambda扩展,且支持分库分表自动生成实体之基础

LnskyDB是基于Dapper的Lambda扩展,支持按时间分库分表,也可以自定义分库分表方法.而且可以T4生成实体类免去手写实体类的烦恼.文档地址: https://liningit.github.io/LnskyDB/开源地址: https://github.com/liningit/LnskyDBnuget地址: https://www.nuget.org/packages/LnskyDB…

技术达人“创造营”官宣:Microsoft Learn 学习平台C位出道

真的大神敢于直面随时更新的IT技术你是要做一个平平无奇的“合格员工”&#xff1f;还是要做一个博古通今的“江湖百晓生”&#xff1f;转型变化&#xff0c;是时代的氛围面对日新月异的技术更新一不留神&#xff0c;就会沦落为“技术支持滞后人员”在微软&#xff0c;有这样一…

P2839 [国家集训队]middle 二分 + 主席树 在值域上建区间

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 我们先解决怎么判断中位数的问题&#xff0c;我们可以二分一个midmidmid&#xff0c;将<mid<mid<mid的值都变成−1-1−1&#xff0c;其他的数都变成111&#xff0c;那么当全部的和…

读再多书都没觉得自己变强?试试我这“5年陈”的方法

这里是Z哥的个人公众号每周五早8点 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「76」篇原创敬上4800字巨献奉上hi&#xff0c;大家好。三周过去了&#xff0c;上次教你的几个「速读」技巧练习的怎么样了&#xff1f;上周&#xff0c;已经有不少小伙们开始催…

Educational Codeforces Round 77 (Rated for Div. 2) C. Infinite Fence 数论

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 碰到这样的题肯定是先写几个找找规律了&#xff0c;随便写几个就可以发现是以lcm(a,b)lcm(a,b)lcm(a,b)为一个循环&#xff0c;所以我们只需要在一个周期lcm(a,b)lcm(a,b)lcm(a,b)中求最长…

C# 内存的理解 通俗说

一.概念堆栈是什么&#xff1f;在说堆栈之前&#xff0c;先说说内存是神马&#xff1f;内存&#xff1a;程序在运行的过程&#xff0c;电脑需要不断通过CPU进行计算&#xff0c;这个计算的过程会读取并产生运算的数据&#xff0c;这些数据需要一个存储容器存放。这个容器&#…

P3899 [湖南集训]谈笑风生 主席树解决二维数点

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 由于a,ba,ba,b都比ccc厉害&#xff0c;那么a,ba,ba,b一定是某个是某个的祖先。那么就分为两种情况了&#xff1a; (1)(1)(1) bbb在aaa上面&#xff0c;约定depth[1]1depth[1]1depth[1]1&am…

打造 .NET Core 链接转发服务

我最近使用 .NET Core 2.2 造了个名为"Link Forwarder" &#xff08;链接转发器&#xff09;的 URL 转发服务&#xff0c;并已开源。目前预览版已部署到我的子域"go.edi.wang"。本文将分享我如何构建这个项目&#xff0c;以及我学到的东西。为了帮助大家了…

P3293 [SCOI2016]美味 主席树 + 伪01trie

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 看到异或的话&#xff0c;很容易想到用01trie来贪心的搞&#xff0c;但是这个题涉及区间问题&#xff0c;直接搞的话需要将[l,r][l,r][l,r]的数都插入trie里面&#xff0c;这样的复杂度显然…

Abp 0.18.0 正式发布! -ABP CLI,新模板和其他功能

ABP CLI, v0.18版本新模板和其他功能ABP v0.18已发布, 包含解决的80个issue, 550次提交.网站更改abp.io网站完全更新以突出ABP框架的目标和重要功能.文档和博客网址也会更改&#xff1a;abp.io/documents移至docs.abp.io.abp.io/blog转移到blog.abp.io.ABP CLIABP CLI(命令行界…