有想過hash["A1"] = DateTime.Now;這句是怎么實現的嗎?我們來重溫下學校時代就學過的哈希算法吧。
我們要寫個class,實現如下主程序調用:
static void Main(string[] args) { MyHash hash = new MyHash(); hash["A1"] = DateTime.Now; hash["A2"] = 1; Console.WriteLine(Convert.ToString(hash["A1"])); Console.WriteLine(Convert.ToString(hash["A2"])); }
一看,也確實挺簡單的,就是一個所引器,如下:
class MyHash { public object this[string key] { get { } set { } } }
程序中要保存的對象,最終是要保存在一個數組中的,而且需要通過一個轉換函數來進行string key與數組Index的Map,如下:
private List<List<Tuple<string, object>>> lstArray = new List<List<Tuple<string, object>>>(defaultSize); private int MapString2Int(string key) { int hashIndex=0; char[] keyAry = key.ToCharArray(); foreach (var c in keyAry) hashIndex += (int)c; hashIndex = hashIndex % lstArray.Capacity; return hashIndex; }
這個函數是遍歷string key的每個char,累加,最終取模(同數組的長度),這樣得出的一個value肯定就在數組范圍內。
如果2個key轉換出來的index相同呢?會導致沖突,一個最簡單的解決辦法是把數組中的每個元素變成List, 也就是說,如果string key轉換后出現了相同的Index,沒關系,只要把那2個元素都放在那個Index所標識的數組位置中即可,本文中用的是List<Tuple<string, object>>。
下面是整個程序的代碼:
class Program { static void Main(string[] args) { MyHash hash = new MyHash(); hash["A1"] = DateTime.Now; hash["A2"] = 1; Console.WriteLine(Convert.ToString(hash["A1"])); Console.WriteLine(Convert.ToString(hash["A2"])); } } class MyHash { private const int defaultSize = 99999; private List<List<Tuple<string, object>>> lstArray = new List<List<Tuple<string, object>>>(defaultSize); public MyHash() { int i = lstArray.Capacity; while(i>=0) { lstArray.Add(new List<Tuple<string,object>>()); i--; } } public object this[string key] { get { EnsureNotNull(key); List<Tuple<string, object>> lst; Tuple<string, object> obj = FindByKey(key, out lst); if (obj == null) throw new Exception("Key不存在"); return obj.Item2; } set { EnsureNotNull(key); List<Tuple<string, object>> lst; Tuple<string, object> obj = FindByKey(key, out lst); if (obj!=null) lst.Remove(obj); lst.Add(new Tuple<string, object>(key, value)); } } private Tuple<string, object> FindByKey(string key, out List<Tuple<string, object>> lst) { int hashIndex = MapString2Int(key); lst = lstArray[hashIndex]; Tuple<string, object> obj = null; for (var i = 0; i < lst.Count; i++) { if (lst[i].Item1 == key) { obj = lst[i]; break; } } return obj; } private static void EnsureNotNull(string key) { if (key == null || key.Trim().Length == 0) throw new Exception("Key不能為空"); } private int MapString2Int(string key) { int hashIndex=0; char[] keyAry = key.ToCharArray(); foreach (var c in keyAry) hashIndex += (int)c; hashIndex = hashIndex % lstArray.Capacity; Console.WriteLine(string.Format("{0}相應的Index為:{1}", key, hashIndex)); return hashIndex; } }
運行效果圖: