C#容器類,效能介紹

☆綠茶☆發表於2017-03-09

http://www.php.cn/csharp-article-354819.html

1 indexer

 

  []宣告的變數必須是固定長度的,即長度是靜態的;object[] objectArray = new object[10]; 
objectArray是淺複製,即只在memory中給其賦一個地址值,此時每一item此時都是null引用;

  應用舉例

1
2
3
4
5
6
7
8
AdjustablePanel[] adjustPanelArrays = new AdjustablePanel[12];    
foreach (Control ultraControl in this.Controls)
       {                if (ultraControl.GetType() == typeof(UltraGrid) ||
            ultraControl.GetType() == typeof(UltraChart) ||   ultraControl.GetType() == typeof(Panel))
           {                //adjustPanelArrays[index]此時為null,因此會出現null引用bug
               adjustPanelArrays[index].Controls.Add(ultraControl);
           }
       }

2 Array

  提供建立、操作、搜尋和排序陣列的方法,因而在公共語言執行時用作所有陣列的基類。長度是固定的,不能按需動態增加;Array 是抽象類,不能使用 new Array 建立;GetValue返回的是object型別。

1
2
3
4
5
Array myArray = Array.CreateInstance(typeof(int),3);
myArray.SetValue(1,0);
myArray.SetValue(2,1);
myArray.SetValue(3,2);            //GetValue返回的是object型別,需要進行型別提升為int
int val2 = (int)myArray.GetValue(2);

3 ArrayList

  使用大小可按需動態增加的陣列實現 IList 介面,且是針對任意型別。

1
2
3
4
5
6
7
8
ArrayList al = new ArrayList();
ArrayList arrayList = new ArrayList();
al.Add("qaz");
al.Add(1);
al.Add(new List<object>());           
string str = (string)al[0];           
int intval = (int)al[1];
List<object> objs = (List<object>)al[2];

總結 
   [], Array 編譯前需要已知長度,是靜態的,型別需要唯一確定的,Array是抽象類,建立需要Array.CreateInstance(); 
   ArrayList 編譯時長度未知,是動態的,並且新增的元素可以是不同的型別。

4 List-APIs

4-1 簡介

List< T>是一個泛型類,實現了介面IList< T>,通過內部使用一個size動態調整的陣列來顯示外部的介面。

4-2 增加元素

實現新增一個元素

1
Add(obj)

批量新增元素到列表中:

1
AddRange(objList)

舉例:

1
2
3
4
5
private List<int> intList = new List<int>();        public void AddApi()
{
    intList.Add(10); //新增1個元素
    intList.AddRange(new List<int>() { 5, 1, 1, 2, 2, 3 }); //批量新增元素
}

將集合中的某個元素插入指定索引處

1
void Insert(int index, T item);
1
void InsertRange(int index, IEnumerable《T》 collection)

4-3移除元素

假定intList是一個List型別,初始值為 {10,5,1,1,2,2,3}。執行:

1
intList.Remove(1);

從intList中移除特定物件的第一個匹配項。移除元素1後,intList = {10,5,1,2,2,3};

移除一定範圍的元素 :

1
intList.RemoveRange(0, 2);

intList = {2,2,3};

移除所有重複元素後:intList = {3};

1
2
3
4
intList.RemoveAll(removeDuplicateElements);
intList.RemoveAll(i =>
{                List<int> elementList = intList.FindAll(r => r.Equals(i));                if (elementList != null && elementList.Count > 1)                    return true;                return false;
});

在以上判斷某個元素是否存在時,比如移除某個元素時,需要用到相等比較器。如果型別T實現了IEquatable< T> 泛型介面,相等比較器就是 Equals(T) 方法; 否則, 預設的相等比較器是 Object.Equals(Object).

下面看一個不是預設的比較器,實現介面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MyObject
{        public int Value { getset; }       
public MyObject(int value)
    {            this.Value = value;
    }
}    //實現介面IEquatable<MyObject>
public class MyObjectCollection : IEquatable<MyObject>
{        private List<MyObject> _myObjects = new List<MyObject>()
    {            new MyObject(3),           
    new MyObject(4),           
    new MyObject(3),           
    new MyObject(2),          
     new MyObject(3)
    };        //刪除所有重複的元素
    public void RemoveDuplicates()
    {
        _myObjects.RemoveAll(Equals);
    }        public List<MyObject> MyObjects
    {            get
        {                return _myObjects;
        }
    }
 
    public bool Equals(MyObject other)
    {
        MyObject duplicate = _myObjects.Find(r => r.Value == other.Value);           
        if (duplicate != null && duplicate!=other)               
        return true;           
        return false;
    }
}

此處實現了Equals(object),但是Remove(test)暫時是失敗的,以後找原因。

4-4查詢元素

確定某元素是否在List 中。

1
bool Contains(obj)

