using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; namespace DataStructures.HashSpace { /// /// A hash table which uses user specified step size probing /// /// /// [Serializable] public class LinearProbingDictionary : IDictionary { private const int DefaultCapacity = 1023; private int capacity; private readonly int stepSize; private int count; private Pair[] pairs; public ICollection Keys { get { return pairs.Where(p => (p != null)) .Select(p => p.Key) .ToList() .AsReadOnly(); } } public ICollection Values { get { return pairs.Where(p => (p!=null)) .Select(p => p.Value) .ToList() .AsReadOnly(); } } public int Count { get { return count; } } public int Capacity { get { return capacity; } } public bool IsReadOnly { get { throw new NotImplementedException(); } } public LinearProbingDictionary(int capacity, int stepSize = 1) { Contract.Requires(capacity > 0); Contract.Requires(stepSize > 0); this.capacity = capacity; this.stepSize = stepSize; pairs = new Pair[capacity]; } public LinearProbingDictionary(int stepSize) : this(DefaultCapacity, stepSize) { } public void Add(Tkey key, TValue value) { Pair pair = new Pair(key, value); int pos = pair.GetHashCode(); int visit = 0; while(pairs[pos] != null) { if(visit >= capacity) { throw new Exception("Dictionary is full"); } pos = (pos+stepSize) % capacity; visit++; } pairs[pos] = pair; count++; } /// /// Returns index of th item /// /// /// -1 if not present private int GetIndex(Tkey key) { if (key == null) { return -1; } int index = key.GetHashCode() % capacity; int currentIndex = index; do { if (pairs[currentIndex] == null) { return -1; } if (pairs[currentIndex].Key.Equals(key)) { return currentIndex; } else { currentIndex = (currentIndex + stepSize) % capacity; } } while (currentIndex != index); return -1; } public bool ContainsKey(Tkey key) { return (GetIndex(key) != -1) ; } public bool Remove(Tkey key) { Contract.Requires(key != null, "key"); int index; if ((index = GetIndex(key)) != -1) { pairs[index] = null; count--; return true; } Remove(new KeyValuePair()); return false; } public bool TryGetValue(Tkey key, out TValue value) { int index = GetIndex(key); if (index != -1) { value = pairs[index].Value; return true; } else { value = default(TValue); return false; } } public TValue this[Tkey key] { get { var index = GetIndex(key); if(index == -1) { return default(TValue); } return pairs[index].Value; } set { var index = GetIndex(key) ; if (index == -1) { Add(key, value); } else { pairs[index].Value = value; } } } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public void Clear() { count = 0; pairs = new Pair[capacity]; } public bool Contains(KeyValuePair item) { return ContainsKey(item.Key) ? item.Value.Equals(pairs[GetIndex(item.Key)].Value) : false; } public void CopyTo(KeyValuePair[] array, int arrayIndex) { foreach (var pair in pairs) { if(pair != null) { array[arrayIndex] = new KeyValuePair(pair.Key, pair.Value); arrayIndex++; } } } public bool Remove(KeyValuePair item) { int index = GetIndex(item.Key); if (index == -1) { return false; } pairs[index] = null; count--; return true; } public IEnumerator> GetEnumerator() { foreach (var pair in pairs) { if(pair == null) { continue; } yield return new KeyValuePair(pair.Key, pair.Value); } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } private class Pair { public Tkey Key { get; set; } public TValue Value { get; set; } public Pair(Tkey key, TValue value) { Key = key; Value = value; } public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return false; } return Key.Equals(obj); } public override int GetHashCode() { int hash = 31; unchecked { hash = hash + 17 * Key.GetHashCode(); } return hash; } } } }