1. 程式人生 > >C#數組的使用

C#數組的使用

其中 clas 傳遞 mov 重要 img 繼承 使用下標 set

C#基礎語法中得數組,定義就是:數組是一種數據結構,包含同一個類型的多個元素。從CLR的角度來看,首先數組是引用類型,堆棧分配屬於分配於堆上,其次數組在內存中是連續的存儲的,所以索引速度很快,而且賦值與修改元素也很簡單。可以利用偏移地址訪問元素,時間復雜度為O(1);可以用折半查找法查找元素,效率高。

上面這段話初看之下很莫名奇妙,解釋一下,首先基礎語法定義了數組是什麽,是一種數據結構,數據結構有很多種:棧,隊列,列表,字典,樹,圖,數組也是這樣一種數據結構,而且是很多其他數據結構的基本,但是數組的內的數據類型只能是一種,在一個數組中不能既存在int又存在string

數組,ArrayList,List區別

在從CLR的角度來看,CLR介紹數組時,就從其派生自System.Array,而System.Array派生自Object,所以數組是引用類型,分配於托管堆上,並且數組在托管堆上分配到的是一塊連續存儲的內存,可以通過索引查找,雖然查詢的時間復雜度是O(1),但有個問題被忽略了,就是找的快未必就有用,數組分配在一塊連續的數據空間上,因此分配空間時必須確定大小。空間的連續,也導致了存儲效率低,插入和刪除元素效率比較低,而且麻煩。如果,要增添一個元素,需要移動大量元素,在內存中空出一個元素的空間,然後將要增加的元素放在其中。同樣,你想刪除一個元素,需要移動大量元素去填補被移動的元素。這就是數組的詬病,為了解決這個問題C#又推出了ArrayList

ArrayList是.Net Framework提供的用於數據存儲和檢索的專用類,它是命名空間System.Collections下的一部分。它的大小是按照其中存儲的數據來動態擴充與收縮的。所以,我們在聲明ArrayList對象時並不需要指定它的長度。但微軟又發現使用ArrayList存在一個更為致命的問題,看下面的代碼

