自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

細說Array數(shù)組

開發(fā) 后端
Array數(shù)組有很多值得學(xué)習(xí)的地方,本篇文章,筆者將為大家細說Array。

  本文將對Array數(shù)組的各個方面做一個比較簡略地介紹,其中包括數(shù)組的基礎(chǔ)知識,分類,以及效率性能問題。

  1. 數(shù)組大局觀

  數(shù)組是一個引用類型,也就是意味著數(shù)組的內(nèi)存分配在托管堆上,并且我們在棧上維護的是他的指針而并非真正的數(shù)組。接下來我們分析下數(shù)組的元素,其中的元素?zé)o外乎是引用類型和值類型。當(dāng)數(shù)組中的元素是值類型時,不同于int i;這樣的代碼。數(shù)組會根據(jù)數(shù)組的大小自動把元素的值初始化為他的默認值。例如:

  1. static void Main(string[] args)  
  2.   {  
  3.   int[] intArray = new int[3];  
  4.   foreach(int i in intArray)  
  5.   {  
  6.   Console.WriteLine(i);  
  7.   }  
  8.   DateTime[] dtArray = new DateTime[3];  
  9.   foreach (DateTime i in dtArray)  
  10.   {  
  11.   Console.WriteLine(i);  
  12.   }  
  13.   }  

  結(jié)果如下:

  當(dāng)數(shù)組中的元素是引用類型時,實際上數(shù)組中的元素是一個指向?qū)ο髮嶋H內(nèi)存空間的指針,占用4Bytes的空間。

  2. 談?wù)劻慊鶖?shù)組

  從學(xué)C語言時起,相信老師就會對我們講,數(shù)組的***個索引是0,而不是1。但是在C#中,我們可以去構(gòu)造一個非零基數(shù)組,在這一節(jié),我們就來把這個說透。

  在常規(guī)意義上,我們初始化一個數(shù)組,都默認是零基數(shù)組,這也使得數(shù)組成為了字符串后再一個初始化時特殊的類型。正如我們知道的一樣,初始化一個字符串時,對應(yīng)的IL指令是newstr,同樣,初始化一個零基數(shù)組對應(yīng)的IL指令是newarr。

  當(dāng)我們希望構(gòu)造一個非零基數(shù)組時,我們可以以下的語句來做到:

  1. static void Main(string[] args)  
  2.   {  
  3.   Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.   Console.WriteLine(intArr.GetValue(1).ToString());  
  5.   Console.WriteLine(intArr.GetValue(0).ToString());  
  6.   }  

  得到的測試結(jié)果便如下:

  于是便證明,我們初始化了一個非零基數(shù)組。此外,延伸一下,我們還應(yīng)該通過這個記住以下兩個方法:

  1. static void Main(string[] args)  
  2.   {  
  3.   Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.   Console.WriteLine(intArr.GetLowerBound(0));  
  5.   Console.WriteLine(intArr.GetUpperBound(0));  
  6.   }  

  得到的測試結(jié)果如下:

 

  3. 談?wù)勑蕟栴}

  相信會有好多陰謀論者說,C#是個類型安全的語言,也就是意味著我循環(huán)時每次訪問一次數(shù)組的元素,那么就要檢查一次該索引是否會造成數(shù)組越界,于是就造成了一定的性能損失。那么在這里,我們就把這個問題說透。

  我們在這里把數(shù)組分成零基數(shù)組,非零基數(shù)組,多維數(shù)組,交錯數(shù)組四種情況來分別討論這個問題。

  零基數(shù)組是.NET中提倡使用的類型,并且初始化時提供了特殊的IL指令newarr則充分說明了他在.NET中的特殊性,自然.NET Framework也會為其提供很大的優(yōu)化待遇。在循環(huán)訪問數(shù)組時,如這樣的代碼:

  1. static void Main(string[] args)  
  2.   {  
  3.   int[] intArr = new int[5];  
  4.   for (int i = 0; i < 4; i++)  
  5.   {  
  6.   //Some Method  
  7.   }  
  8.   }  

  JIT編譯器只會在循環(huán)開始之前檢查一次4和intArr.GetUpperBound的大小關(guān)系,之后便不會對其進行干預(yù)。也就是說JIT編譯器只對其檢查一次安全,因此帶來的性能損失是非常小的。

  而對于非零基數(shù)組,我們來比較這樣兩段代碼:

  1. static void Main(string[] args)  
  2.   {  
  3.   Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.   Console.WriteLine(intArr.GetValue(1).ToString());  
  5.   Console.WriteLine(intArr.Length);  
  6.   //  
  7.   int[] intArr1 = new int[5];  
  8.   Console.WriteLine(intArr1[1]);  
  9.   Console.WriteLine(intArr1.Length);  
  10.   }  

  其實兩者創(chuàng)建的幾乎是相同的數(shù)組,調(diào)用的也幾乎是一樣的方法,但是我們看下IL卻會發(fā)現(xiàn)兩者有著驚人的不同,首先是非零基數(shù)組的IL:

  接下來是零基數(shù)組的:

  我們可以發(fā)現(xiàn),對于非零基數(shù)組中的大部分操作,.NET Framework都提供了對應(yīng)的IL指令,我們也可以理解為.NET Framework為其提供了特殊的優(yōu)化。

  當(dāng)然,實際上,正如CLR via C#所說的一樣:.NET Framework對應(yīng)非零基數(shù)組沒有任何方面的優(yōu)化,每次訪問都需要檢查其上限和下限與索引之間的關(guān)系。效率的損耗是必然的。

  事實上,當(dāng)我們測試這樣一段代碼時,也會發(fā)現(xiàn)其實零基數(shù)組和非零基數(shù)組的區(qū)別是很大的:

  1. static void Main(string[] args)  
  2.   {  
  3.   Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.   Console.WriteLine("intArr的?類à型í是?:o{0}", intArr.GetType());  
  5.   //  
  6.   int[] intArr1 = new int[5];  
  7.   Console.WriteLine("intArr1的?類à型í是?:o{0}", intArr1.GetType());  
  8.   }  

  得到的結(jié)果如下:

  接下來我們再來簡單地說下多維數(shù)組和交錯數(shù)組。

  多維數(shù)組和非零基數(shù)組一樣,都沒有受到.NET Framework的特殊優(yōu)待。

  而交錯數(shù)組,其實就是數(shù)組中的數(shù)組,因此效率實際上取決于數(shù)組中的數(shù)組是零基數(shù)組還是非零基數(shù)組。

  那接下來的一節(jié),我們來具體探討一下交錯數(shù)組和多維數(shù)組的區(qū)別和應(yīng)用。

  4. 多維數(shù)組和交錯數(shù)組

  考慮到兩個詞的翻譯問題,在這里給出兩個詞的英文:

  多維數(shù)組:Multi-dimensional Array。

  交錯數(shù)組:Jagged Array。

  好,下面步入正題。

  首先從二者的內(nèi)存分布說起。

  多維數(shù)組是一個整體的數(shù)組,因此他在內(nèi)存中占據(jù)一個整體的托管堆內(nèi)存塊。

  而交錯數(shù)組實際上是數(shù)組中的數(shù)組,因此我們用二維交錯數(shù)組來舉例,其內(nèi)存如圖所示:

 

  也就是說,如果是一個3*100的數(shù)組,也就是說需要初始化101次數(shù)組,當(dāng)數(shù)組的元素更加多的時候,那創(chuàng)建和垃圾回收將帶來巨大的效率損失。

  因此,也就是說:交錯數(shù)組的效率瓶頸在于創(chuàng)建和銷毀上,而并非類型安全檢查上。

  于是,我們就可以得出這樣的結(jié)論:

  當(dāng)一次創(chuàng)建,多次訪問時,我們應(yīng)該創(chuàng)建交錯數(shù)組。

  當(dāng)一次創(chuàng)建,一次訪問時,我們應(yīng)該創(chuàng)建多維數(shù)組。

  5. 用代碼改善效率

  上面說到了,訪問非零基數(shù)組和多維數(shù)組的效率是比較低的,對于非零基數(shù)組,我們的應(yīng)用比較少,但是多維數(shù)組,相信每個人都或多或少有著一定的應(yīng)用,那么面對其性能問題,我們該怎么辦呢?

  我們先來想想,多維數(shù)組的訪問,性能瓶頸在安全檢查上。在C語言中,為什么沒有這樣的問題,對,因為C語言不會做這樣的檢查。于是,相信聰明的大家都會想到不安全代碼。

  改善多維數(shù)組以及非零基數(shù)組的效率問題,我們就用不安全代碼。

  1. static unsafe void Main(string[] args)  
  2.   {  
  3.   int[,] intArr = new int[3, 3];  
  4.   for (int i = 0; i < 3; i++)  
  5.   {  
  6.   for (int j = 0; j < 3; j++)  
  7.   {  
  8.   intArr[i, j] = i * 3 + j;  
  9.   }  
  10.   }  
  11.   fixed (int* p = &intArr[0, 0])  
  12.   {  
  13.   for (int i = 0; i < 3; i++)  
  14.   {  
  15.   int baseOffset = i * 3;  
  16.   for (int j = 0; j < 3; j++)  
  17.   {  
  18.   Console.WriteLine(baseOffset + j);  
  19.   }  
  20.   }  
  21.   }  
  22.   }  

  這里,我們又見到了C語言中熟悉的指針,相信不需要多加介紹了。這里唯一需要注意的就是fixed,由于在垃圾回收時采用的是代機制+壓縮機制,因此其內(nèi)存地址很可能發(fā)生改變,因此我們應(yīng)該講數(shù)組的內(nèi)存地址鎖住,防止我們訪問到其他的內(nèi)存地址而造成我們讀取數(shù)據(jù)的錯誤。

  6. 對零基數(shù)組的精益求精

  當(dāng)然,即使是零基數(shù)組,我們依然在托管堆上為其分配了內(nèi)存空間。如果對性能要求極高,我們知道創(chuàng)建一個對象也是有著一定的時間損耗,其中包括分配內(nèi)存空間,同步塊索引,以及指向下一塊內(nèi)存空間的指針等一系列復(fù)雜的操作。那么我們就放棄掉托管堆這個東東,而直接在棧中來創(chuàng)建這個數(shù)組,這樣又省去了很多時間,從而達到了和C語言相同的效果,代碼如下:

  1. static unsafe void Main(string[] args)  
  2.   {  
  3.   int* intArr=stackalloc int[10];  
  4.   for (int i = 0; i < 10; i++)  
  5.   {  
  6.   intArr[i] = i;  
  7.   }  
  8.   for (int i = 0; i < 10; i++)  
  9.   {  
  10.   Console.WriteLine(intArr[i]);  
  11.   }  
  12.   }  

  這樣,效率就進一步提高了,對于二維數(shù)組,我們一樣可以如此創(chuàng)建。其代碼與C語言完全等同。我在這里就不繼續(xù)演示了。

  編者后話:在文章的***,介紹的是用不安全代碼來訪問創(chuàng)建數(shù)組來提高性能。不過在實際工作中,如果對性能沒有特別高的要求,則沒必要用不安全代碼來操作數(shù)組,因為其很可能因為你的一些失誤而帶來其他的一些安全問題,并且對代碼的可讀性也是個比較大的傷害,這就有些得不償失了。

