C#高階程式設計五十四天----Lookup類和有序字典
Lookup類
Dictionary<Tkey,TValue>只為每個鍵支援一個值.新類Lookup<Tkey,TValue>是.NET3.5中新增的,它類似與Dictionary<Tkey,TElement>,但把鍵對映帶一個值集上.這個類在程式及System.Core中實現,用System,Linq名稱空間定義.
Lookup<Tkey,TElement>的方法和屬性如下表:
屬性名或者方法名 |
說明 |
Count |
屬性Count返回集合中的元素個數 |
Item |
使用索引器可以根據鍵訪問特定的元素.因為同一個鍵可以對應多個值 |
Contain() |
方法Contains()根據使用用Key引數傳送元素,返回一個布林值 |
ApplyResultSelector() |
ApplyResultSelector(0根據傳送給它的轉換函式,轉換每一項,返回一個集合 |
Loopup<TKey,TElement>不能像一般的字典那樣建立,而必須呼叫方法ToLookup(),它返回一個Lookup<TKey,TElement>物件.方法ToLookup()是一個擴充套件方法,可以用於實現了IEnumerable<T>的所有類.
當一個Key要求對應多個value
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lookup類
{
class Program
{
static void Main(string[] args)
{
//建立一個
string[] array = { "cat","dog","horse"};
//生成查詢結構
var lookup = array.ToLookup(item => item.Length);
//列舉字元長度3的串
foreach (var item in lookup[3])
{
Console.WriteLine("3 = "+item);
}
//列舉字元長度5的串
foreach (var item in lookup[5])
{
Console.WriteLine("5 = " + item);
}
//列舉分組
foreach (var grouping in lookup)
{
Console.WriteLine("Grouping : ");
foreach (var item in grouping)
{
Console.WriteLine(item);
}
}
Console.ReadKey();
}
}
}
上面的案例是通過陣列元素的字串長度為Key分組,也就是字元長度相同的元素的Key是一樣的,索引下標也是一樣.比如以通過lookup[3]訪問,而horse要用lookup[5]來訪問.
有序字典
SortedDictionary<TKey,TValue>類是一個二叉搜尋樹,其中的元素根據鍵來排序.該鍵型別必須實現IComparable<TKey>介面.如果鍵的型別不能排序,則還可以建立一個實現了IComparer<TKey>介面的比較器,將比較器用作有序字典的建構函式的一個引數.
SortedDictionary<TKey,TValue>類和SortedList<TKey,TValue>類的功能類似.但因為SortedList<TKey,TValue>實現為一個基於陣列的列表,而SortedDictionary<TKey,TValye>類實現為一個字典,所以他們有不同的特徵:
1.SortedList<Tkey,TValue>類使用的記憶體比SortedDictionary<TKey,TValue>類少
2.SortedDictionary<TKey,TValue>類的元素插入和刪除速度比較快
3.在用已排好序的資料填充集合時,若不需要修改容量,SortedList<TKey,TValue>類就比較快.
案例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 有序字典
{
class Program
{
static void Main(string[] args)
{
//SortedList<TKey,TValue>使用的記憶體少
//SortedDictionary<TKey,TValue>元素插入和刪除速度快
//鍵要實現IComparable<in T>介面
SortedDictionary<EmployeeID, Person> sd = new SortedDictionary<EmployeeID, Person>();
sd.Add(new EmployeeID(3),new Person("中國", "張飛", 40));
sd.Add(new EmployeeID(20), new Person("中國", "關羽", 43));
sd.Add(new EmployeeID(4), new Person("中國", "劉備", 45));
sd.Add(new EmployeeID(5), new Person("中國", "諸葛亮", 24));
sd.Add(new EmployeeID(1), new Person("美國", "豪威爾", 40));
sd.Add(new EmployeeID(0),new Person("美國", "奧巴馬", 40));
sd.Add(new EmployeeID(210), new Person("朝鮮", "金三胖", 40));
sd.Add(new EmployeeID(80), new Person("印度", "印度阿三", 40));
foreach (var item in sd)
{
Console.WriteLine(item.Key.ID+","+item.Value.Name);//鍵,正序排序
}
Console.ReadKey();
}
}
public class EmployeeID : IComparable<EmployeeID>
{
public int ID { get; private set; }
public EmployeeID(int id)
{
this.ID = id;
}
public int CompareTo(EmployeeID other)
{
return ID.CompareTo(other.ID);
}
}
public class Person
{
public string Country { get; private set; }
public string Name { get; private set; }
public int Age { get; private set; }
public Person(string country, string name, int age)
{
this.Country = country;
this.Name = name;
this.Age = age;
}
}
}
注意:SortedList類使用的記憶體比SortedDictionary類少,但SortedDictionary類在插入和刪除未排序的資料時比較快.
詳細分析SOrtedList和SortedDictionary類的不同,SortedList內部用陣列儲存,只能算是有序線性表,而SortedSictionary的內部結構是紅黑樹(這是一種資料結構,不懂得自己去百度).
SortedDictionary內部結構是紅黑樹,紅黑樹的平衡二叉樹的一種,SortedList是有序線性表,內部結構是Array,運用了二分查詢法提高效率.從兩者查詢,插入,刪除操作的時間複雜度來看,都為O(LogN),分辨不出優劣,但內部結構的不同導致了實際操作的效能差異.
SortedList和SortedDictionary效能比較----插入
由於SortedList用陣列儲存,每次進行插入操作時,首先用二分查詢發找到相應的位置,得到位置以後,SortedList會把該位置以後的值依次往後移動一個位置,空出當前位,再把值插入,這個過程用到了Array.Copy方法,而呼叫該方法是比較損耗效能的,程式碼如下:
private void Insert(int index,TKey key,TValue value)
{
...
if(index<this._size)
{
Array.Copy(this.keys.index,this.keys,index+1,this._size-index);
Array.Copy(this.values,index,this.values,index+1,this._size-index);
}
...
}
SortedDictionary在新增操作時,只會根據紅黑樹的特性,旋轉節點,保持平衡,並沒有對Array.Copy的呼叫.
測試程式碼:迴圈一個int型,容量為100000的隨機陣列,分別用SortedList和SortedDictionary新增.
結論:在大量新增操作的情況下,SortedDictionary效能優於DortedList.
SortedList和SortedDictionary效能比較----查詢
兩者的查詢操作中,事件複雜度都為O(LogN),且原始碼中也沒有額外的操作造成效能損失.
經過測試得出:兩者在迴圈10W次的情況下,僅僅相差幾十毫秒,可以看出兩者的查詢操作效能相差不大.
SortedList和SortedDictionary效能比較----刪除
從新增操作的案例可以看出,由於SortedList內部使用陣列進行儲存資料,而陣列本身的侷限性使得SortedList大部分的新增操作都要滴啊用Array.Copy方法,從而導致了效能的損失,這種情況同樣存在於刪除操作中.所以得出了:在大量刪除操作的情況下是,SortedDictionary的效能優於SortedList.
總結:SortedDictionary內部用紅黑樹儲存資料,SortedList用陣列儲存資料,兩者的查詢效率差不多,但由於陣列本身的限制,在大量新增刪除操作的情況下,SortedDictionary的效能優於SortedList.