(轉)Unity3D中常用的資料結構總結與分析

來源:互聯網
上載者:User

標籤:方便   定時   http   title   hive   建立   索引值   也有   aop   

1.幾種常見的資料結構

常碰到的幾種資料結構:Array,ArrayList,List<T>,LinkedList<T>,Queue<T>,Stack<T>,Dictionary<K,T>

 數組Array:

  數組是最簡單的資料結構。其具有如下特點:

  1. 數組儲存在連續的記憶體上。
  2. 數組的內容都是相同類型。
  3. 數組可以直接通過下標訪問。

  數組Array的建立:

1 int size = 5;2 int[] test = new int[size];

  建立一個新的數組時將在 CLR 託管堆中分配一塊連續的記憶體空間,來盛放數量為size,類型為所宣告類型的數組元素。如果類型為實值型別,則將會有size個未裝箱的該類型的值被建立。如果類型為參考型別,則將會有size個相應類型的引用被建立。

  由於是在連續記憶體上儲存的,所以它的索引速度非常快,訪問一個元素的時間是恒定的也就是說與數組的元素數量無關,而且賦值與修改元素也很簡單。

string[] test2 = new string[3];//賦值test2[0] = "chen";test2[1] = "j";test2[2] = "d";//修改test2[0] = "chenjd";

  但是有優點,那麼就一定會伴隨著缺點。由於是連續儲存,所以在兩個元素之間插入新的元素就變得不方便。而且就像上面的代碼所顯示的那樣,聲明一個新的數組時,必須指定其長度,這就會存在一個潛在的問題,那就是當我們聲明的長度過長時,顯然會浪費記憶體,當我們聲明長度過短的時候,則面臨這溢出的風險。這就使得寫代碼像是投機,小匹夫很厭惡這樣的行為!針對這種缺點,下面隆重推出ArrayList。

 ArrayList:

  為瞭解決數組建立時必須指定長度以及只能存放相同類型的缺點而推出的資料結構。ArrayList是System.Collections命名空間下的一部分,所以若要使用則必須引入System.Collections。正如上文所說,ArrayList解決了數組的一些缺點。

  1. 不必在聲明ArrayList時指定它的長度,這是由於ArrayList對象的長度是按照其中儲存的資料來動態增長與縮減的。
  2. ArrayList可以儲存不同類型的元素。這是由於ArrayList會把它的元素都當做Object來處理。因而,加入不同類型的元素是允許的。

  ArrayList的操作:

ArrayList test3 = new ArrayList();//新增資料test3.Add("chen");test3.Add("j");test3.Add("d");test3.Add("is");test3.Add(25);//修改資料test3[4] = 26;//刪除資料test3.RemoveAt(4);

  說了那麼一堆”優點“,也該說說缺點了吧。為什麼要給”優點”打上引號呢?那是因為ArrayList可以儲存不同類型資料的原因是由於把所有的類型都當做Object來做處理,也就是說ArrayList的元素其實都是Object類型的,辣麼問題就來了。

  1. ArrayList不是型別安全的。因為把不同的類型都當做Object來做處理,很有可能會在使用ArrayList時發生類型不符的情況。
  2. 如上文所訴,數組儲存實值型別時並未發生裝箱,但是ArrayList由於把所有類型都當做了Object,所以不可避免的當插入實值型別時會發生裝箱操作,在索引取值時會發生拆箱操作。這能忍嗎?

註:為何說頻繁的沒有必要的裝箱和拆箱不能忍呢?且聽小匹夫慢慢道來:所謂裝箱(boxing):就是實值型別執行個體到對象的轉換(百度百科)。那麼拆箱:就是將參考型別轉換為實值型別咯(還是來自百度百科)。下面舉個栗子~

//裝箱,將String類型的值FanyoyChenjd賦值給對象。int  info = 1989;  object obj=(object)info;  //拆箱,從Obj中提取值給infoobject obj = 1;
int info = (int)obj;

 

那麼結論呢?好吧,請允許小匹夫很low再次引用百度百科。顯然,從原理上可以看出,裝箱時,產生的是全新的引用對象,這會有時間損耗,也就是造成效率降低。

 

 List<T>泛型List

  為瞭解決ArrayList不安全類型與裝箱拆箱的缺點,所以出現了泛型的概念,作為一種新的數群組類型引入。也是工作中經常用到的數群組類型。和ArrayList很相似,長度都可以靈活的改變,最大的不同在於在聲明List集合時,我們同時需要為其聲明List集合內資料的物件類型,這點又和Array很相似,其實List<T>內部使用了Array來實現。