確定是否包含與指定謂詞所定義的條件相匹配的元素。

1
bool Exists(Predicate<T> match)

搜尋與指定謂詞所定義的條件相匹配的元素,並返回第一個匹配元素。

1
T Find(Predicate<T> match)

檢索與指定謂詞定義的條件匹配的所有元素。

1
List<T> FindAll(Predicate<T> match)

搜尋與指定謂詞所定義的條件相匹配的元素,並返回第一個匹配元素的從零開始的索引

1
int FindIndex(Predicate<T> match)

搜尋與指定謂詞所定義的條件相匹配的元素,並返回從指定索引到最後一個元素的元素範圍內第一個匹配項的從零開始的索引。

1
int FindIndex(int startIndex, Predicate<T> match)

搜尋與指定謂詞所定義的條件相匹配的元素,並返回從指定的索引開始幷包含指定元素數量的元素範圍內的第一個匹配項的零始索引

1
int FindIndex(int startIndex, int count, Predicate<T> match)
1
T FindLast(Predicate<T> match)
1
int FindLastIndex(Predicate<T> match)
1
int FindLastIndex(int startIndex, Predicate<T> match)
1
int FindLastIndex(int startIndex, int count, Predicate<T> match)

搜尋指定的物件,並返回第一個匹配項的從零開始的索引

1
int IndexOf(T item)

搜尋指定的物件,並返回從指定索引到最後一個元素的元素範圍內第一個匹配項的從零開始的索引

1
int IndexOf(T item, int index)
1
int IndexOf(T item, int index, int count)

搜尋指定的物件,並返回最後一個匹配項的從零開始的索引。

1
int LastIndexOf(T item)
1
int LastIndexOf(T item, int index)
1
int LastIndexOf(T item, int index, int count)

4-5二分查詢

使用預設的比較器在整個已排序的List中搜尋元素,並返回該元素從零開始的索引。

1
int BinarySearch(T item);

使用指定的比較器在整個已排序的List中搜尋元素,並返回該元素從零開始的索引。

1
int BinarySearch(T item, IComparer<T> comparer)
1
int BinarySearch(int index, int count, T item, IComparer<T> comparer)

4-6排序

使用預設比較器對整個List中的元素進行排序。

1
void Sort()

使用指定的 System.Comparison 對整個 List中的元素進行排序。

1
void Sort(Comparison<T> comparison)

使用指定的比較器對List中的元素進行排序。

1
void Sort(IComparer<T> comparer)
1
void Sort(int index, int count, IComparer<T> comparer)

4-7效能分析

操作時間複雜度
Add O(1)或O(n)
Insert O(n)
Remove O(n)
GetAnItem O(1)
Sort O(nlogn),最壞O(n^2)
Find O(n)

4-8 附使用陷阱點:

1 list.Min() 和 list.Max() 和 Average()等Linq方法,當list元素個數為0,則會出現“序列不包含任何元素”的異常。

2 object.ToString() 使用前要檢測object是否為null。

3 Foreach遍歷時,迭代器是不允許增加或刪除的。例如:

1
2
3
4
5
6
7
8
9
10
public List<MDevice> GetNormalDevices(List<MDevice> devices)
   {
       rtnDevices = devices;        foreach (var device in devices)
       {            var tmpdevices = bslMDevice.GetMDeviceByDeviceCode(device.DeviceCode);           
       if (!devices[0].IsNormal)
           {            //這是非法的,因為移除rtnDevices列表的一個元素,等價於移除devices列表。
               rtnDevices.Remove(device);
           }
       }
   }

5 SortedList

5-1 SortedList簡介

Sorted表明了它內部實現自動排序,List表明了它有點像List,可以通過index訪問集合中的元素。

5-2 內部實現機理

一個SortedList物件內部維護了2個陣列,以此來儲存元素,其中一個陣列用來存放鍵(keys),另一個存放鍵關聯的值(values)。每一個元素都是鍵值對(key/value pair)。key不能是null,value可以。

5-3 總結API

5-3-1 Capacity

一個SortedList物件的容量是SortedList能容納的元素數,這個值是動態變化,自動調整的。如下所示:

1
2
3
4
5
6
SortedList mySL = new SortedList();
mySL.Add("Third""!");
mySL.Add("Second""World");
mySL.Add("First""Hello");
Console.WriteLine( "mySL" );
Console.WriteLine( "  Capacity: {0}", mySL.Capacity );

此時Capacity: 16

如果新增到mySL中的元素增多,相應的Capacity會相應的自動變大。

5-3-2 訪問元素

通過index訪問

SortedList物件要想通過index訪問,需要使用建構函式SortedList() 或 SortedList(IComparer icompared)。

1
2
3
4
SortedList sortedList = new SortedList();
sortedList.Add(3,"gz");
sortedList.Add(9, "lhx");
sortedList.Add(3, "gz");object getByIndex = sortedList.GetByIndex(2);
通過key訪問

