话说 虽然敲过好多代码, 但除了C++,一直没正眼瞧过其它语言。(没办法 谁叫C++既有oop又能自由控制内存呢)

今天 看公司老项目的src,c#的,linq+Dictionary的用法有感。所以找来C#的资料 就学了一下,妈的 变天儿了。

以后不能再用C++编写思路,囫囵着过日子了。

------------------------------------------------------------------ 我是分割线 -----------------------------------------------------------------------

以下 学习笔记

列表List<T>、队列、栈、链表、字典和集;
位数组 和 并发集合 【多线程环境使用】
 
集合借口和类型
大多数集合类在System.Collections 和 System.Collections.Generic命名空间中。
泛型集合 ==> System.Collections.Generic
专用于特定类型的集合类 ==> System.Collections.Concurrent
不可变的集合类 ==> System.Collections.Immutable
 
列表
.NET Framework为动态列表提供了泛型类 List<T>。
这个类实现了IList、ICollection、IEnumerable、IList<T>、ICollection<T>和IEnumerable<T>接口。
 
ArrayList是一个非泛型列表,它可以将任意Object类型作为其元素。
 
使用默认的构造函数创建一个空列表。元素添加到列表中后,列表的容量就会扩大为可容纳4个元素。如果添加了第5个元素,列表的大小就成新设置为包含8个元素,如果8个元素还不够,列表的大小就重新设置为包含16个元素。每次都会将列表的容量重新设置为原来的2倍。
如果列表的内容改变了,整个集合就要重新分配到一个新的内存块中。即创建一个新的数组,大小是原来的2倍。
 
创建指定元素个数的列表
List<int> intList = new List<int>(10);
 
可以通过索引访问的集合类有 ArrayList、StringCollection 和 List<T>
 
ForEach()方法遍历集合中的每一项,调用作为每一项的参数传递的方法。
public delegate void Action<T> (T obj);
public void ActionHandler (Racer obj);
racers.ForEach( Console.WriteLine );
racers.ForEach( r => Console.WriteLine("{0:A}", r); //lambda表达式
删除元素
删除元素时,可以利用索引,也可以传递要删除的元素。
按索引删除比较快,因为必须在集合中搜索要删除的元素。Remove()方法现在集合中搜索,用IndexOf()方法获取元素的索引,在使用该索引删除元素。IndexOf()方法先检查元素类型是否实现了IEquatable<T>接口。如果是就调用这个接口的Equals()方法,确定集合中的元素是否等于传递给Equals()方法的元素。如果没有实现这个接口,就使用Object类的Equals()方法比较这些元素。Object类中的Equals()方法的默认实现代码对值类型进行比较,对引用类型只比较其引用。
重写IEquatable<T>接口或Object.Equals()方法可以根据列表元素对象的特定属性进行删除列表元素。
第7章 介绍如何重写Equals()方法
 
搜索
有不同的方式在集合中搜索元素。可以获得要查找的元素的引用,或者搜索元素本身。
方法有:
IndexOf()
LastIndexOf()
FindIndex()
FindLastIndex()
Find()
FindLast()
检查元素是否存在:List<T>.Exists()方法;
IndexOf()可以指定不需要搜索整个集合,需要指定开始索引以及需要迭代的元素个数
FindIndex()可以搜索有某个特性的元素
public int FindIndex(Predicate<T> match); //Predicate<T>类型是一个委托,该委托返回一个bool值
int index = racers.FindIndex( r => r.Country == "FinLand");
 
FindIndex()方法返回所查找元素的索引。Find()方法除了获得索引之外,还可以直接获得集合中的元素。
Racer racer = racers.Find( r => r.FirstName == "Niki");
要获得于Predicate<T>类型匹配的所有项,而不是一项,可以使用FindAll()方法;
 
排序
List<T>类可以使用Sort()方法对元素排序。Sort()方法使用快速排序算法。
Sort()方法使用了几个重载的方法:
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, IComparet<T>);

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

2. 如果需要按照元素类型不默认支持的方式排序,就应使用其他技术,如传递一个实现了IComparer<T>接口的对象。
3. 排序的另一种方式使用重载的Sort()方法。
调用Reverse()方法,逆转整个集合的顺序。
 
