當(dāng)元素的個(gè)數(shù)是動(dòng)態(tài)的,,就應(yīng)使用集合類,集合類一般有List<T>,ArrayList,、數(shù)組,、隊(duì)列,、堆棧、鏈表等,。下面來介紹各種集合的使用方法,。 9.1 列表 對(duì)象類型的集合主要位于System.collections命名空間中;泛型集合主要是在System.collections.Generic命名空間中,,當(dāng)然List <T>肯定也都在給命名空間下,,下面來介紹列表的使用 1.列表初始化 List<int> intList = new List<int>() { 1, 2 }; 定義一個(gè)int類型的列表。 2.添加一個(gè)元素 intList.Add(3);
3.添加多個(gè)元素 intList.AddRange(new int[] { 4, 5 }); AddRange方法的參數(shù)是一個(gè)IEnumerable<T>類型的對(duì)象,,當(dāng)然也可以傳送一個(gè)數(shù)組,,上面示例即傳送數(shù)組。 4.訪問元素 訪問元素和訪問數(shù)組很類似的,,主要是list<T>都提供了一個(gè)索引器,,也就是繼承了ICollection接口,由于已經(jīng)提供了索引器了,,那么我們就可以像訪問數(shù)組那樣訪問數(shù)據(jù),。 int i=intList[0]; 5.遍歷數(shù)據(jù) 一種是可以使用for來循環(huán)迭代集合中的每個(gè)元素,使用索引器來訪問數(shù)據(jù),,另一種是使用ForEach主要是Ilist<T>同時(shí)也繼承了接口IEnumerable,,該接口主要是用來迭代數(shù)據(jù)的。 如下面代碼:
Console.WriteLine("For Loop");
for (int i = 0; i < intList.Count;i++) { Console.WriteLine(intList[i]); } Console.WriteLine("ForEach Loop"); foreach(int i in intList) { Console.WriteLine(i.ToString()); } 9.2 隊(duì)列 隊(duì)列是其元素以先進(jìn)先出的方式處理集合,。先放進(jìn)在隊(duì)列的元素會(huì)先讀取 ,。隊(duì)列的例子很多的,我們常見的就是排隊(duì),,排在前面的先服務(wù),,后來的后服務(wù)。 隊(duì)列和列表的主要區(qū)別在于隊(duì)列沒有執(zhí)行IList接口,,所有不能用索引器訪問隊(duì)列,。只能添加元素,下面給出個(gè)例子來: 隊(duì)列demo
//隊(duì)列的使用
public class DocumentManager { private readonly Queue<Document> documentQueue = new Queue<Document>();//定義一個(gè)只讀的隊(duì)列 public void AddDocument(Document doc) { lock (this) { documentQueue.Enqueue(doc);//隊(duì)列尾部添加元素 } } public Document GetDocument() { Document doc = null; lock (this) { doc = documentQueue.Dequeue();//隊(duì)列頭部獲得元素 } return doc; } public bool IsDocumentAvailable { get { return documentQueue.Count > 0;//判斷隊(duì)列是否有元素 } } } 9.3 棧 棧和隊(duì)列是非常相似的集合,,只是棧是后進(jìn)先出而已,。 棧Demo
Stack<char> alphalist = new Stack<char>();
alphalist.Push('A'); alphalist.Push('B'); foreach(char a in alphalist) { Console.WriteLine(a); } 說明:由上面的例子可以得出,輸入A,B,輸出結(jié)果為B,,A,,那么可以得出棧是后進(jìn)先出,。 9.4 鏈表 LinkedList<T>是一個(gè)雙向鏈表,其元素指向他的前后的元素,。鏈表的優(yōu)點(diǎn)是,,能夠快速插入列表中間的數(shù)據(jù)。缺點(diǎn)就是查找速度比較慢,。 9.5 有序表 SortList<TKey,Tvalue>,,這個(gè)類按照鍵值給元素排序 有序表demo
SortedList<string, string> sortList = new SortedList<string, string>();
sortList.Add("1", "demo"); sortList.Add("2", "demo2"); foreach(KeyValuePair<string,string> m in sortList) { Console.WriteLine("{0},{1}", m.Key, m.Value); } 9.6 字典 字典表示一種復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。字典也成為隱射或散列表,。字典的特性是能夠快速查找值,,也可以自由添加和刪除元素。并且沒有在內(nèi)存中移動(dòng)后續(xù)元素的性能開銷,。 用作字典中的鍵的類型必須重寫object類得GetHashCode方法,。只要字典類需要確定元素的位置,就要調(diào)用GetHashCode方法,。該方法返回的Int由字典用于計(jì)算放置元素的索引,。另外鍵類型還必須執(zhí)行IEquality.Equals的方法或重寫object的equals方法,主要是防止不同鍵值對(duì)象可能返回相同的散列碼,,所以字典使用Equals方法來比較鍵,。下面給出個(gè)示例: 字典demo
[Serializable]
public struct EmployeeId : IEquatable<EmployeeId> { private readonly char prefix; private readonly int number; public EmployeeId(string id) { if (id == null) throw new ArgumentNullException("id"); prefix = (id.ToUpper())[0]; int numLength = id.Length - 1; number = int.Parse(id.Substring(1, numLength > 6 ? 6 : numLength)); } public override string ToString() { return prefix.ToString() + string.Format("{0,6:000000}", number); } public override int GetHashCode() { return (number ^ number << 16) * 0x15051505; } public bool Equals(EmployeeId other) { return (prefix == other.prefix && number == other.number); } public override bool Equals(object obj) { if (!(obj is EmployeeId)) return false; return Equals((EmployeeId)obj); } public static bool operator ==(EmployeeId emp1, EmployeeId emp2) { return emp1.Equals(emp2); } public static bool operator !=(EmployeeId emp1, EmployeeId emp2) { return !emp1.Equals(emp2); } } [Serializable] public class Employee { private string name; private decimal salary; private readonly EmployeeId id; public Employee(EmployeeId id, string name, decimal salary) { this.id = id; this.name = name; this.salary = salary; } public override string ToString() { return String.Format("{0}: {1, -20} {2:C}", id.ToString(), name, salary); } } class Program { static void Main() { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); Dictionary<EmployeeId, Employee> employees = new Dictionary<EmployeeId, Employee>(31); EmployeeId idJeff = new EmployeeId("C7102"); Employee jeff = new Employee(idJeff, "Jeff Gordon", 5164580.00m); employees.Add(idJeff, jeff); Console.WriteLine(jeff); EmployeeId idTony = new EmployeeId("C7105"); Employee tony = new Employee(idTony, "Tony Stewart", 4814200.00m); employees.Add(idTony, tony); Console.WriteLine(tony); EmployeeId idDenny = new EmployeeId("C8011"); Employee denny = new Employee(idDenny, "Denny Hamlin", 3718710.00m); employees.Add(idDenny, denny); Console.WriteLine(denny); EmployeeId idCarl = new EmployeeId("F7908"); Employee carl = new Employee(idCarl, "Carl Edwards", 3285710.00m); employees[idCarl] = carl; Console.WriteLine(carl); EmployeeId idMatt = new EmployeeId("F7203"); Employee matt = new Employee(idMatt, "Matt Kenseth", 4520330.00m); employees[idMatt] = matt; Console.WriteLine(matt); while (true) { try { Console.Write("Enter employee id (X to exit)> "); string userInput = Console.ReadLine(); userInput = userInput.ToUpper(); if (userInput == "X") break; EmployeeId id = new EmployeeId(userInput); Employee employee; if (!employees.TryGetValue(id, out employee)) { Console.WriteLine("Employee with id {0} does not exist", id); } else { Console.WriteLine(employee); } } catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); } } } } 9.7 HashSet 這個(gè)集合類包含了不重復(fù)項(xiàng)的無序列表。能夠很方便的插入元素,,該類還提供合集和交集,。下面給出簡(jiǎn)單例子: 哈希集合demo
using System;
using System.Collections.Generic; using System.Linq; using System.Text; namespace Wrox.ProCSharp.Collections { class Program { static void Main() { HashSet<string> companyTeams = new HashSet<string>() { "Ferrari", "McLaren", "Toyota", "BMW", "Renault", "Honda" }; HashSet<string> traditionalTeams = new HashSet<string>() { "Ferrari", "McLaren" }; HashSet<string> privateTeams = new HashSet<string>() { "Red Bull", "Toro Rosso", "Spyker", "Super Aguri" }; //添加沒有重復(fù),返回true 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 a subset of companyTeams"); } //超集 if (companyTeams.IsSupersetOf(traditionalTeams)) { Console.WriteLine("companyTeams is a superset of traditionalTeams"); } traditionalTeams.Add("Williams"); //至少有一個(gè)元素相同 if (privateTeams.Overlaps(traditionalTeams)) { Console.WriteLine("at least one team is the same with the traditional and private teams"); } HashSet<string> allTeams = new HashSet<string>(companyTeams); //添加全部?jī)?nèi)容到集合中去 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); } } } } 9.8 位數(shù)組 當(dāng)我們遇到位運(yùn)算時(shí)候,,可以使用BitArray類來處理,,該類可以重新設(shè)置大小,不需要知道位數(shù),,類bitArray是一個(gè)引用類型,,包含一個(gè)int數(shù)組,每32位使用一個(gè)新的整形,。主要提供了,,或 、與,、異或操作,,以及倒置位的值等方法,下面給出例子: 位數(shù)組demo
using System;
using System.Collections.Generic; using System.Text; using System.Collections; using System.Collections.Specialized; namespace BitArraySample { class Program { static void BitArrayDemo() { BitArray bits1 = new BitArray(8); bits1.SetAll(true); bits1.Set(1, false); bits1[5] = false; bits1[7] = false; Console.Write("initialized: "); DisplayBits(bits1); Console.WriteLine(); DisplayBits(bits1); bits1.Not(); Console.Write(" not "); DisplayBits(bits1); Console.WriteLine(); BitArray bits2 = new BitArray(bits1); bits2[0] = true; bits2[1] = false; bits2[4] = true; DisplayBits(bits1); Console.Write(" or "); DisplayBits(bits2); Console.Write(" : "); bits1.Or(bits2); DisplayBits(bits1); Console.WriteLine(); DisplayBits(bits2); Console.Write(" and "); DisplayBits(bits1); Console.Write(" : "); bits2.And(bits1); DisplayBits(bits2); Console.WriteLine(); DisplayBits(bits1); Console.Write(" xor "); DisplayBits(bits2); bits1.Xor(bits2); Console.Write(" : "); DisplayBits(bits1); Console.WriteLine(); } static void BitVectorDemo() { BitVector32 bits1 = new BitVector32(); int bit1 = BitVector32.CreateMask(); int bit2 = BitVector32.CreateMask(bit1); int bit3 = BitVector32.CreateMask(bit2); int bit4 = BitVector32.CreateMask(bit3); int bit5 = BitVector32.CreateMask(bit4); bits1[bit1] = true; bits1[bit2] = false; bits1[bit3] = true; bits1[bit4] = true; Console.WriteLine(bits1); bits1[0xabcdef] = true; Console.WriteLine(bits1); int received = 0x79abcdef; BitVector32 bits2 = new BitVector32(received); Console.WriteLine(bits2); // sections: FF EEE DDD CCCC BBBBBBBB AAAAAAAAAAAA BitVector32.Section sectionA = BitVector32.CreateSection(0xfff); BitVector32.Section sectionB = BitVector32.CreateSection(0xff, sectionA); BitVector32.Section sectionC = BitVector32.CreateSection(0xf, sectionB); BitVector32.Section sectionD = BitVector32.CreateSection(0x7, sectionC); BitVector32.Section sectionE = BitVector32.CreateSection(0x7, sectionD); BitVector32.Section sectionF = BitVector32.CreateSection(0x3, sectionE); Console.WriteLine("Section A: " + IntToBinaryString(bits2[sectionA], true)); Console.WriteLine("Section B: " + IntToBinaryString(bits2[sectionB], true)); Console.WriteLine("Section C: " + IntToBinaryString(bits2[sectionC], true)); Console.WriteLine("Section D: " + IntToBinaryString(bits2[sectionD], true)); Console.WriteLine("Section E: " + IntToBinaryString(bits2[sectionE], true)); Console.WriteLine("Section F: " + IntToBinaryString(bits2[sectionF], true)); } static string IntToBinaryString(int bits, bool removeTrailingZero) { StringBuilder sb = new StringBuilder(32); for (int i = 0; i < 32; i++) { if ((bits & 0x80000000) != 0) { sb.Append("1"); } else { sb.Append("0"); } bits = bits << 1; } string s = sb.ToString(); if (removeTrailingZero) return s.TrimStart('0'); else return s; } static void Main() { BitVectorDemo(); BitArrayDemo(); } static void DisplayBits(BitArray bits) { foreach (bool bit in bits) { Console.Write(bit ? 1 : 0); } } } } 小結(jié): 本章節(jié)講了關(guān)于不同集合處理,,數(shù)組的大小是固定的,,但可以使用列表作為動(dòng)態(tài)增加的集合。隊(duì)列先進(jìn)先出的方式訪問元素,,可以使用在很多特定場(chǎng)合,。棧以后進(jìn)先出的方式訪問元素。鏈表可以快速的插入和刪除元素,,但是查詢操作就慢很多,。字典查詢和插入操作比較快。hashSet可以用于無序的唯一項(xiàng),。位數(shù)組可以使用在二進(jìn)制運(yùn)算的特定場(chǎng)所,。至于各個(gè)集合的性能問題,需要在使用時(shí)候特別考慮下,。性能問題請(qǐng)參考yangjun寫的C#六種集合性能比較 |
|