1. 程式人生 > >Unity3D中常用的資料結構總結與分析

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

來到週末,小匹夫終於有精力和時間來更新下部落格了。前段時間小匹夫讀過一份程式碼,對其中各種資料結構靈活的使用讚不絕口,同時也大大激發了小匹夫對各種資料結構進行梳理和總結的慾望。正好最近也拜讀了若干大神的文章,覺得總結下常用的資料結構以供自己也能靈活的使用變得刻不容緩。那麼還是從小匹夫的工作內容入手,就談談在平時使用U3D時經常用到的資料結構和各種資料結構的應用場景吧。

1.幾種常見的資料結構

 陣列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中提取值給info
object 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常用資料結構總結分析

來到週末,小匹夫終於有精力和時間來更新下部落格了。前段時間小匹夫讀過一份程式碼,對其中各種資料結構靈活的使用讚不絕口,同時也大大激發了小匹夫對各種資料結構進行梳理和總結的慾望。正好最近也拜讀了若干大神的文章,覺得總結下常用的資料結構以供自己也能靈活的使用變得刻不容緩。那麼還是從小匹夫的工作內容入手,就談談在平

(轉)Unity3D常用的數據結構總結分析

cnblogs 關於 指定 值類型 提取 聲明 數組 取消 例如 http://www.cnblogs.com/murongxiaopifu/p/4161648.html#array 1.幾種常見的數據結構 常碰到的幾種數據結構:Array,ArrayList

轉-Unity3D常用的數據結構總結分析

信息 解決 下回 lifo 百度百科 aop sys 例子 命名 來到周末,小匹夫終於有精力和時間來更新下博客了。前段時間小匹夫讀過一份代碼,對其中各種數據結構靈活的使用贊不絕口,同時也大大激發了小匹夫對各種數據結構進行梳理和總結的欲望。正好最近也拜讀了若幹大神的文章,覺

java 幾種常用資料結構 collectionmap