类型转换
使用List<T>类的ConvertAll<TOutput>()方法,可以把所有类型的集合转换为另一种类型。
ConvertAll<TOutput>()方法使用一个Converter委托:
public sealed delegate TOutput Converter<TInput, TOutput> (TInput from);
eg:
List<Person> persons = racers.ConvertAll<Person>( r => new Person(r.FirstName + " " + r.LastName));
只读集合
List<T>集合的AsReadOnly()方法返回 ReadOnlyCollection<T>类型的对象。
ReadOnlyCollection<T>类实现的接口与List<T>集合相同,但如若修改将抛出异常NotSupportedException异常。
ReadOnlyCollection<T>还实现了IReadOnlyCollection<T>和IReadOnlyList<T>接口。
 
 
队列
Queue<T> 命名空间 System.Collections.Generic
队列是其元素以先进先出(FIFO)的方式来处理的集合。
 
可以使用多个队列,一个队列对应一个优先级。打印队列和线程队列是这样的。
可以为一组队列建立一个数组,数组中的一项代表一个优先级。
 
在内部Queue<T>类使用T类型的数组;它实现ICollection和IEnumerable<T>接口。
因为没有实现IList<T>接口,所以不能用索引器访问元素。
Queue<T>方法如下:
Count
Enqueue
Dequeue
Peek //从队列头部读取一个元素但不删除它
TrimExcess //重新设置队列的容量,Dequeue()方法从队列中删除元素,但不会重新设置队列容量,要从队列的头部去除空元素,应使用TrimExcess()方法

多线程可以同时访问,但要是用lock语句锁定队列的访问:

public class DocumentManager {
private readonly Queue<Document> documentQueue = new Queue<Document>();
public void AddDocument(Document doc) {
lock (this) {
documentQueue.Enqueue(doc);
}
} public Document GetDocument() {
Document doc = null;
lock (this) {
doc = documentQueue.Dequeue();
}
return doc;
} public bool IsDocumentAvailable {
get { return documentQueue.Count > 0; }
}
}
栈是一个后进先出(LIFO)的容器
与Queue<T>类相同,Stack<t>类实现了IEnumerable<T>和ICollection接口。
成员列表:
Count
Push
Pop
Peek
Contains
在foreach方法中,使用IEnumerable接口迭代所有的元素;栈的枚举器不会删除元素,它只是逐个返回元素
 
链表
LinkedList<T>是一个双向链表
链表的有点事,如果将元素插入列表的中间位置,使用链表就会非常快。
在插入一个元素时,只需要修改上一个元素的Next引用和下一个元素的Previous引用,使它们引用所插入的元素。
在List<T>类中,插入一个元素时,需要移动该元素后面的所有元素。
链表的缺点:链表的元素只能一个接一个地访问,这需要较长的时间来查找位于链表中间或尾部的元素。
 
有序列表
如果需要基于键对所需集合排序,就可以使用SortList<TKey, TValue>类。这个类按照键给元素排序。
 
字典
.NET Framework提供了几个字典类,可以使用的最主要的类是Dictionary<TKey, TValue>
 
键的类型
用作字典中键的类型必须重写Object类的GetHashCode()方法;字典的性能取决于GetHashCode()方法的实现代码。
除了实现GetHashCode()方法之外,键类型还必须实现IEquatable<T>.Equals()方法,或者重写Object类的Equals()方法。
 
Lookup 类
Lookup<TKey, TElement>把键映射到一个值集上;Lookup<TKey, TElement>类在程序集System.Core中实现,用System.Linq命名空间。
 
Lookup<TKey, TElement>类不能像一般的字典那样创建,而必须调用ToLookup()方法,该方法返回一个Lookup<TKey, TElement>对象。ToLookup()方法是一个扩展方法,它可以用于实现了IEnumerable<T>接口的所有类。
 
有序字典
SortedDictionary<TKey, TValue>类是一个二叉搜索树,其中的元素根据键来排序。该键类型必须实现IComparable<TKey>接口。
如果键的类型不能排序,则还可以创建一个实现了IComparer<TKey>接口的比较器,将比较器用作有序字典的构造函数的一个参数。
 
 
包含不重复元素的集合成为“集(set)”。
.NET Framework包含两个集 HashSet<T> 和 SoredSet<T>, 它们都实现ISet<T>接口。
 
可观察的集合
如果需要集合中的元素何时删除或添加的信息,就可以使用ObservableCollection<T>类。
这个类是为WPF定义的,这样UI就可以得知集合的变化,因此这个类在程序集WindowsBase中定义;命名空间是 System.Collections.ObjectModel。
ObservableCollection<T>类派生自Collection<T>基类,该基类可以创建自定义集合,并在内部使用List<T>类。重写基类中的虚方法SetItem()和RemoveItem(),以触发CollectionChanged事件。这个类的用户可以使用INotifyCollectionChanged接口注册这个事件。
 