List<string> test4 = new List<string>();    //新增資料  test4.Add(“Fanyoy”);  test4.Add(“Chenjd”);  //修改資料  test4[1] = “murongxiaopifu”;    //移除資料  test4.RemoveAt(0);  

  這麼做最大的好處就是

  1. 即確保了型別安全。
  2. 也取消了裝箱和拆箱的操作。
  3. 它融合了Array可以快速存取的優點以及ArrayList長度可以靈活變化的優點。
  LinkedList<T>

  也就是鏈表了。和上述的數組最大的不同之處就是在於鏈表在記憶體儲存的排序上可能是不連續的。這是由於鏈表是通過上一個元素指向下一個元素來排列的,所以可能不能通過下標來訪問。

  既然鏈表最大的特點就是儲存在記憶體的空間不一定連續,那麼鏈表相對於數組最大優勢和劣勢就顯而易見了。

  1. 向鏈表中插入或刪除節點無需調整結構的容量。因為本身不是連續儲存而是靠各對象的指標所決定,所以添加元素和刪除元素都要比數組要有優勢。
  2. 鏈表適合在需要有序的排序的情境下增加新的元素,這裡還拿數組做對比,例如要在數組中間某個位置增加新的元素,則可能需要移動移動很多元素,而對於鏈表而言可能只是若干元素的指向發生變化而已。
  3. 有優點就有缺點,由於其在記憶體空間中不一定是連續排列,所以訪問時候無法利用下標,而是必須從頭結點開始,逐次遍曆下一個節點直到尋找到目標。所以當需要快速存取對象時,數組無疑更有優勢。

  綜上,鏈表適合元素數量不固定,需要經常增減節點的情況。

  關於鏈表的使用,MSDN上有詳細的例子。

  Queue<T>

  在Queue<T>這種資料結構中,最先插入在元素將是最先被刪除;反之最後插入的元素將最後被刪除,因此隊列又稱為“先進先出”(FIFO—first in first out)的線性表。通過使用Enqueue和Dequeue這兩個方法來實現對 Queue<T> 的存取。

  一些需要注意的地方:

  1. 先進先出的情景。
  2. 預設情況下,Queue<T>的初始容量為32, 增長因子為2.0。
  3. 當使用Enqueue時,會判斷隊列的長度是否足夠,若不足,則依據增長因子來增加容量,例如當為初始的2.0時,則隊列容量增長2倍。
  4. 乏善可陳。

  關於Queue<T>的使用方法,MSDN上也有相應的例子。

  Stack<T>

  

  與Queue<T>相對,當需要使用後進先出順序(LIFO)的資料結構時,我們就需要用到Stack<T>了。

  一些需要注意的地方:

  1. 後進先出的情景。
  2. 預設容量為10。
  3. 使用pop和push來操作。
  4. 乏善可陳。

  同樣,在這裡你也可以看到大量Stack<T>的例子。

  Dictionary<K,T>

  字典這東西,小匹夫可是喜歡的不得了。看官們自己也可以想想字典是不是很招人喜歡,建立一個字典之後就可以往裡面扔東西,增加、刪除、訪問那叫一個快字了得。但是直到小匹夫日前看了一個大神的文章,才又想起了那句話“啥好事咋能讓你都佔了呢”。那麼字典背後到底隱藏著什麼迷霧,撥開重重迷霧之後,是否才是真相?且聽下回分。。。等等,應該是下面就讓我們來分析一下字典吧。

  提到字典就不得不說Hashtable雜湊表以及Hashing(雜湊,也有叫散列的),因為字典的實現方式就是雜湊表的實現方式,只不過字典是型別安全的,也就是說當建立字典時,必須聲明key和item的類型,這是第一條字典與雜湊表的區別。關於雜湊表的內容推薦看下這篇部落格雜湊表。關於雜湊,簡單的說就是一種將任意長度的訊息壓縮到某一固定長度,比如某學校的學生學號範圍從00000~99999,總共5位元字,若每個數字都對應一個索引的話,那麼就是100000個索引,但是如果我們使用後3位作為索引,那麼索引的範圍就變成了000~999了,當然會衝突的情況,這種情況就是雜湊衝突(Hash Collisions)了。扯遠了,關於具體的實現原理還是去看小匹夫推薦的那篇部落格吧,當然那篇部落格上面那個大大的轉字也是蠻刺眼的。。。

  回到Dictionary<K,T>,我們在對字典的操作中各種時間上的優勢都享受到了,那麼它的劣勢到底在哪呢?對嘞,就是空間。以空間換時間,通過更多的記憶體開銷來滿足我們對速度的追求。在建立字典時,我們可以傳入一個容量值,但實際使用的容量並非該值。而是使用“不小於該值的最小質數來作為它使用的實際容量,最小是3。”(老趙),當有了實際容量之後,並非直接實現索引,而是通過建立額外的2個數組來實現間接的索引,即int[] buckets和Entry[] entries兩個數組(即buckets中儲存的其實是entries數組的下標),這裡就是第二條字典與雜湊表的區別,還記得雜湊衝突嗎?對,第二個區別就是處理雜湊衝突的策略是不同的!字典會採用額外的資料結構來處理雜湊衝突,這就是剛才提到的數組之一buckets桶了,buckets的長度就是字典的真實長度,因為buckets就是字典每個位置的映射,然後buckets中的每個元素都是一個鏈表,用來儲存相同雜湊的元素,然後再分配儲存空間。

因此,我們面臨的情況就是,即便我們建立了一個空的字典,那麼伴隨而來的是2個長度為3的數組。所以當處理的資料不多時,還是謹慎使用字典為好,很多情況下使用數組也是可以接受的。

 

2.幾種常見資料結構的使用情景
Array 需要處理的元素數量確定並且需要使用下標時可以考慮,不過建議使用List<T>
ArrayList 不推薦使用,建議用List<T>
List<T>泛型List 需要處理的元素數量不確定時 通常建議使用
LinkedList<T> 鏈表適合元素數量不固定,需要經常增減節點的情況,2端都可以增減
Queue<T> 先進先出的情況
Stack<T> 後進先出的情況
Dictionary<K,T> 需要索引值對,快速控制項目

 

  

 

  

  

 

 

 

裝模作樣的 聲明一下:本博文章若非特殊註明皆為原創,若需轉載請保留原文連結及作者資訊慕容小匹夫

(轉)Unity3D中常用的資料結構總結與分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.