技術分享
 1              //初始化ArrayList 
 2              ArrayList list = new ArrayList();
 3             //新增數據
 4             list.Add("
abc"); 5 list.Add(123); 6 //插入數據 7 list.Insert(0, "在第一個位置插入一條數據"); 8 foreach (var item in list) 9 { 10 Console.WriteLine(item); 11 }
View Code

在list中,我們不僅插入了字符串"abc",而且又插入了數字123。這樣在ArrayList中插入不同類型的數據是允許的。因為ArrayList會把所有插入其中的數據都當作為object類型來處理。這樣,在我們使用ArrayList中的數據來處理問題的時候,很可能會報類型不匹配的錯誤,也就是說ArrayList不是類型安全的。既使我們保證在插入數據的時候都很小心,都有插入了同一類型的數據,但在使用的時候,我們也需要將它們轉化為對應的原類型來處理。這就存在了裝箱與拆箱的操作,會帶來很大的性能損耗。

雖然ArrayList解決了數組長度問題,但是留下了類型安全問題,裝箱和拆箱操作一直是操作程序中所努力在避免的操作,因為其對性能的損耗確實是很大的,所以C#推出了Lits集合,下面的代碼是聲明實現一個List的集合,可以看到List指定了類型,避免了拆箱裝箱的操作,並且也無需指定元素個數。

技術分享
1      List<int> list = new List<int>();
2             //新增數據
3             list.Add(123);
4             //報錯,無法從string轉化成int
5             list.Add("123");
6             foreach (var item in list)
7             {
8                 Console.WriteLine(item);
9             }
View Code

事實上,List來自對ArrayList的封裝,而ArrayList封裝自數組,數組是ArrayList和List的底層實現,那麽是不是使用List就可以完美的代替數組了呢?以後所有的代碼都只需要寫成List就好了,既然List是來自數組的封裝,繼承了數組的所有方法和行為,其實這裏有一次回到了效率問題,如果是固定的並且知道其長度的數據集合用數組,而不固定長度的用List。額講了這麽多,或許就是這句話最重要吧。

創建下限非零的數組

C#中有兩種數組,一種是下表從0開始的數組,一種是下標非0開始的,不推薦使用下標非0開始的,通過下面的代碼就可以創建一個指定下限的多維數組

技術分享
 1   static void Main(string[] args)
 2         {
 3             // 創建和初始化多維數組字符串類型。
 4             int[] myLengthsArray = new int[2] { 3, 5 };
 5             int[] myBoundsArray = new int[2] { 2, 3 };
 6             //CreateInstance  創建指定下標的數組的方法
 7             //elementTypeType: System.Type要創建的 Array 的 Type。
 8             //一維數組,它包含要創建的 Array 的每個維度的大小。
 9             //一維數組,它包含要創建的 Array 的每個維度的下限(起始索引)。
10             Array myArray = Array.CreateInstance(typeof(String), myLengthsArray, myBoundsArray);
11 
12             for (int i = myArray.GetLowerBound(0); i <= myArray.GetUpperBound(0); i++)
13                 for (int j = myArray.GetLowerBound(1); j <= myArray.GetUpperBound(1); j++)
14                 {
15                     int[] myIndicesArray = new int[2] { i, j };
16                     myArray.SetValue(Convert.ToString(i) + j, myIndicesArray);
17                 }
18 
19             //顯示每一個維度的上限和下限
20             Console.WriteLine("Bounds:\tLower\tUpper");
21             for (int i = 0; i < myArray.Rank; i++)
22                 Console.WriteLine("{0}:\t{1}\t{2}", i, myArray.GetLowerBound(i), myArray.GetUpperBound(i));
23             // 顯示的值的數組。
24             Console.WriteLine("The Array contains the following values:");
25             PrintValues(myArray);
26         }
27         public static void PrintValues(Array myArr)
28         {
29             IEnumerator myEnumerator = myArr.GetEnumerator();
30             int i = 0;
31             int cols = myArr.GetLength(myArr.Rank - 1);
32             while (myEnumerator.MoveNext())
33             {
34                 if (i < cols)
35                 {
36                     i++;
37                 }
38                 else
39                 {
40                     Console.WriteLine();
41                     i = 1;
42                 }
43                 Console.Write("\t{0}", myEnumerator.Current);
44             }
45             Console.WriteLine();
46         }
View Code

數組的傳遞和返回

其實傳遞就是當作參數傳遞給函數,返回就是可以作為類型返回接收,但有個問題,數組是引用類型,開篇我們就介紹了,傳遞給函數,如果函數改動了數組,原數組就會跟著一起變,這肯定不是我們想要的。解決方案是可以直接復制一個數組,通過Array.Copy()方法,復制一個新的數組傳遞給函數體,如果不希望原數組被改動的話。

不安全的數組訪問

我們每次訪問一個數組中的元素時,CLR都會確保索引不會超出數組的上下限。CLR的索引檢查會有一些性能方面的代價。如果大家對自己的代碼有足夠的信心,並且不介意使用非安全代碼,則可在訪問一個數組時不讓CLR執行索引檢查。

技術分享
 1 //unsafe 開啟不安全訪問標誌
 2 //需要在你的項目屬性頁面裏面,把是否包含unsafe代碼的選項選上 
 3 //否則會報錯
 4 unsafe static void main()
 5 {
 6     Int32[] arr = new Int32{1, 2, 3, 4, 5};
 7     //獲取一個指向數組第0元素的指針
 8     fixed(Int32 * element = &arr[0])
 9     {
10         for(Int32 x = 0, n = arr.Length; x < n; x++)
11         {
12             Console.WriteLine(element[x]);
13         }
14     }
15 }
View Code

小結

今天的內容理論偏多代碼偏少,因為關於數組我覺得以CLR的角度看,不需要寫聲明,增刪查,二維多維數組這些概念,還有數組的排序和復制,如果把數組的一個一個方法拿出來介紹可能並沒有多少必要性,而是分析一下數組在底層是一個怎樣的分配,它和ArrayList還有List是什麽關系,其實數組可以說是很多數據結構的基礎。

C#數組的使用