位数组
如果需要处理的数字有许多位,就可以使用BitArray类和BitVector32接口。
 
BitArray类
BitArray类位于名称空间System.Collections中,BitArray类可以重新设置大小,如果事先不知道需要的位数,就可以使用BitArray类,它可以包含非常多的位。
BitArray类是一个引用类型,它包含一个int数组,其中每32位使用一个新整数。
成员如下:
CountLength
Item [Get / Set]
SetAll
Not //取反
And / Or / Xor
辅助方法DisplayBits()遍历BitArray:
static void DisplayBits(BitArray bits) {
foreach (bool bit in bits) {
Console.Write(bit ? 1 : 0);
}
}
var bits = new BitArray(8); //创建一个8位的数组
bits.SetAll(true); //把8位都设置位true,即 1
bits.Set(1, false); //把下标为1的位设置为false,即 0
bits[5] = false; //使用索引器设置
Console.Write("Initialized:");
DisplayBits(bits);
Console.WriteLine();
BitVector32结构
BitVector32结构位于命名空间System.Collections.Specialized中。
BitVector32结构是基于栈的,因此比较快。但仅能包含32位,存储在一个整数中。
 
如果事先知道需要的位数,就可以使用BitVector32结构替代BitArray类,效率较高;因为他是一个值类型。
一个整数可以存储32位,如果需要更多的位,可以使用多个BitVector32值或BitArray类。
BitVector32成员如下:
Data //Data属性把BitVector32结构中的数据返回为整数
Item //BitVector32的值可以使用索引器设置
CreateMask //这是一个静态方法,用于为访问BitVector32结构中的特定位创建掩码
CreateSection //这是一个静态方法,用于创建32位中的几个片段
 
不变的集合
如果对象可以改变其状态,就很难在多个同时运行的任务中使用。这些集合必须同步。如果对象不能改变其状态,就很容易在多个线程中使用。不能改变的对象成为不变的对象。
在VS2013中,Microsoft提供了一个新的集合库: Microsoft Immutable Collections。它包含不变的集合类 ----- 创建后就不能改变的集合类。
 
并发集合
从 .NET 4开始,命名空间System.Collections.Concurrent中提供了几个线程安全的集合类。
线程安全的集合可防止多个线程以相互冲突的方式访问集合。
为了对集合进行线程安全的访问,定义了IProducerConsumerCollection<T>接口。这个接口中最重要的方法是TryAdd()和TryTake()。TryAdd()方法尝试给集合添加一项,但如果集合禁止添加项,这个操作就可能失败。TryTake()雷同。
 
下面列出System.Collections.Concurrent名称空间中的类及功能:
ConcurrentQueue<T>
ConcurrentStack<T>
ConcurrentBag<T>
ConcurrentDictionary<TKey, TValue>
BlockingCollection<T>
ConcurrentXXXX集合是线程安全的,如果某个动作不适用于线程当前状态,他们返回false。
BlockingCollection<T>是对实现IProducerConsumerCollection<T>接口的任意类的修饰器,他默认使用ConcurrentQueue<T>类。
 
创建管道
将这些并发集合类用于管道是一种很好的应用:一个任务向一个集合类写入一些内容,同时另一个任务从该集合中读取内容。
 
性能
许多集合类都提供了相同的功能,但是,其性能常常有很大的区别。
在MSDN文档中,集合的方法常常有性能提示,给出了以大写O标记的操作时间:
O(1) //表示无论集合中有多少数据项,这个操作需要的时间都不变
O(long n) //表示对于集合执行一个操作需要的事件在最坏情况是是N
O(n) //表示操作需要的时间随集合中元素的增加而增加,但每个元素需要增加的时间不是线性的,而是呈对数曲线
 
 
总结
数组Array的大小是固定的,可以使用列表List作为动态增长的集合。
队列Queue以先进先出的方式访问元素,栈Stack以先进后出的方式访问元素。
链表LinkedList可以快速的插入和删除元素,但搜索操作比较慢。
通过键值对可以使用字典Dictionary,它的搜索和插入操作比较快。
集用于唯一项,可以是无序的HashSet,也可以是有序的SortedSet。
ObservableCollection类提供了列表中的元素发生变化时触发的事件。
 

C#高级编程(第9版) 第10章 集合 笔记的更多相关文章

  1. 【转】apue《UNIX环境高级编程第三版》第一章答案详解

    原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...

  2. C#高级编程第11版 - 第六章 索引

    [1]6.2 运算符 1.&符在C#里是逻辑与运算.管道符号|在C#里则是逻辑或运算.%运算符用来返回除法运算的余数,因此当x=7时,x%5的值将是2. [2]6.2.1 运算符的简写 1.下 ...

  3. C#高级编程第11版 - 第五章 索引

    [1]5.1 泛型概述 1.通过泛型,你可以创建独立于特定类型(contained types)以外的方法和类,而不用为不同类型编写多份同样功能的代码,你只需要创建一个方法或者类. 2.泛型类使用泛型 ...

  4. C#高级编程第11版 - 第三章 索引

    [1]3.1 创建及使用类 1.构造函数:构造函数的名字与类名相同: 使用 new 表达式创建类的对象或者结构(例如int)时,会调用其构造函数.并且通常初始化新对象的数据成员. 除非类是静态的,否则 ...

  5. C#高级编程 (第六版) 学习 第二章:C#基础

    第二章 基础 1,helloworld示例: helloworld.cs using System; using System.Collections.Generic; using System.Li ...

  6. C#高级编程 (第六版) 学习 第一章:.Net体系结构

    第一章 .Net体系结构 1,公共语言运行库(Common Language Runtime, CLR) .Net Framework的核心是其运行库的执行环境,称为公共语言运行库,或.Net运行库. ...

  7. C#高级编程第11版 - 第七章 索引

    [1]7.1 相同类型的多个对象 1.假如你需要处理同一类型的多个对象,你可以使用集合或者数组. 2.如果你想使用不同类型的不同对象,你最好将它们组合成class.struct或者元组. [2]7.2 ...

  8. C#高级编程第11版 - 第四章 索引

    [1]4.2 继承的类型 1.C#不支持类的多继承,但它支持一个接口继承自多个接口. 2.单继承:单继承允许一个类继承自另外一个基类,C#支持. 3.多级继承:多级继承允许创建一个类继承自它的父类,而 ...

  9. javascript高级程序设计第3版——第10章 DOM

    第十章,DOM DOM是语言中立的API,用于访问和操作HTML 和XML 文档.DOM1 级将HTML 和XML 文档形象地看作一个层次化的节点树,可以使用JavaScript 来操作这个节点树,进 ...

随机推荐

  1. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 图片:为图片添加圆角 (IE8 不支持)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. mysq 数据库约束入门

  3. Java Break 与 Continue

    章节 Java 基础 Java 简介 Java 环境搭建 Java 基本语法 Java 注释 Java 变量 Java 数据类型 Java 字符串 Java 类型转换 Java 运算符 Java 字符 ...

  4. NAND Flash驱动

    硬件原理及分析 管脚说明         Pin Name Pin Function R/B(RnB) The R/B output indicates the status of the devic ...

  5. java.lang.NumberFormatException: For input string: "F"

    在通过myBatis执行sql时,报错: java.lang.NumberFormatException: For input string: "F" xml中sql内容为: &l ...

  6. Golang的运算符-位运算符

    Golang的运算符-位运算符 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.位运算符概述 常见的位逻辑运算符: &: 位与运算符,表示AND(表示所有条件都得匹配), ...

  7. js实现连续输入之后发送请求

    输入框是我们经常会用到的功能,想要实现输入就请求的功能 但是在实际开发中,为了减少服务器压力,会在输入之后停留1s没有输入之后再进行搜索 研究之后用原生js及表单写了一个简单的demo,如果有好的de ...

  8. asp.net mvc邮箱激活

    1.发送邮件 public ActionResult SendEmail() { var member = dbSession.MemberRepository.LoadEntities(p => ...

  9. Rabbitmq之高级特性——百分百投递消息&消息确认模式&消息返回模式实现

    rabbitmq的高级特性: 如何保障消息的百分之百成功? 要满足4个条件:生产方发送出去,消费方接受到消息,发送方接收到消费者的确认信息,完善的消费补偿机制 解决方案,1)消息落库,进行消息状态打标 ...

  10. mysql基本知识的总结

    Mysql基本sql知识 Navicat快捷方式: 选中当前行 在行尾:shift+home 在行首:shift+end 执行当前行:ctrl+shift+R 复制当前行:ctrl+D 显示所有数据库 ...