【編輯推薦】

  1. JS中Array數(shù)組的三大屬性用法揭秘
  2. 常用C# Arraylist的介紹
  3. 淺析C# ArrayList
  4. C語言封送結(jié)構(gòu)體數(shù)組
  5. 詳細講述C#數(shù)組和指針
責(zé)任編輯:韓亞珊 來源: 博客園
相關(guān)推薦

2010-10-09 15:20:23

MySQL數(shù)組函數(shù)

2009-11-16 15:07:23

PHP數(shù)組函數(shù)庫

2009-11-16 15:16:59

PHP數(shù)組

2025-02-08 13:23:27

JavaScript開發(fā)喚醒鎖

2011-07-18 09:48:10

jQuery

2010-10-09 09:26:59

Array數(shù)組JS

2009-11-24 17:52:46

PHP函數(shù)in_arr

2021-11-10 11:37:48

Spring整合 Mybatis

2014-12-08 09:26:52

HTTP

2010-09-29 14:41:42

Suse DHCP配置

2009-09-17 10:04:32

LINQ存儲過程

2021-02-07 07:52:07

數(shù)組 JavaScript結(jié)構(gòu)

2014-11-21 10:36:26

VLANTrunk

2009-11-24 18:18:21

PHP函數(shù)array_

2024-08-30 08:35:03

JavaScript切片數(shù)組

2010-08-06 12:47:18

Linux NFS

2009-11-24 17:45:47

PHP數(shù)組排序函數(shù)ar

2009-11-24 18:08:39

PHP函數(shù)array_

2009-11-25 14:44:34

PHP函數(shù)array_

2014-12-16 13:51:55

華為eSpace UC統(tǒng)一通信
點贊
收藏

51CTO技術(shù)棧公眾號