JAVA中常用的資料結構(java.util. 中) Java中有幾種常用的資料結構,主要分為Collection和map兩個主要介面(介面只提供方法,並不提供實現),而程式中最終使用的資料結構是繼承自這些介面的資料結構類。其主要的關係(繼承關係)有:  (----詳

《OpenCV3程式設計入門》——4.2 OpenCV常用資料結構和函式(Point、Scalar、Size、Rect、cvtColor)

目錄 1、點的表示:Point類 2、顏色的表示:Scalar類 3、尺寸的表示:Size類 4、矩形的表示:Rect類 5、顏色空間轉換:cvtColor()函式 1、點的表示:Point類 Point類資料結構表示了二維座標系下的點,即由影象座標x和y指定的2D點

常用資料結構總結(基於C++)

棧(stack) 簡介 棧是一種只能在一端進行插入或者刪除操作的線性表。其中允許進行插入或者刪除操作的一端稱為棧頂。棧的插入和刪除一般叫入棧和出棧。棧的順序儲存結構叫做順序棧,棧的鏈式儲存結構叫做鏈棧。 C++中棧的標頭檔案為<stack> 宣告 stack<資

面試-8種 常用資料結構總結

1976年,一個瑞士電腦科學家寫一本書《Algorithms + Data Structures = Programs》。即:演算法 + 資料結構 = 程式。40多年過去了,這個等式依然成立。 很多程式碼面試題都要求候選者深入理解資料結構,不管你來自大學計算機專業還是程式設計培訓機構,也不管你有

Java常用資料結構總結

資料元素相互之間的關係稱為結構。有四類基本結構:集合、線性結構、樹形結構、圖狀結構;集合結構:除了同屬於一種類型外,別無其它關係線性結構:元素之間存在一對一關係常見型別有: 陣列,連結串列,佇列,棧,它

JAVA常用資料結構及原理分析

java.util包中三個重要的介面及特點:List(列表)、Set(保證集合中元素唯一)、Map(維護多個key-value鍵值對,保證key唯一)。其不同子類的實現各有差異,如是否同步(執行緒安全)、是否有序。 常用類繼承樹: 以下結合原始碼講解常用類實現原理及相互之間

動圖+原始碼,演示Java常用資料結構執行過程及原理

最近在整理資料結構方面的知識, 系統化看了下Java中常用資料結構, 突發奇想用動畫來繪製資料流轉過程. 主要基於jdk8, 可能會有些特性與jdk7之前不相同, 例如LinkedList LinkedHashMap中的雙向列表不再是迴環的. HashMap中的單鏈表是尾插, 而不是頭插入等等, 後文不再贅敘

筆試題目總結之二——常用資料結構演算法

資料結構與演算法,這個部分的內容其實是十分的龐大,要想都覆蓋到不太容易。在校學習階段我們可能需要對每種結構,每種演算法都學習,但是找工作筆試或者面試的時候,要在很短的時間內考察一個人這方面的能力,把每種結構和演算法都問一遍不太現實。所以,實際的情況是,企業一般考察一些看起來

Exchange Online未送達報告(DSN)的總結分析

ide 安全 選項卡 star microsoft 反垃圾郵件 resolve 配置更改 form 從微軟廠商工程師那收集了一些未送達報告DSN代碼的總結和分析,分享給大家,對遇到郵件發送問題會有很大的幫助。 Exchange Online?和?Office 365?中的

redis學習2:redis資料結構結構物件

第1章 前言 redis這麼強大,那麼它底層是如何實現的呢?使用了哪些資料結構呢?本文就帶大家來剖析剖析 第2章 簡單動態字串(SDS)   redis的字串不是直接用c語言的字串,而是用了一種稱為簡單動態字串(SDS)的抽象型別,並將其作為預設字串。   redis中包含字串值的鍵

在Object-C學習資料結構演算法之排序演算法

筆者在學習資料結構與演算法時,嘗試著將排序演算法以動畫的形式呈現出來更加方便理解記憶,本文配合Demo 在Object-C中學習資料結構與演算法之排序演算法閱讀更佳。 目錄 選擇排序 氣泡排序 插入排序 快速排序 雙路快速排序 三路快速排序 堆排序 總結與收穫

常用資料結構演算法時間複雜度求解

1.0 資料結構的相關概念 2.0 一些基本演算法的時間複雜度 O(1): int x=1; O(n): for(int i = 0; i < n; i++){ printf("%d",i); } O(lo

java常用資料結構基礎知識總結(二)

     在上一篇中,和大家交流了java常用資料結構的基礎知識。現在與大家分享各類資料結構的遍歷問題、轉換問題。 一、遍歷問題 (1) List的遍歷問題(以ArrayList為例) ①通過迭代器遍歷     public static void traverseArr

在Linux使用tcpdump命令捕獲分析資料包詳解

tcpdump 是linux系統中提供的一個命令列工具,可以將網路中傳送的資料包完全截獲下來,提供網路資料分析 前言 tcpdump 是一個有名的命令列資料包分析工具。我們可以使用 tcpdump 命令捕獲實時 TCP/IP 資料包,這些資料包也可以儲存到檔案中。之後這些

Java常見資料結構:listmap -底層如何實現

1:集合 2 Collection(單列集合) 3 List(有序,可重複) 4 ArrayList 5 底層資料結構是陣列,查詢快,增刪慢 6 執行緒不安全,效率高

圖解Java常用資料結構(一)\JDK原始碼分析(二)——LinkedList

最近在整理資料結構方面的知識, 系統化看了下Java中常用資料結構, 突發奇想用動畫來繪製資料流轉過程. 主要基於jdk8, 可能會有些特性與jdk7之前不相同, 例如LinkedList LinkedHashMap中的雙向列表不再是迴環的. HashMap中的單鏈表

資料結構演算法——常用資料結構及其Java實現

前言 彷彿一下子,2017年就快過去一半了,研一馬上就要成為過去式了,我打算抓住研一的尾巴,好好梳理一下資料結構與演算法,畢竟這些基礎知識是很重要的嘛。所以準備在這裡搞一個系列的文章,以期透徹。 本系列將採用Java語言來進行描述。亦即總結常見的的資料結構,以及在J