zoukankan      html  css  js  c++  java
  • 散列算法是怎么实现的

    我们来比较下散列的3种冲突解决方式,建立3个类,分别代表3种不同的冲突解决方式:

    1. MyHash_MAD_多槽位
    2. MyHash_MAD_独立链
    3. MyHash_MAD_线性探测法

    然后在主程序中分别插入10000条记录,比较各自所需要的时间。

    先介绍下:

    • MAD:
      • multiply-add-divide method,乘法 - 加法 - 除法(取模),如下这个公式是散列核心公式
      • (a*collisionIndex+b)%M, M要求是素数,a, b的取值要合理
    • 冲突解决方式:
      • 多槽位
        • 当计算出的Index位置处已经被占用后,还是会在这个index的地方增加一个元素
        • 主数组的每个元素是个列表(比如每个元素都能放5个子元素),因此每个位置都能放多个元素
      • 独立链
        • 基本同上
        • 区别:主数组的每个元素对应的是一个链表
      • 线性探测法
        • 主数组只有一层,也就是每个数组元素只有一个空位,没有子列表
        • 如果计算出的Index位置处已经被占用,就自动往后面查找,直到找到一个没有被占用的位置,把元素放这个空位中

    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}
    有值个数:{3}
    空值比例:{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}
    有值个数:{3}
    空值比例:{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}
    有值个数:{3}
    空值比例:{0}%", emptyCount / lstArray.Capacity * 100, emptyCount, lstArray.Capacity, lstArray.Capacity - emptyCount);
                Console.WriteLine(msg);
            }
    
        }

     

    线性探测法的空间占用率最高,几乎没有空位,但是耗费的时间最多,主要是查找I/O效率低。

    多槽位性能最好。

  • 相关阅读:
    Linux Ctrl+Z的使用方法
    cx_Oracle库导入失败引起crontab中python程序运行失败,并且无错误提示
    cx_Oracle库导入失败引起crontab中python程序运行失败,并且无错误提示
    python __file__ 与相对路径
    ORACLE之手动注册监听listener。alter system set local_listener="XXX"
    pl/sql developer 连接本地ORACLE 11g 64位数据库
    在linux设置环境变量
    通过Instant Client包来使用SQL*PLUS
    linux 安装oracle 11g
    plsql developer 使用技巧
  • 原文地址:https://www.cnblogs.com/aarond/p/HashCollision.html
Copyright © 2011-2022 走看看