博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
脏字过滤(基于hash的优化算法)
阅读量:5276 次
发布时间:2019-06-14

本文共 1957 字,大约阅读时间需要 6 分钟。

说的trie算法原文见

http://www.cnblogs.com/yeerh/archive/2011/08/24/2152607.html

回复中有说到一个很快的方法 。原文见的博客

仅测试,这种方法确定很快,但已不是单纯的hash算法了。

文章中基本上只有代码,只有很少的说明。

经过本人的认真阅读,终于搞懂了优化的关键所在。

现在对这种做了一个小的改动,不敢独独享,特分享给大家。

这种优化基于我们本常所用的大部分词或是字并不是脏字的前提。

有些字符即使在脏字单词中出现,他们出现地位置也不一样。

根据这个特点。我们先建立一个用于快速过滤的数组。

Uint16[] m_fastCheck = new Uint16[char.MaxValue];

fastCheck的索引号用来表示对应的字符。

里面的值 表示这个字符在单词中出现的位置,我们用Uint16来表示,

也就可以保存1-16。。

比如:马这个字符脏字有 "你马", '马的' , '草泥马'

则 fastCheck[39532] = 0x07;  //''转化为数字为39532

因为字符可以隐式转换为整数。也可以写作 fastCheck[''] = 0x07;

至于这个0x07是怎么来的。因为马出现的位置有 12

对这些位置做位运算就可以得出7.

这个我们在添加关键中的时候就可以初始化。

public void AddKey(string word)

{.................

for(int i=0;i<word.Length;i++)

{

    m_fastCheck[word[i]] |= (UInt16)(1<<i);

}

}

有了这个,我们可以快速排除一些不是脏字字符。还可以更快吗?

可以,我们再加一个首尾字符的判断。

Uint16[] m_startCheck = new Uint16[char.MaxValue];

Uint16[] m_endCheck = new Uint16[char.MaxValue];

而这种我们保存的不是字符出现的位置。而是保存词的长度。

public void AddKey(string word)

{.................

for(int i=0;i<word.Length;i++)

{

    m_fastCheck[word[i]] |= (UInt16)(1<<i);

}

Uint16 mask = (UInt16)(1<<word.Length-1);

m_startCheck[word[0]]  |= mask;

m_endCheck[word[word.Length-1]] |=  mask;

}

就这样,在进行查找的时候。我们先判断对应位置的字符出现地位置是否正确,

再判断首尾字符的长度是否要求。如果这些条件都满足,再进行hash查找。

方法如下:

 public string FindOne(string text)

        {

            for (int index = 0; index < text.Length; index++)

            {

                int count = 0;

                int maxIndex = Math.Min(maxWordLength + index, text.Length);

                char begin = text[index];

                for (int j = index; j < maxIndex; j++)

                {

                    char current = text[j];

                    UInt16 mask = (UInt16)(1 << count);

                    //先判断字符出现的位置是否正确

                    if ((m_fastCheck[current] & mask) == 0)

                    {

                        index += count;

                        break;

                    }

                    ++count;

                    //再判断首字符和尾字符的长度是否正确.

                    if ((m_startLength[begin] & mask) > 0 && (m_endLength[current] & mask) > 0)

                    {

                        //进行hash比较

                        .........................

                    }

                }

            }

            return string.Empty;

        }

至此,整个查找方法就完成了。脏字替换跟查找的方法差不多。

为了减少字符串的截取,我重写了一个HashSet, 支持bool  Contains(string text,int offset,int coung)的方式进行调用.

完整的代码下载:

转载于:https://www.cnblogs.com/yishion-liu/archive/2011/10/20/2219241.html

你可能感兴趣的文章
DRF的版本控制,认证,权限和频率限制
查看>>
Linux crontab 命令格式与详细例子
查看>>
百度地图Api进阶教程-地图鼠标左右键操作实例和鼠标样式6.html
查看>>
游标使用
查看>>
LLBL Gen Pro 设计器使用指南
查看>>
SetCapture() & ReleaseCapture() 捕获窗口外的【松开左键事件】: WM_LBUTTONUP
查看>>
PLSQL Developer使用技巧
查看>>
Android 设置界面的圆角选项
查看>>
百度地图api服务端根据经纬度得到地址
查看>>
使用yum更新时不升级Linux内核的方法
查看>>
sqlserver计算时间差DATEDIFF 函数
查看>>
51nod1307(暴力树剖/二分&dfs/并查集)
查看>>
用户体验分析: 以 “南通市图书馆微信公众号” 为例
查看>>
linux的管道 |和grep命令以及一些其他命令(diff,echo,cat,date,time,wc,which,whereis,gzip,zcat,unzip,sort)...
查看>>
Nginx和PHP-FPM的启动、重启、停止脚本分享
查看>>
cookie 和session 的区别详解
查看>>
Vuex-状态管理模式
查看>>
浮点数运算的精度问题:以js语言为例
查看>>
数据挖掘领域十大经典算法
查看>>
【C语言】09-字符串
查看>>