跟上一篇《數據結構,你還記得嗎(上)》目錄進行一一對應講解C#中各類數據結構,以此來提高理解。html
多維數組,行和列是固定的: int[][] arrMore=new int[3][6]; 鋸齒數組只要在第一個方括號設置行數,每行的個數是可變的。 int[][] jagged=new int[3][]; jagged[0]=new int[2]{1,2}; jagged[1]=new int[6]{1,2,3,4,5,6}; jagged[2]=new int[3]{1,2,3};
Array 類是 C# 中全部數組的基類,它是在 System 命名空間中定義(System.Array)。Array 類提供了各類用於數組的屬性和方法。
用方括號[] 聲明數組是C#中使用Array類的表示法。在後臺使用C#語法,會建立一個派生自抽象基類Array的新類。這樣,就可使用Array類爲每一個C#數組定義的方法和屬性了。算法
數組能夠直接經過下標訪問。數據庫
建立一個新的數組時將在 CLR 託管堆中分配一塊連續的內存空間,來存放數量爲n,類型爲所聲明類型的數組元素。若是類型爲值類型,則將會有n個未裝箱的該類型的值被建立。若是類型爲引用類型,則將會有n個相應類型的引用被建立。編程
缺點
因爲是連續存儲,因此在兩個元素之間插入新的元素就變得不方便。並且就像上面的代碼所顯示的那樣,聲明一個新的數組時,必須指定其長度,這就會存在一個潛在的問題,那就是當咱們聲明的長度過長時,顯然會浪費內存,當咱們聲明長度太短的時候,則面臨這溢出的風險。有點投機,針對這種缺點,引出了ArrayList。c#
爲了解決數組建立時必須指定長度以及只能存放相同類型的缺點而推出的數據結構。ArrayList是System.Collections命名空間下的一部分,因此若要使用則必須引入System.Collections。正如上文所說,ArrayList解決了數組的一些缺點。數組
爲了解決ArrayList不安全類型與裝箱拆箱的缺點,因此出現了泛型的概念,做爲一種新的數組類型引入。也是工做中常常用到的數組類型。和ArrayList很類似,長度均可以靈活的改變,最大的不一樣在於在聲明List集合時,咱們同時須要爲其聲明List集合內數據的對象類型,這點又和Array很類似,其實List
有序列表 SortedList<Tkey,TElement> 只容許每一個鍵有一個對應的值,若是須要每一個鍵對應多個值,就須要使用Lookup<Tkey,TElement>數據結構
Array類是一個抽象類,因此不能使用構造函數來建立數組。但除了可使用C#語法建立數組實例以外,還可使用靜態方法CreateInstance()建立數組。若是事先不知道元素的類型,該靜態方法就很是有用,由於類型能夠做爲Type對象傳遞給CreateInstance()方法。多線程
例如: Array arr=Array.CeateInstance(typeof(int),5); for(int i=0;i<5;i++) { arr.SetVaule(i,i); } for(int i=0;i<5;i++) { int vaule=arr.getVaule(i); }
羽毛球筒編程語言
堆棧(Stack)表明了一個後進先出的對象集合。當您須要對各項進行後進先出的訪問時,則使用堆棧。當您在列表中添加一項,稱爲推入元素,當您從列表中移除一項時,稱爲彈出元素。
public class Stack<T> : IEnumerable<T>, ICollection, IEnumerable public class Stack : ICollection, IEnumerable, ICloneable
屬性 | 描述 |
---|---|
Count | 獲取 Stack 中包含的元素個數 |
方法 | 描述 |
---|---|
Pop | public virtual object Pop();移除並返回在 Stack 的頂部的對象 |
push | public virtual void Push(object obj);向 Stack 的頂部添加一個對象 |
peek | public virtual object Peek();返回在 Stack 的頂部的對象,但不移除它 |
ToArray | public virtual object[] ToArray();建立數組並將堆棧元素複製到其中 |
Contains | public virtual bool Contains(object obj);判斷一個元素是否在棧中 |
Clear | public virtual void Clear();從 Stack 中移除全部的元素。 |
水管子
隊列(Queue)表明了一個先進先出的對象集合。當您須要對各項進行先進先出的訪問時,則使用隊列。當您在列表中添加一項,稱爲入隊,當您從列表中移除一項時,稱爲出隊。
public class Queue<T> : IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>, ICollection
屬性 | 描述 |
---|---|
Count | 獲取 Queue 中包含的元素個數 |
方法 | 描述 |
---|---|
Clear | public virtual void Clear(); 從 Queue 中移除全部的元素。 |
Contains | public virtual bool Contains( object obj ); 判斷某個元素是否在 Queue 中。 |
Dequeue | public virtual object Dequeue();移除並返回在 Queue 的開頭的對象。 |
Enqueue | public virtual void Enqueue( object obj ); 向 Queue 的末尾添加一個對象。 |
ToArray | public virtual object[] ToArray();複製 Queue 到一個新的數組中。 |
TrimToSize | public virtual void TrimToSize();設置容量爲 Queue 中元素的實際個數。 |
實現方式 public class Node<T> { public T Data { set; get; } //數據域,當前結點數據 public Node<T> Next { set; get; } //位置域,下一個結點地址 public Node(T item) { this.Data = item; this.Next = null; } public Node() { this.Data = default(T); this.Next = null; } }
有優勢就有缺點,因爲其在內存空間中不必定是連續排列,因此訪問時候沒法利用下標,而是必須從頭結點開始,逐次遍歷下一個節點直到尋找到目標。因此當須要快速訪問對象時,數組無疑更有優點。
綜上,鏈表適合元素數量不固定,須要兩端存取且常常增減節點的狀況。
請轉到《數據結構:單鏈表》查看更詳細內容!
LinkedList
鏈表在存儲元素時,不只要存儲元素的值,還必須存儲每一個元素的下一個元素和上一個元素的信息。這就是LinkedList
鏈表的優勢是,若是將元素插入到列表的中間位置,使用鏈表就會很快。在插入一個元素時,只須要修改上一個元素的Next引用和下一個元素的Previous引用,使它們引用所插入的元素。在List
鏈表的缺點是,鏈表元素只能一個接一個的訪問,這須要較長時間來查找位於鏈表中間或尾部的元素。
LinkedList
在指定位置插入元素:AddAfter(),AddFirst()和AddLast();
刪除指定位置的元素:Remove(),RemoveFirst(),RemoveLast();
搜索:Find(),FindLast()。
菜單樹
C#中沒有實現樹的具體類,通常能夠經過本身實現。
結點樹包含:父結點(根結點的父結點爲null)、子結點(List集合)、數據對象。
請轉到《 數據結構:樹》查看更詳細的內容!
圖狀結構簡稱圖,是另外一種非線性結構,它比樹形結構更復雜。樹形結構中的結點是一對多的關係,結點間具備明顯的層次和分支關係。每一層的結點能夠和下一層的多個結點相關,但只能和上一層的一個結點相關。而圖中的頂點(把圖中的數據元素稱爲頂點)是多對多的關係,即頂點間的關係是任意的,圖中任意兩個頂點之間均可能相關。也就是說,圖的頂點之間無明顯的層次關係,這種關係在現實世界中大量存在。所以,圖的應用至關普遍,在天然科學、社會科學和人文科學等許多領域都有着很是普遍的應用。
c#沒有實現圖的數據結構,可是能夠本身實現,參考以下
請轉到《數據結構:圖》查看更詳細內容!
字典樹,又稱爲單詞查找樹,Tire數,是一種樹形結構,它是一種哈希樹的變種。
典型應用是用於統計,排序和保存大量的字符串(不只限於字符串),常常被搜索引擎系統用於文本詞頻統計。
c#也沒有實現字典樹,能夠本身實現,參考以下
請轉到《數據結構:字典樹》查看更詳細內容!
請轉到《字典樹(Trie樹)實現與應用》查看更詳細內容!
利用字符串的公共前綴來減小查詢時間,最大限度的減小無謂的字符串比較,查詢效率比哈希樹高。
Hashtable是System.Collections命名空間提供的一個容器,用於處理和表現相似keyvalue的鍵值對,其中key一般可用來快速查找,同時key是區分大小寫;value用於存儲對應於key的值。Hashtable中keyvalue鍵值對均爲object類型,因此Hashtable能夠支持任何類型的keyvalue鍵值對.
using System.Collections; using System.Collections.Generic;
//添加一個keyvalue鍵值對: HashtableObject.Add(key,value); //移除某個keyvalue鍵值對: HashtableObject.Remove(key); //移除全部元素: HashtableObject.Clear(); // 判斷是否包含特定鍵key: HashtableObject.Contains(key);
遍歷哈希表須要用到DictionaryEntry Object,代碼以下: for(DictionaryEntry de in ht) //ht爲一個Hashtable實例 { Console.WriteLine(de.Key); //de.Key對應於keyvalue鍵值對key Console.WriteLine(de.Value); //de.Key對應於keyvalue鍵值對value }
請轉到《數據結構:哈希表》查看更詳細內容!
表示索引鍵和值的集合。
[System.Runtime.InteropServices.ComVisible(false)] [System.Serializable] public class Dictionary<TKey,TValue> : System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>, System.Collections.Generic.IDictionary<TKey,TValue>, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>, System.Collections.Generic.IReadOnlyCollection<System.Collections.Generic.KeyValuePair<TKey,TValue>>, System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>, System.Collections.IDictionary, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable
由於字典的實現方式就是哈希表的實現方式,只不過字典是類型安全的,也就是說當建立字典時,必須聲明key和item的類型。
結論:Dictionary<K,V>是泛型的,當K或V是值類型時,其速度遠遠超過Hashtable。
因爲 Hashtable 和 Dictionary 同時存在, 在使用場景上必然存在選擇性, 並不任什麼時候刻都能相互替代.
關鍵字和它在表中存儲位置之間存在一種函數關係。這個函數咱們稱爲爲哈希函數。
hash : 翻譯爲「散列」,就是把任意長度的輸入,經過散列算法,變成固定長度的輸出,該輸出就是散列值。
這種轉換是一種壓縮映射,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,因此不可能從散列值來惟一的肯定輸入值,由此引出hash衝突。
簡單的說就是一種將任意長度的消息壓縮到固定長度的消息的函數。
hash衝突
就是鍵(key)通過hash函數獲得的結果做爲地址去存放當前的鍵值對(key-value)(這個是hashmap的存值方式),可是卻發現該地址已經有人先來了,一山不容二虎,就會產生衝突。這個衝突就是hash衝突了。若是兩個不一樣對象的hashCode相同,這種現象稱爲hash衝突。
開發定址法(線性探測再散列,二次探測再散列,僞隨機探測再散列)
這種方法也稱再散列法,其基本思想是:當關鍵字key的哈希地址p=H(key)出現衝突時,以p爲基礎,產生另外一個哈希地址p1,若是p1仍然衝突,再以p爲基礎,產生另外一個哈希地址p2,…,直到找出一個不衝突的哈希地址pi ,將相應元素存入其中。這種方法有一個通用的再散列函數形式:
Hi=(H(key)+di)% m i=1,2,…,n
其中H(key)爲哈希函數,m 爲表長,di稱爲增量序列。增量序列的取值方式不一樣,相應的再散列方式也不一樣。主要有如下三種:
1) 線性探測再散列
2) 二次(平方)探測再散列
3) 僞隨機探測再散列
再哈希法
這種方法是同時構造多個不一樣的哈希函數:
Hi=RH1(key) i=1,2,…,k
當哈希地址Hi=RH1(key)發生衝突時,再計算Hi=RH2(key)……,直到衝突再也不產生。這種方法不易產生彙集,但增長了計算時間。
鏈地址法
將全部哈希地址相同的都連接在同一個鏈表中 ,於是查找、插入和刪除主要在同義詞鏈中進行。鏈地址法適用於常常進行插入和刪除的狀況。
hashmap就是用此方法解決衝突的。
創建一個公共溢出區
將哈希表分爲基本表和溢出表兩部分,凡是和基本表發生衝突的元素,一概填入溢出表。
綜上所述,找了相關的文檔以後,發現C#自己沒有封裝部分數據結構,多是讓你們本身發揮,也可能跟它當初設計的緣由有關,由於它不是專們爲處理數據而誕生的。寫完以後,發現寫到這裏還不夠,因而將標題改成《數據結構,你還記得嗎(中)》,接下來還要繼續《數據結構,你還記得嗎(下)》 未完待續!
其餘系列的C#數據結構參考《C# 數據結構》
數組存儲區間是連續的,佔用內存嚴重,故空間複雜的很大。但數組的索引查找複雜度小,爲O(1);數組的特色是:尋址容易,插入和刪除困難;
鏈表存儲區間離散,佔用內存比較寬鬆,故空間複雜度很小,但時間複雜度很大,達O(N)。鏈表的特色是:尋址困難,插入和刪除容易。
那麼咱們能不能綜合二者的特性,作出一種尋址容易,插入刪除也容易的數據結構?答案是確定的,這就是咱們要提起的哈希表。哈希表((Hash table)既知足了數據的查找方便,同時不佔用太多的內容空間,使用也十分方便。
哈希表綜合以上兩個優勢,但同時還有一個缺點,就是在連續查詢的時候性能很是差。那怎麼尋址容易,插入,刪除也容易,連續查詢也容易呢? 這個就引出了數據庫底層採用的存儲數據結構,B+樹。