1. 程式人生 > >C#高階程式設計五十四天----Lookup類和有序字典

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

情況ToLookup方法非常有用,ToLookup返回一種特殊的資料結構,類似SQL中的group,可以把集合分組並且可以用索引訪問這些元素,案例:

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型別的陣列

            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類在插入和刪除未排序的資料時比較快.

詳細分析SOrtedListSortedDictionary類的不同,SortedList內部用陣列儲存,只能算是有序線性表,SortedSictionary的內部結構是紅黑樹(這是一種資料結構,不懂得自己去百度).

SortedDictionary內部結構是紅黑樹,紅黑樹的平衡二叉樹的一種,SortedList是有序線性表,內部結構是Array,運用了二分查詢法提高效率.從兩者查詢,插入,刪除操作的時間複雜度來看,都為O(LogN),分辨不出優劣,但內部結構的不同導致了實際操作的效能差異.

SortedListSortedDictionary效能比較----插入

由於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的隨機陣列,分別用SortedListSortedDictionary新增.

結論:在大量新增操作的情況下,SortedDictionary效能優於DortedList.

SortedListSortedDictionary效能比較----查詢

兩者的查詢操作中,事件複雜度都為O(LogN),且原始碼中也沒有額外的操作造成效能損失.

經過測試得出:兩者在迴圈10W次的情況下,僅僅相差幾十毫秒,可以看出兩者的查詢操作效能相差不大.

SortedListSortedDictionary效能比較----刪除

從新增操作的案例可以看出,由於SortedList內部使用陣列進行儲存資料,而陣列本身的侷限性使得SortedList大部分的新增操作都要滴啊用Array.Copy方法,從而導致了效能的損失,這種情況同樣存在於刪除操作中.所以得出了:在大量刪除操作的情況下是,SortedDictionary的效能優於SortedList.

總結:SortedDictionary內部用紅黑樹儲存資料,SortedList用陣列儲存資料,兩者的查詢效率差不多,但由於陣列本身的限制,在大量新增刪除操作的情況下,SortedDictionary的效能優於SortedList.