SortedList物件要想通過key訪問,需要使用帶有TKey,TValue的泛型建構函式。

1
2
3
SortedList<int,string> sortedList = new SortedList<int,string>();
sortedList.Add(3,"gz");
sortedList.Add(9, "lhx");object getByIndex = sortedList[3];

5-3-3排序

SortedList有一種預設的比較順序,比如下面的程式碼:

1
2
3
SortedList<int,string> sortedList = new SortedList<int,string>();
sortedList.Add(9,"gz");
sortedList.Add(3, "lhx");

結果是 sortedList中第一個對是3,”lhx”

如果不想按照預設的排序順序,需要自己在構造時定製一種排序順序,如下面的程式碼:

實現排序介面

新建一個私有排序類,實現介面IComparer

1
2
3
4
5
private class ImplementICompare: IComparer<int>
  {      public int Compare(int x, int y)
      {          return x < y ? 1 : -1;
      }
  }
構造SortedList
1
2
3
4
ImplementICompare impleCompare = new ImplementICompare();
SortedList<intstring> sortedList = new SortedList<intstring>(impleCompare);
sortedList.Add(9,"gz");
sortedList.Add(3, "lhx");

按照鍵從大到小的順序排序,結果是 sortedList中第一個對是9,”gz”

5-3-4 新增元素

用add介面實現新增某個元素到集合中,不允許重複新增相同鍵。

1
2
3
SortedList<int,string> sortedList = new SortedList<int,string>();
sortedList.Add(9,"gz");
sortedList.Add(3, "lhx");

5-3-5 移除元素

移除集合中指定元素Remove(object removedElement);指定index處移除元素RemoveAt(int index)。

Remove(object)
1
2
3
4
5
6
SortedList mySL = new SortedList();
mySL.Add( "3c""dog" );
mySL.Add( "2c""over" );
mySL.Add( "3a""the" );
mySL.Add( "3b""lazy" );  
mySL.Remove( "3b" ); //sucessful to remove
1
2
3
SortedList<intstring> sortedList = new SortedList<intstring>();
sortedList.Add(9,"gz");
sortedList.Add(3, "lhx");bool removedFlag = sortedList.Remove(3); //true
1
2
3
4
ImplementICompare impleCompare = new ImplementICompare();
SortedList<intstring> sortedList = new SortedList<intstring>(impleCompare);
sortedList.Add(9,"gz");
sortedList.Add(3, "lhx");bool removedFlag = sortedList.Remove(3); //false

這是需要注意的一個地方,構造器帶有impleCompare實現了排序介面時,好像不能移除某個元素,需要待確認。

RemoveAt(int index)
1
2
3
4
SortedList sorted = new SortedList();
sorted.Add(9, "gz");
sorted.Add(3, "lhx");
sortedList.RemoveAt(1); //在排序後的位置移除,sortedList的一個對的鍵 為3,第二個對的鍵為9,因此移除了9這個鍵值對

5-4 效能

一個SortedList的操作相比Hashtable物件是要慢些的,由於它實現了排序功能。但是,SortedList提供了訪問的方便性,由於既可以通過index,也可以通過key去訪問元素。

6 .net容器相關介面

介面描述
IEnumerable< T> 實現foreach語句需要實現此介面,介面方法GetEnumerator返回列舉器。
ICollection< T> 方法:Count屬性,CopyTo(Array),Add, Remove, Clear
IList< T> 定義了indexer,Insert, RemoveAt方法,繼承ICollection< T>
ISet< T> 方法:求並集,交集,繼承於ICollection< T>
IDictionary< TKey, TValue> 有key和value的集合實現
ILookup< TKey, TValue> 類似上,允許multiple values with one key.
IComparer< T> comparer實現,排序比較的規則
IEqualityComparer< T> 物件be compared for equality另一個物件
IProducerConsumerCollection< T> thread-safe collection classes

 

 

7 介面UML

 


這裡寫圖片描述

 

8 各個容器時間複雜度

 

集合型別AddInsertRemoveItemSortFind
List< T> O(1)或O(n) O(n) O(n) O(1) O(nlogn) O(n)
Stack< T> O(1)或O(n) 不適用 pop() O(1) 不適用 不適用 不適用
Queue< T> O(1)或O(n) 不適用 O(1) 不適用 不適用 不適用
HashSet< T> O(1)或O(n) O(1)或O(n) O(1) 不適用 不適用 不適用
LinkedList< T> O(1) O(1) O(1) O(n) 不適用 O(n)
Dictionary<, > O(1)或O(n) 不適用 O(1) O(1) 不適用 不適用
SortedDictionary<,> O(logn) 不適用 O(logn) O(logn) 不適用 不適用
SortedList<,> O(logn) 不適用 O(n) O(logn) 不適用 不適用

相關文章