我们来比较下散列的3种冲突解决方式,建立3个类,分别代表3种不同的冲突解决方式:
然后在主程序中分别插入10000条记录,比较各自所需要的时间。
先介绍下:
code:
class Program { static void Main(string[] args) { Timing t = new Timing(); Random rnd = new Random(DateTime.Now.Second); MyHash_MAD_多槽位 hash = new MyHash_MAD_多槽位(); t.Start(); for (var i = 0; i < 10000; i++) { string key = string.Format("{0}-{1}", rnd.Next(0, 9999), rnd.Next(0, 9999)); hash[key] = i; } t.Stop(); t.Display("MyHash_MAD_多槽位: "); hash.DisplayEmptyRatio(); Console.WriteLine(); rnd = new Random(DateTime.Now.Second); MyHash_MAD_独立链 hash2 = new MyHash_MAD_独立链(); t.Start(); for (var i = 0; i < 10000; i++) { string key = string.Format("{0}-{1}", rnd.Next(0, 9999), rnd.Next(0, 9999)); hash2[key] = i; } t.Stop(); t.Display("MyHash_MAD_独立链: "); hash2.DisplayEmptyRatio(); Console.WriteLine(); rnd = new Random(DateTime.Now.Second); MyHash_MAD_线性探测法 hash3 = new MyHash_MAD_线性探测法(); t.Start(); for (var i = 0; i < 10000; i++) { string key = string.Format("{0}-{1}", rnd.Next(0, 9999), rnd.Next(0, 9999)); hash3[key] = i; } t.Stop(); t.Display("MyHash_MAD_线性探测法: "); hash3.DisplayEmptyRatio(); Console.WriteLine("done."); Console.ReadKey(); } } class MyHash_MAD_多槽位 { private const int defaultSize = 10001; private List<List<Tuple<string, object>>> lstArray = new List<List<Tuple<string, object>>>(defaultSize); public MyHash_MAD_多槽位() { 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 = (31 * hashIndex + 2) % lstArray.Capacity; return hashIndex; } public void DisplayFlags() { foreach (var item in lstArray) Console.Write(string.Format("{0}, ", item.Count)); } public void DisplayEmptyRatio() { float emptyCount = 0; foreach (var item in lstArray) if (item.Count == 0) emptyCount++; string msg = string.Format("空值个数:{1}/{2}\n有值个数:{3}\n空值比例:{0}%", emptyCount / lstArray.Capacity * 100, emptyCount, lstArray.Capacity, lstArray.Capacity-emptyCount); Console.WriteLine(msg); } } class MyHash_MAD_独立链 { class HashNode { public string Key { get; set; } public object Value { get; set; } } private const int defaultSize = 10001; //private List<LinkedList<HashNode>> lstArray = new List<LinkedList<HashNode>>(defaultSize); private LinkedList<HashNode>[] lstArray = new LinkedList<HashNode>[defaultSize]; public MyHash_MAD_独立链() { int i = defaultSize; while (i > 0) { lstArray[i - 1] = new LinkedList<HashNode>(); i--; } } public object this[string key] { get { EnsureNotNull(key); LinkedList<HashNode> lst; HashNode obj = FindByKey(key, out lst); if (obj == null) throw new Exception("Key不存在"); return obj.Value; } set { EnsureNotNull(key); LinkedList<HashNode> lst; HashNode obj = FindByKey(key, out lst); if (obj != null) lst.Remove(obj); lst.AddLast(new HashNode() { Key=key, Value=value}); } } private HashNode FindByKey(string key, out LinkedList<HashNode> lst) { int hashIndex = MapString2Int(key); lst = lstArray[hashIndex]; HashNode obj = lst.FirstOrDefault(t => t.Key == key); if (obj != null && !string.IsNullOrEmpty(obj.Key)) return obj; return null; } 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 = (31 * hashIndex + 2) % defaultSize; return hashIndex; } public void DisplayFlags() { foreach (var item in lstArray) Console.Write(string.Format("{0}, ", item.Count)); } public void DisplayEmptyRatio() { float emptyCount = 0; foreach (var item in lstArray) if (item.Count == 0) emptyCount++; string msg = string.Format("空值个数:{1}/{2}\n有值个数:{3}\n空值比例:{0}%", emptyCount / defaultSize * 100, emptyCount, defaultSize, defaultSize - emptyCount); Console.WriteLine(msg); } } class MyHash_MAD_线性探测法 { private const int defaultSize = 10001; private List<List<Tuple<string, object>>> lstArray = new List<List<Tuple<string, object>>>(defaultSize); public MyHash_MAD_线性探测法() { int i = lstArray.Capacity; while (i > 0) { lstArray.Add(new List<Tuple<string, object>>()); i--; } } public object this[string key] { get { EnsureNotNull(key); Tuple<string, object> obj = FindElement(key); if (obj == null) throw new Exception("Key不存在"); return obj.Item2; } set { EnsureNotNull(key); List<Tuple<string, object>> lst; Tuple<string, object> obj = FindNextEmptyPlace(key, out lst); if (obj != null) lst.Remove(obj); lst.Add(new Tuple<string, object>(key, value)); } } private Tuple<string, object> FindElement(string key) { int hashIndex = MapString2Int(key); while (true) { hashIndex = hashIndex % lstArray.Capacity; if (lstArray[hashIndex].Count > 0) { List<Tuple<string, object>> lst = lstArray[hashIndex]; if (lst[0].Item1 == key) { return lst[0]; break; } } hashIndex++; } } private Tuple<string, object> FindNextEmptyPlace(string key, out List<Tuple<string, object>> lst) { int hashIndex = MapString2Int(key); while (true) { hashIndex = hashIndex % lstArray.Capacity; if (lstArray[hashIndex].Count == 0) break; hashIndex++; } 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 = (31 * hashIndex + 2) % lstArray.Capacity; return hashIndex; } public void DisplayFlags() { foreach (var item in lstArray) Console.Write(string.Format("{0}, ", item.Count)); } public void DisplayEmptyRatio() { float emptyCount = 0; foreach (var item in lstArray) if (item.Count == 0) emptyCount++; string msg = string.Format("空值个数:{1}/{2}\n有值个数:{3}\n空值比例:{0}%", emptyCount / lstArray.Capacity * 100, emptyCount, lstArray.Capacity, lstArray.Capacity - emptyCount); Console.WriteLine(msg); } }
线性探测法的空间占用率最高,几乎没有空位,但是耗费的时间最多,主要是查找I/O效率低。
多槽位性能最好。