话说 虽然敲过好多代码, 但除了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类提供了列表中的元素发生变化时触发的事件。
- 【转】apue《UNIX环境高级编程第三版》第一章答案详解
原文网址:http://blog.csdn.net/hubbybob1/article/details/40859835 大家好,从这周开始学习apue<UNIX环境高级编程第三版>,在此 ...
- C#高级编程第11版 - 第六章 索引
[1]6.2 运算符 1.&符在C#里是逻辑与运算.管道符号|在C#里则是逻辑或运算.%运算符用来返回除法运算的余数,因此当x=7时,x%5的值将是2. [2]6.2.1 运算符的简写 1.下 ...
- C#高级编程第11版 - 第五章 索引
[1]5.1 泛型概述 1.通过泛型,你可以创建独立于特定类型(contained types)以外的方法和类,而不用为不同类型编写多份同样功能的代码,你只需要创建一个方法或者类. 2.泛型类使用泛型 ...
- C#高级编程第11版 - 第三章 索引
[1]3.1 创建及使用类 1.构造函数:构造函数的名字与类名相同: 使用 new 表达式创建类的对象或者结构(例如int)时,会调用其构造函数.并且通常初始化新对象的数据成员. 除非类是静态的,否则 ...
- C#高级编程 (第六版) 学习 第二章:C#基础
第二章 基础 1,helloworld示例: helloworld.cs using System; using System.Collections.Generic; using System.Li ...
- C#高级编程 (第六版) 学习 第一章:.Net体系结构
第一章 .Net体系结构 1,公共语言运行库(Common Language Runtime, CLR) .Net Framework的核心是其运行库的执行环境,称为公共语言运行库,或.Net运行库. ...
- C#高级编程第11版 - 第七章 索引
[1]7.1 相同类型的多个对象 1.假如你需要处理同一类型的多个对象,你可以使用集合或者数组. 2.如果你想使用不同类型的不同对象,你最好将它们组合成class.struct或者元组. [2]7.2 ...
- C#高级编程第11版 - 第四章 索引
[1]4.2 继承的类型 1.C#不支持类的多继承,但它支持一个接口继承自多个接口. 2.单继承:单继承允许一个类继承自另外一个基类,C#支持. 3.多级继承:多级继承允许创建一个类继承自它的父类,而 ...
- javascript高级程序设计第3版——第10章 DOM
第十章,DOM DOM是语言中立的API,用于访问和操作HTML 和XML 文档.DOM1 级将HTML 和XML 文档形象地看作一个层次化的节点树,可以使用JavaScript 来操作这个节点树,进 ...
随机推荐
- 吴裕雄--天生自然JAVA面向对象高级编程学习笔记:接口的基本实现
interface A{ // 定义接口A public static final String AUTHOR = "李兴华" ; // 全局常量 public abstract ...
- python-python基础3
本章内容: 函数 递归 高阶函数 一.函数 一个函数一般完成一项特定的功能 函数使用 函数需要先定义 使用函数,调用
- JMeter学习-图形化 HTML 报表概要说明
JMeter 3.0开始支持动态生成图形化 HTML dashboard报告,当前生成报告有一下两种方式: 1.脚本测试执行结束后,即生成HTML测试报告 2.通过之前生成的测试结果,生成HTML测试 ...
- 实训41 S7通信 单向连接 基于DP网络通信
连接的基本概念? 连接是指两个通信伙伴之间执行通信服务建立的逻辑链路,而不是指两个站之间用物理媒体(例如电缆)实现的连接. 连接相当于 通信伙伴之间 一条虚拟的"专线". 一条物理 ...
- 使用PYaudio录制音频和视频(自己)
参考:https://blog.csdn.net/zhaoyun_zzz/article/details/84341801 音频录制:简洁版 import pyaudioimport waveimpo ...
- Element 以二进制的形式 自定义上传图片
一,只有在上传文件之前的钩子函数中才可以获得最初的文件(文件本身的二进制形式),用以以上传服务器. 还需要使用formdata来承载数据,便于接收 <template> <div ...
- 02.swoole学习笔记--UDP服务器
<?php //创建服务器 $serv=,SWOOLE_PROCESS,SWOOLE_SOCK_UDP); //bool $swoole_server->on(string $event, ...
- class(二)--派生类的继承
前言 从我之前的一篇笔记对象的继承中, 我们可以知道JS的继承方式依赖原型链,而比较好的继承方式是寄生组合式继承 先来温习下什么是寄生组合式继承 function Rectangle(length, ...
- 接口测试基础----postman、jmeter
一,什么是接口 接口一般接口分两种: 系统对外接口:与外部系统对接的接口,用来获取或者传递数据给外部系统 系统内部接口:系统模块.方法之间用来获取或者传递数据的接口 二.接口分类 webservice ...
- c++输出哈夫曼编码
#include<iostream> #include<string> using namespace std; struct huffTree { int parent; i ...