一個數據庫表(id,name,…)中有10萬條記錄,查找name=’guoguo‘可能需要很長時間,但是如果對name建立了索引,那么再用name=’guoguo‘來查詢將變得非常快(有多快?自己可以去試試)。
相應的,有時候我們的代碼里面會用到List<T>,Array來存儲一組數據。我們以一個例子來說明一下。
定義數據類型:
public class UserInfo { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } }
示例代碼有個前提:name不會重復。從List中按照name找到對應的UserInfo可以用以下代碼:
List<UserInfo> _userinfos; public UserInfo GetUserInfoByName(string name) { for (int i = 0; i < _userinfos.Count; i++) { UserInfo ui = _userinfos[i]; if (ui.Name == name) { return ui; } } return null; } public UserInfo GetUserInfoByName_Find(string name) { return _userinfos.Find((temp) => { return temp.Name == name; }); }
兩個方法其實都是使用遍歷列表的方式去比較、查找;我做了實驗,如果列表中有10萬條記錄,分別執行“查找第5萬個元素”1000遍的耗時為:
GetUserInfoByName |
1877毫秒 |
GetUserInfoByName_Find |
2290毫秒 |
也就是說平均一次要2毫秒左右(Find效率還更低);
OK,接下來我們要試着借鑒數據庫的方式給List建立索引。
public List<UserInfo> Userinfos { get { return _userinfos; } set { _userinfos = value; MakeIndex(); } } Dictionary<string, UserInfo> _userIndex; /// <summary> /// 建立索引 /// </summary> private void MakeIndex() { Dictionary<string, UserInfo> userIndex = new Dictionary<string, UserInfo>(); foreach (var item in _userinfos) { userIndex.Add(item.Name, item); } _userIndex = userIndex; }
MakeIndex方法在Userinfos的set屬性器里面調用;那么查詢的方法就應該這么寫:
public UserInfo GetUserInfoByNameEx(string name) { return _userIndex[name]; }
這么簡單?對,就是這么簡單,而且,效率特別高。與上面的兩個方法一起進行比較:
建立索引+查找10萬次=36毫秒!
原因就是Dictionary[Key]方法的時間復雜度為O(1),幾乎不耗時。
注意:本示例為了代碼簡潔,對於key重復,null引用等等都沒有判斷,實際編碼過程中請注意考慮這些情況。
以下是示例的所有代碼:

using System; using System.Collections.Generic; using System.Diagnostics; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { List<UserInfo> userinfos = new List<UserInfo>(); //創建10萬個數據 for (int i = 0; i < 10 * 10000; i++) { UserInfo ui = new UserInfo(); ui.ID = i; ui.Name = Guid.NewGuid().ToString(); userinfos.Add(ui); } UserUtil util = new UserUtil(); //用於計時 Stopwatch sw = new Stopwatch(); sw.Start(); util.Userinfos = userinfos; sw.Stop(); Console.WriteLine(string.Format("建立索引MakeIndex耗時:{0}毫秒", sw.ElapsedMilliseconds)); //以第5萬個名字作為要查找的名字 string nameToFind = userinfos[5 * 10000].Name; sw.Reset(); sw.Start(); for (int i = 0; i < 1000; i++) { util.GetUserInfoByName(nameToFind); } sw.Stop(); Console.WriteLine(string.Format("執行1000次GetUserInfoByName耗時:{0}毫秒", sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); for (int i = 0; i < 1000; i++) { util.GetUserInfoByName_Find(nameToFind); } sw.Stop(); Console.WriteLine(string.Format("執行1000次GetUserInfoByName_Find耗時:{0}毫秒", sw.ElapsedMilliseconds)); sw.Reset(); sw.Start(); for (int i = 0; i < 10 * 10000; i++) { util.GetUserInfoByNameEx(nameToFind); } sw.Stop(); Console.WriteLine(string.Format("執行10萬次GetUserInfoByNameEx耗時:{0}毫秒", sw.ElapsedMilliseconds)); Console.ReadKey(); } } public class UserUtil { List<UserInfo> _userinfos; public List<UserInfo> Userinfos { get { return _userinfos; } set { _userinfos = value; MakeIndex(); } } Dictionary<string, UserInfo> _userIndex; public UserInfo GetUserInfoByName(string name) { for (int i = 0; i < _userinfos.Count; i++) { UserInfo ui = _userinfos[i]; if (ui.Name == name) { return ui; } } return null; } public UserInfo GetUserInfoByName_Find(string name) { return _userinfos.Find((temp) => { return temp.Name == name; }); } /// <summary> /// 建立索引 /// </summary> private void MakeIndex() { Dictionary<string, UserInfo> userIndex = new Dictionary<string, UserInfo>(); foreach (var item in _userinfos) { userIndex.Add(item.Name, item); } _userIndex = userIndex; } public UserInfo GetUserInfoByNameEx(string name) { return _userIndex[name]; } } public class UserInfo { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } } }