• sqlite中的hash算法实现


    sqlite的分词器模块需要对输入的字符串映射为系统中的标示符,其对关键字映射使用了hash算法,其对hash冲突的解决十分巧妙。

    1:最常规的解决办法:写一堆判断对每个输入字符串判断是否匹配,如果匹配就映射为系统中的关键字。由于sqlite的关键字有100多个,如果每个字符串进行比较判断,无疑效率很低

    2:使用hash算法:

         首先构造一个散列函数,该函数计算字符串得到一个hash映射表的入口地址。

         在入口地址中存放对应的记录.

         由于对不同的字符串进行散列后可能得到一个相同的入口地址,这就要求我们要对冲突进行解决.


    2.1以前遇到类似的问题,基本使用了链地址法来解决冲突的问题。例如:

    typedef struct map_s map_t;
    
    struct map_s
    
    {
    
        unsigned char *pStr;
    
        unsigned char token;
    
    }
    
    unsigned char getTken(unsigned char *pStr, int len)
    
    {
    
        const unsigned char map[M][N] = {
                                        {{"token11",TK_TOKEN11},...,{"token1n",TK_TOKEN1N}},
    
                                        ....
    
                                        {{"tokenm1",TK_TOKENM1},...,{NULL,TK_ERR}},
    
                                        };
    
        hashCode = getHashCode(pStr);
    
        for(int i=0;i<N;i++)
    
        {
    
                if(map[hashCode][i].pStr equals pStr)
    
                     return map[hashCode][i].token
    
        }
    
        return TK_ERR;
    }

    该方法简单容易理解,如果散列函数较好,基本可以寻址复杂度为O(1),但该方法对于没有被映射的位置存在一些空间的浪费。

    2.2   sqlite使用了一个字符串缓冲区来包含所有的可能关键字,该缓冲区是被压缩过的。

         static const char zText[544] =
         "ABORTABLEFTEMPORARYADDATABASELECTHEND"
          ....
         "UNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL";

    关键字"abort"和"table"公用“ABORTABLE”缓冲区间, 对于每个关键字都存在一个该缓冲区的入口位置,以该入口位置进行字符串比较,判断是否冲突。

        static const unsigned short int aOffset[117] = {
         0,   4,   7,  10,  10,  14,  19,  21,  26,  27,  32,  34,  36,
         ....
         476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528
        };

    hash映射表保存了每个计算的hash值的可能入口位置,如果该入口位置的缓冲区字符串和待转换字符串等同,表明没有冲突,直接获取对应的aCode映射值。

        static const unsigned char aHash[127] = {
        92,  80, 107,  91,   0,   4,   0,   0, 114,   0,  83,   0,   0,
        ....
        15,   0, 116,  51,  56,   0,   2,  55,   0, 111,
        };

        static const unsigned char aCode[117] = {
        TK_ABORT,      TK_TABLE,      TK_JOIN_KW,    TK_TEMP,       
        ....
        TK_WHERE,      TK_VIRTUAL,    
        };

    如果出现冲突,使用了“再散列法”来解决,对冲突的地址在aNext重新分配一个没有使用过的入口位置,该入口位置的缓冲区字符串和待转换字符串等同。

        static const unsigned char aNext[117] = {
        0,   0,   0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,
        ....
        0,  14,  27,  78,   0,  57,  89,   0,  35,   0,  62,   0,
        };

    该hash算法设计的比较巧妙,使用了一个压缩的字符串缓冲区结合“再散列法”完美的解决了hash冲突问题。在空间和查找效率上都很优秀。

    http://www.cnblogs.com/chencheng/archive/2012/06/18/2554001.html

  • 相关阅读:
    ASP.NET MVC 入门9、Action Filter 与 内置的Filter实现(介绍) 【转】
    一个建议,看看大家的意见。
    发现不错的文章,推!
    有个小问题,大家一起研究。
    逼不得已,这个我确实不会,昨办?
    MSN Message6.2 的小BUG
    在IE7浏览器中切换成以资源管理器方式
    手机罗盘(指南针)校准方法
    G13/ Wildfire S/A510e link2SD教程,干净清洁的安装程序到内存卡
    HTC G13电池怎么鉴别真伪
  • 原文地址:https://www.cnblogs.com/chencheng/p/2554001.html
Copyright © 2020-2023  润新知