<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Web Development Notes &#187; Algorithm &amp; Life</title>
	<atom:link href="http://blog.eood.cn/category/algorithm-and-life/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.eood.cn</link>
	<description>PHP, Drupal, Erlang, MySQL, Java, MongoDB, Linux, vim, ssh, screen etc</description>
	<lastBuildDate>Sat, 31 Dec 2011 12:49:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>What tools and software used for development</title>
		<link>http://blog.eood.cn/what-tools-and-software-used-fro-development</link>
		<comments>http://blog.eood.cn/what-tools-and-software-used-fro-development#comments</comments>
		<pubDate>Sun, 19 Jun 2011 04:25:34 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>
		<category><![CDATA[Development tools]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/?p=1679</guid>
		<description><![CDATA[Recently. I totally changed my development tools at home. I can not change that at the office since that will also be lots of .NET development and the project related to M$ OFFICE SDK. Developers always interested to share or show off there development tools, because they want to improve there productivity. You can see [...]]]></description>
			<content:encoded><![CDATA[<p>Recently. I totally changed my development tools at home. I can not change that at the office since that will also be lots of .NET development and the project related to M$ OFFICE SDK.</p>
<p>Developers always interested to share or show off there development tools, because they want to improve there productivity.</p>
<p>You can see how developers care about there development machine and tools:</p>
<p><img class=" size-full wp-image-1681" title="tools_software_use" src="http://blog.eood.cn/wp-content/uploads/2011/06/tools_software_use.gif" alt="" width="590" height="400" /><br />
What is my development tools and software?</p>
<p>I use Ubuntu 11.04 as the main OS. There will be tons of work to do after you install the default Ubuntu.</p>
<p>I installed more fonts such as MSYH, Arial, then you will see the similar web page when you surfing the web.</p>
<p>Change the Ubuntu theme back to Ubuntu 10 style.</p>
<p>Soft wares installed under Ubuntu:</p>
<p>1. JDK (power lots of tools, support JAVA development)</p>
<p>2. Chromium (Main browser)</p>
<p>3. GIMP (Photoshop under Linux)</p>
<p>4. Dropbox (Sync tool for my documents)</p>
<p>5. Filezilla (FTP client)</p>
<p>6. Skype (Chatting tool)</p>
<p>7. IDE:</p>
<p>Aptana (Support PHP, Python, Ruby developement. But not used very frequently)</p>
<p>Eclipse (Java development)</p>
<p>Gvim (My main development tool)</p>
<p>8. Ubuntu tweak (configuration tool)</p>
<p>9. Chromium plugins:</p>
<p>Google reader notifier</p>
<p>Screen capture</p>
<p>Color pick</p>
<p>&#8230;</p>
<p>10. Vim plugins:</p>
<p>Vim wiki</p>
<p>Calander</p>
<p>ctags</p>
<p>Nerdtree</p>
<p>bufferexplorer</p>
<p>taglist</p>
<p>zencoding</p>
<p>&#8230;</p>
<p>11. Avant window navigator (Similar as Dock in Mac OS)</p>
<p><img class="size-full wp-image-1682" title="avant" src="http://blog.eood.cn/wp-content/uploads/2011/06/avant.png" alt="" width="426" height="75" /></p>
<p>12. Mysql, PHP, Apache2, Nodejs, mongodb, git, svn, redis and lots of shell scripts to complete tasks.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/what-tools-and-software-used-fro-development/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>经典算法书</title>
		<link>http://blog.eood.cn/%e7%bb%8f%e5%85%b8%e7%ae%97%e6%b3%95%e4%b9%a6</link>
		<comments>http://blog.eood.cn/%e7%bb%8f%e5%85%b8%e7%ae%97%e6%b3%95%e4%b9%a6#comments</comments>
		<pubDate>Fri, 05 Mar 2010 14:20:54 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>
		<category><![CDATA[My Reading]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/?p=893</guid>
		<description><![CDATA[1. CLRS 算法导论 2. Algorithms 算法概论 3. Algorithm Design 算法设计 4. SICP 计算机程序的构造和解释 5. Concrete Mathematics 具体数学 6. Introduction to The Design and Analysis of Algorithms 算法设计与分析基础 7. 编程之美&#8211;微软技术面试心得 8. Fundamentals of Algorithmics 算法基础 9. How to solve it 怎样解题 10. Programming interviews exposed 程序员面试攻略 11. Programming Pearls 编程珠玑 12. 算法艺术与信息学竞赛 13. An Introduction to [...]]]></description>
			<content:encoded><![CDATA[<p>1. CLRS 算法导论<br />
2. Algorithms 算法概论<br />
3. Algorithm Design 算法设计<br />
4. SICP 计算机程序的构造和解释<br />
5. Concrete Mathematics 具体数学<br />
6. Introduction to The Design and Analysis of Algorithms 算法设计与分析基础<br />
7. 编程之美&#8211;微软技术面试心得<br />
8. Fundamentals of Algorithmics 算法基础<br />
9. How to solve it 怎样解题<br />
10. Programming interviews exposed 程序员面试攻略<br />
11. Programming Pearls 编程珠玑<br />
12. 算法艺术与信息学竞赛<br />
13. An Introduction to Probability Theory and Its Applications<br />
14. Numerical Analysis by Richard L. Burden,J. Douglas Faires<br />
数值分析，讨论各种数值算法，比如插值、拟合、积分、微分方程的求解、线性和非线性方程组求解等。<br />
15. TAOCP  <a href="http://www-cs-faculty.stanford.edu/~uno/taocp.html">http://www-cs-faculty.stanford.edu/~uno/taocp.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/%e7%bb%8f%e5%85%b8%e7%ae%97%e6%b3%95%e4%b9%a6/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>N-Gram 算法用来做相似度比较</title>
		<link>http://blog.eood.cn/n-gram-spell-checking</link>
		<comments>http://blog.eood.cn/n-gram-spell-checking#comments</comments>
		<pubDate>Sat, 06 Feb 2010 18:14:47 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/?p=780</guid>
		<description><![CDATA[N-Gram有很多应用，但是我们只用来做相似分析。基本思路来自Grzegorz Kondrak 2005年的一篇论文。http://webdocs.cs.ualberta.ca/~kondrak/papers/spire05.pdf 最近在做Translation memory的时候用到比较字符串相似度的算法。在机器翻译或者语言识别领域之所以能使用相似度算法其实是基于一种假设，相似的词具有相似的意义。 什么是N-Gram算法？ N-Gram 模型基于这样一种假设，第n个词的出现只与前面n-1个词相关，而与其它任何词都不相关，整句的概率就是各个词出现概率的乘积。在拼写检查里即是一个字母的出现概率只和前n-1个字母的出现概率相关,并且是前n-1个字母出现概率的乘积。 如何比较2个字符串的相似度？ 一般情况我们会考虑用edit distance 或者LCS。前边的论文证实了这两种算法都是N-Gram的简化版本。 在搜索引擎里一般是用来做拼写检查或者提示，比如你在百度或者google输入一个词就会有相关的词提示出来。]]></description>
			<content:encoded><![CDATA[<p><img class="size-medium wp-image-800 alignright" title="n-gram" src="http://blog.eood.cn/wp-content/uploads/2010/02/n-gram-300x175.gif" alt="" width="300" height="175" /></p>
<p>N-Gram有很多应用，但是我们只用来做相似分析。基本思路来自Grzegorz Kondrak 2005年的一篇论文。http://webdocs.cs.ualberta.ca/~kondrak/papers/spire05.pdf</p>
<p>最近在做Translation memory的时候用到比较字符串相似度的算法。在机器翻译或者语言识别领域之所以能使用相似度算法其实是基于一种假设，相似的词具有相似的意义。</p>
<p>什么是N-Gram算法？<br />
N-Gram 模型基于这样一种假设，第n个词的出现只与前面n-1个词相关，而与其它任何词都不相关，整句的概率就是各个词出现概率的乘积。在拼写检查里即是一个字母的出现概率只和前n-1个字母的出现概率相关,并且是前n-1个字母出现概率的乘积。<br />
如何比较2个字符串的相似度？</p>
<p>一般情况我们会考虑用edit distance 或者LCS。前边的论文证实了这两种算法都是N-Gram的简化版本。</p>
<p>在搜索引擎里一般是用来做拼写检查或者提示，比如你在百度或者google输入一个词就会有相关的词提示出来。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/n-gram-spell-checking/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>转 A* 算法求解最短路径</title>
		<link>http://blog.eood.cn/%e8%bd%aca%2a%e7%ae%97%e6%b3%95%e6%b1%82%e8%a7%a3%e6%9c%80%e7%9f%ad%e8%b7%af%e5%be%84</link>
		<comments>http://blog.eood.cn/%e8%bd%aca%2a%e7%ae%97%e6%b3%95%e6%b1%82%e8%a7%a3%e6%9c%80%e7%9f%ad%e8%b7%af%e5%be%84#comments</comments>
		<pubDate>Thu, 06 Nov 2008 18:03:22 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/articles/152</guid>
		<description><![CDATA[　近来不少的朋友问我关于&#160;A*&#160;算法的问题,&#160;目的是写一个搜索最短路径的程序.&#160;这个在鼠标控制精灵运动的游戏中(不算智冠出的那些用鼠标充当键盘方向键的弱智&#160;RPG)大量使用,尤其是即时战略类的.&#160;但是我个人认为&#160;A*&#160;算法只适合处理静态路径求解,对即时战略游戏中大量对象堵塞过道时,疏通交通很难实现(也不是不能实现,&#160;这需要一个相当好的估价函数,且不能一次搜索路径) 　　我奇怪的是,&#160;A*&#160;算法应该是算法课的基础知识了,&#160;任何一个系统学习过算法的人都应该了解,&#160;本不应该我在这里乱写一通,&#160;大家随意翻本将计算机算法的书,&#160;就应该看的到.&#160;(将&#160;AI&#160;的书了更是少不了)&#160;不过既然许多朋友问起,&#160;在各个讨论组,&#160;BBS&#160;等地方也屡次见人提到,&#160;特花一下午时间完成本文和附带的程序,&#160;满足我们广大业余游戏制作爱好者的求知欲,&#160;专业人士免看,&#160;以免班门弄斧&#160;^_^&#160;不过如有错误一定指出哟. 　　如果您的上网时间很宝贵,请下载我注释过的源码(3k)离线研究 　　在介绍&#160;A*&#160;算法前,先提一下广度优先搜索,广度优先搜索就是每次将当前状态可能发展的策略逐层展开,比如一个地图中,对象允许向四个方向移动,&#160;那么,就将地点处,对象向上下左右各移动一步,&#160;将四个状态都保存在内存中,&#160;然后再从这四个出发点向各自的四个方向再移动一步&#8230;&#160;(当然这里可以剔除不合理的移动方法,比如不准向回移动)实际上,&#160;整个搜索好似一个圆形向外展开,直到到达目的地,很明显这样求解一定能找到最优解,但节点展开的数量是和距离成级数增加的,&#160;真的用在游戏中,&#160;玩家会抱怨内存128M&#160;也不够用了&#160;^_^&#160;而且伴随待处理节点数的增加,&#160;处理速度也会迅速减慢&#8230;&#160;可以说这个算法并不实用 　　而&#160;A*&#160;算法实际是一种启发式搜索,&#160;所谓启发式搜索,就是利用一个估价函数评估每次的的决策的价值,&#160;决定先尝试哪一种方案.&#160;这样可以极大的优化普通的广度优先搜索.&#160;一般来说,&#160;从出发点(A)到目的地(B)的最短距离是固定的,我们可以写一个函数&#160;judge()&#160;估计&#160;A&#160;到&#160;B&#160;的最短距离,&#160;如果程序已经尝试着从出发点(A)&#160;沿着某条路线移动到了&#160;C&#160;点,&#160;那么我们认为这个方案的&#160;A&#160;B&#160;间的估计距离为&#160;A&#160;到&#160;C&#160;实际已经行走了的距离&#160;H&#160;加上用&#160;judge()&#160;估计出的&#160;C&#160;到&#160;B&#160;的距离.&#160;如此,&#160;无论我们的程序搜索展开到哪一步,&#160;都会算出一个评估值,&#160;每一次决策后,&#160;将评估值和等待处理的方案一起排序,&#160;然后挑出待处理的各个方案中最有可能是最短路线的一部分的方案展开到下一步,&#160;一直循环到对象移动到目的地,&#160;或所有方案都尝试过却没有找到一条通向目的地的路径则结束.&#160;(通常在游戏里还要设置超时控制的代码,当内存消耗过大或用时过久就退出搜索) 　　完了?&#160;没有.&#160;怎么写这个算法中的估价函数非常的重要,如何保证一定能找到最短路径呢?&#160;充要条件是,&#160;你的估价函数算出的两点间的距离必须小于等于实际距离.&#160;这个可以从数学上严格证明,有兴趣可以自己去查阅相关资料.&#160;如果你的估价函数不满足这点,&#160;就只能叫做&#160;A&#160;算法,&#160;并不能保证最后的结果是最优的,但它可能速度非常的快.&#160;而游戏中我们也不一定非要得到最优解的.&#160;但无疑,&#160;满足那个条件的&#160;A*&#160;算法中,&#160;估计值越接近真实值的估价函数就做的越好,&#160;下面给出的程序,我只使用了一个相当简单的估价函数:&#160;求出两点中,若无障碍物的情况下的最短路径.&#160;如果您想写出快速的寻路算法,&#160;请自己寻找好的估价函数吧,有时间的时候,我会对此另文叙述&#160;;-) &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 转贴的。 启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估，得到最好的位置，再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径，提到了效率。在启发式搜索中，对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。我们先看看估价是如何表示的。 　　启发中的估价是用估价函数表示的，如： f(n)&#160;=&#160;g(n)&#160;+&#160;h(n)&#160; 　　其中f(n)&#160;是节点n的估价函数，g(n)实在状态空间中从初始节点到n节点的实际代价，h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息，因为g(n)是已知的。如果说详细点，g(n)代表了搜索的广度的优先趋势。但是当h(n)&#160;&#62;&#62;&#160;g(n)时，可以省略g(n)，而提高效率。 启发式搜索其实有很多的算法，比如：局部择优搜索法、最好优先搜索法等等。当然A*也是。这些算法都使用了启发函数，但在具体的选取最佳搜索节点时的策略不同。象局部择优搜索法，就是在搜索的过程中选取&#8220;最佳节点&#8221;后舍弃其他的兄弟节点，父亲节点，而一直得搜索下去。这种搜索的结果很明显，由于舍弃了其他的节点，可能也把最好的节点都舍弃了，因为求解的最佳节点只是在该阶段的最佳并不一定是全局的最佳。最好优先就聪明多了，他在搜索时，便没有舍弃节点（除非该节点是死节点），在每一步的估价中都把当前的节点和以前的节点的估价值比较得到一个&#8220;最佳的节点&#8221;。这样可以有效的防止&#8220;最佳节点&#8221;的丢失。那么A*算法又是一种什么样的算法呢？其实A*算法也是一种最好优先的算法。只不过要加上一些约束条件罢了。由于在一些问题求解时，我们希望能够求解出状态空间搜索的最短路径，也就是用最快的方法求解问题，A*就是干这种事情的！我们先下个定义，如果一个估价函数可以找出最短的路径，我们称之为可采纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价函数可表示为： f&#8217;(n)&#160;=&#160;g&#8217;(n)&#160;+&#160;h&#8217;(n)&#160; 　　这里，f&#8217;(n)是估价函数，g&#8217;(n)是起点到终点的最短路径值，h&#8217;(n)是n到目标的最断路经的启发值。由于这个f&#8217;(n)其实是无法预先知道的，所以我们用前面的估价函数f(n)做近似。g(n)代替g&#8217;(n)，但&#160;g(n)&#62;=g&#8217;(n)才可（大多数情况下都是满足的，可以不用考虑），h(n)代替h&#8217;(n)，但h(n)&#60;=h&#8217;(n)才可（这一点特别的重要）。可以证明应用这样的估价函数是可以找到最短路径的，也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。 　　举一个例子，其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数，h(n)=0，这种h(n)肯定小于h&#8217;(n)，所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。 再说一个问题，就是有关h(n)启发函数的信息性。h(n)的信息性通俗点说其实就是在估计一个节点的值时的约束条件，如果信息越多或约束条件越多则排除的节点就越多，估价函数越好或说这个算法越好。这就是为什么广度优先算法的那么臭的原因了，谁叫它的h(n)=0，一点启发信息都没有。但在游戏开发中由于实时性的问题，h(n)的信息越多，它的计算量就越大，耗费的时间就越多。就应该适当的减小h(n)的信息，即减小约束条件。但算法的准确性就差了，这里就有一个平衡的问题。]]></description>
			<content:encoded><![CDATA[<p>　近来不少的朋友问我关于&nbsp;A*&nbsp;算法的问题,&nbsp;目的是写一个搜索最短路径的程序.&nbsp;这个在鼠标控制精灵运动的游戏中(不算智冠出的那些用鼠标充当键盘方向键的弱智&nbsp;RPG)大量使用,尤其是即时战略类的.&nbsp;但是我个人认为&nbsp;A*&nbsp;算法只适合处理静态路径求解,对即时战略游戏中大量对象堵塞过道时,疏通交通很难实现(也不是不能实现,&nbsp;这需要一个相当好的估价函数,且不能一次搜索路径) </p>
<p>　　我奇怪的是,&nbsp;A*&nbsp;算法应该是算法课的基础知识了,&nbsp;任何一个系统学习过算法的人都应该了解,&nbsp;本不应该我在这里乱写一通,&nbsp;大家随意翻本将计算机算法的书,&nbsp;就应该看的到.&nbsp;(将&nbsp;AI&nbsp;的书了更是少不了)&nbsp;不过既然许多朋友问起,&nbsp;在各个讨论组,&nbsp;BBS&nbsp;等地方也屡次见人提到,&nbsp;特花一下午时间完成本文和附带的程序,&nbsp;满足我们广大业余游戏制作爱好者的求知欲,&nbsp;专业人士免看,&nbsp;以免班门弄斧&nbsp;^_^&nbsp;不过如有错误一定指出哟. </p>
<p>　　如果您的上网时间很宝贵,请下载我注释过的源码(3k)离线研究 </p>
<p>　　在介绍&nbsp;A*&nbsp;算法前,先提一下广度优先搜索,广度优先搜索就是每次将当前状态可能发展的策略逐层展开,比如一个地图中,对象允许向四个方向移动,&nbsp;那么,就将地点处,对象向上下左右各移动一步,&nbsp;将四个状态都保存在内存中,&nbsp;然后再从这四个出发点向各自的四个方向再移动一步&#8230;&nbsp;(当然这里可以剔除不合理的移动方法,比如不准向回移动)实际上,&nbsp;整个搜索好似一个圆形向外展开,直到到达目的地,很明显这样求解一定能找到最优解,但节点展开的数量是和距离成级数增加的,&nbsp;真的用在游戏中,&nbsp;玩家会抱怨内存128M&nbsp;也不够用了&nbsp;^_^&nbsp;而且伴随待处理节点数的增加,&nbsp;处理速度也会迅速减慢&#8230;&nbsp;可以说这个算法并不实用 </p>
<p>　　而&nbsp;A*&nbsp;算法实际是一种启发式搜索,&nbsp;所谓启发式搜索,就是利用一个估价函数评估每次的的决策的价值,&nbsp;决定先尝试哪一种方案.&nbsp;这样可以极大的优化普通的广度优先搜索.&nbsp;一般来说,&nbsp;从出发点(A)到目的地(B)的最短距离是固定的,我们可以写一个函数&nbsp;judge()&nbsp;估计&nbsp;A&nbsp;到&nbsp;B&nbsp;的最短距离,&nbsp;如果程序已经尝试着从出发点(A)&nbsp;沿着某条路线移动到了&nbsp;C&nbsp;点,&nbsp;那么我们认为这个方案的&nbsp;A&nbsp;B&nbsp;间的估计距离为&nbsp;A&nbsp;到&nbsp;C&nbsp;实际已经行走了的距离&nbsp;H&nbsp;加上用&nbsp;judge()&nbsp;估计出的&nbsp;C&nbsp;到&nbsp;B&nbsp;的距离.&nbsp;如此,&nbsp;无论我们的程序搜索展开到哪一步,&nbsp;都会算出一个评估值,&nbsp;每一次决策后,&nbsp;将评估值和等待处理的方案一起排序,&nbsp;然后挑出待处理的各个方案中最有可能是最短路线的一部分的方案展开到下一步,&nbsp;一直循环到对象移动到目的地,&nbsp;或所有方案都尝试过却没有找到一条通向目的地的路径则结束.&nbsp;(通常在游戏里还要设置超时控制的代码,当内存消耗过大或用时过久就退出搜索) </p>
<p>　　完了?&nbsp;没有.&nbsp;怎么写这个算法中的估价函数非常的重要,如何保证一定能找到最短路径呢?&nbsp;充要条件是,&nbsp;你的估价函数算出的两点间的距离必须小于等于实际距离.&nbsp;这个可以从数学上严格证明,有兴趣可以自己去查阅相关资料.&nbsp;如果你的估价函数不满足这点,&nbsp;就只能叫做&nbsp;A&nbsp;算法,&nbsp;并不能保证最后的结果是最优的,但它可能速度非常的快.&nbsp;而游戏中我们也不一定非要得到最优解的.&nbsp;但无疑,&nbsp;满足那个条件的&nbsp;A*&nbsp;算法中,&nbsp;估计值越接近真实值的估价函数就做的越好,&nbsp;下面给出的程序,我只使用了一个相当简单的估价函数:&nbsp;求出两点中,若无障碍物的情况下的最短路径.&nbsp;如果您想写出快速的寻路算法,&nbsp;请自己寻找好的估价函数吧,有时间的时候,我会对此另文叙述&nbsp;;-) </p>
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; </p>
<p>转贴的。 <br />
启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估，得到最好的位置，再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径，提到了效率。在启发式搜索中，对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。我们先看看估价是如何表示的。 <br />
　　启发中的估价是用估价函数表示的，如： </p>
<p>f(n)&nbsp;=&nbsp;g(n)&nbsp;+&nbsp;h(n)&nbsp; </p>
<p>　　其中f(n)&nbsp;是节点n的估价函数，g(n)实在状态空间中从初始节点到n节点的实际代价，h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息，因为g(n)是已知的。如果说详细点，g(n)代表了搜索的广度的优先趋势。但是当h(n)&nbsp;&gt;&gt;&nbsp;g(n)时，可以省略g(n)，而提高效率。 <br />
启发式搜索其实有很多的算法，比如：局部择优搜索法、最好优先搜索法等等。当然A*也是。这些算法都使用了启发函数，但在具体的选取最佳搜索节点时的策略不同。象局部择优搜索法，就是在搜索的过程中选取&ldquo;最佳节点&rdquo;后舍弃其他的兄弟节点，父亲节点，而一直得搜索下去。这种搜索的结果很明显，由于舍弃了其他的节点，可能也把最好的节点都舍弃了，因为求解的最佳节点只是在该阶段的最佳并不一定是全局的最佳。最好优先就聪明多了，他在搜索时，便没有舍弃节点（除非该节点是死节点），在每一步的估价中都把当前的节点和以前的节点的估价值比较得到一个&ldquo;最佳的节点&rdquo;。这样可以有效的防止&ldquo;最佳节点&rdquo;的丢失。那么A*算法又是一种什么样的算法呢？其实A*算法也是一种最好优先的算法。只不过要加上一些约束条件罢了。由于在一些问题求解时，我们希望能够求解出状态空间搜索的最短路径，也就是用最快的方法求解问题，A*就是干这种事情的！我们先下个定义，如果一个估价函数可以找出最短的路径，我们称之为可采纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价函数可表示为： </p>
<p>f&#8217;(n)&nbsp;=&nbsp;g&#8217;(n)&nbsp;+&nbsp;h&#8217;(n)&nbsp; </p>
<p>　　这里，f&#8217;(n)是估价函数，g&#8217;(n)是起点到终点的最短路径值，h&#8217;(n)是n到目标的最断路经的启发值。由于这个f&#8217;(n)其实是无法预先知道的，所以我们用前面的估价函数f(n)做近似。g(n)代替g&#8217;(n)，但&nbsp;g(n)&gt;=g&#8217;(n)才可（大多数情况下都是满足的，可以不用考虑），h(n)代替h&#8217;(n)，但h(n)&lt;=h&#8217;(n)才可（这一点特别的重要）。可以证明应用这样的估价函数是可以找到最短路径的，也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。 <br />
　　举一个例子，其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数，h(n)=0，这种h(n)肯定小于h&#8217;(n)，所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。 <br />
再说一个问题，就是有关h(n)启发函数的信息性。h(n)的信息性通俗点说其实就是在估计一个节点的值时的约束条件，如果信息越多或约束条件越多则排除的节点就越多，估价函数越好或说这个算法越好。这就是为什么广度优先算法的那么臭的原因了，谁叫它的h(n)=0，一点启发信息都没有。但在游戏开发中由于实时性的问题，h(n)的信息越多，它的计算量就越大，耗费的时间就越多。就应该适当的减小h(n)的信息，即减小约束条件。但算法的准确性就差了，这里就有一个平衡的问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/%e8%bd%aca%2a%e7%ae%97%e6%b3%95%e6%b1%82%e8%a7%a3%e6%9c%80%e7%9f%ad%e8%b7%af%e5%be%84/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VSM应用</title>
		<link>http://blog.eood.cn/vsm%e5%ba%94%e7%94%a8</link>
		<comments>http://blog.eood.cn/vsm%e5%ba%94%e7%94%a8#comments</comments>
		<pubDate>Thu, 06 Nov 2008 17:37:53 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/articles/151</guid>
		<description><![CDATA[余弦定理和新闻的分类似乎是两件八杆子打不着的事，但是它们确有紧密的联系。具体说，新闻的分类很大程度上依靠余弦定理。 Google 的新闻是自动分类和整理的。所谓新闻的分类无非是要把相似的新闻放到一类中。计算机其实读不懂新闻，它只能快速计算。这就要求我们设计一个算法来算出任意两篇新闻的相似性。为了做到这一点，我们需要想办法用一组数字来描述一篇新闻。 我们来看看怎样找一组数字，或者说一个向量来描述一篇新闻。回忆一下我们在&#8220;如何度量网页相关性&#8221;一文中介绍的TF/IDF 的概念。对于一篇新闻中的所有实词，我们可以计算出它们的单文本词汇频率/逆文本频率值（TF/IDF)。不难想象，和新闻主题有关的那些实词频率高，TF/IDF 值很大。我们按照这些实词在词汇表的位置对它们的 TF/IDF 值排序。比如，词汇表有六万四千个词，分别为 单词编号 汉字词 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 1 阿 2 啊 3 阿斗 4 阿姨 &#8230; 789 服装 &#8230;. 64000 做作 在一篇新闻中，这 64,000 个词的 TF/IDF 值分别为 单词编号 TF/IDF 值 ============== 1 0 2 0.0034 3 0 4 0.00052 5 0 &#8230; 789 0.034 &#8230; 64000 0.075 如果单词表中的某个次在新闻中没有出现，对应的值为零，那么这 64,000 个数，组成一个64,000维的向量。我们就用这个向量来代表这篇新闻，并成为新闻的特征向量。如果两篇新闻的特征向量相近，则对应的新闻内容相似，它们应当归在一类，反之亦然。 学过向量代数的人都知道，向量实际上是多维空间中有方向的线段。如果两个向量的方向一致，即夹角接近零，那么这两个向量就相近。而要确定两个向量方向是否一致，这就要用到余弦定理计算向量的夹角了。 余弦定理对我们每个人都不陌生，它描述了三角形中任何一个夹角和三个边的关系，换句话说，给定三角形的三条边，我们可以用余弦定理求出三角形各个角的角度。假定三角形的三条边为 [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-size: 10pt">余弦定理和新闻的分类似乎是两件八杆子打不着的事，但是它们确有紧密的联系。具体说，新闻的分类很大程度上依靠余弦定理。</p>
<p>Google 的新闻是自动分类和整理的。所谓新闻的分类无非是要把相似的新闻放到一类中。计算机其实读不懂新闻，它只能快速计算。这就要求我们设计一个算法来算出任意两篇新闻的相似性。为了做到这一点，我们需要想办法用一组数字来描述一篇新闻。</p>
<p>我们来看看怎样找一组数字，或者说一个向量来描述一篇新闻。回忆一下我们在&ldquo;</span><a href="http://googlechinablog.com/2006/06/blog-post_27.html" target="_blank"><span style="font-size: 10pt"><font color="#1a8bc8">如何度量网页相关性</font></span></a><span style="font-size: 10pt">&rdquo;一文中介绍的TF/IDF 的概念。对于一篇新闻中的所有实词，我们可以计算出它们的单文本词汇频率/逆文本频率值（TF/IDF)。不难想象，和新闻主题有关的那些实词频率高，TF/IDF 值很大。我们按照这些实词在词汇表的位置对它们的 TF/IDF 值排序。比如，词汇表有六万四千个词，分别为</p>
<p>单词编号 汉字词<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
1 阿<br />
2 啊<br />
3 阿斗<br />
4 阿姨<br />
&#8230;<br />
789 服装<br />
&#8230;.<br />
64000 做作</p>
<p>在一篇新闻中，这 64,000 个词的 TF/IDF 值分别为</p>
<p>单词编号 TF/IDF 值<br />
==============<br />
1 0<br />
2 0.0034<br />
3 0<br />
4 0.00052<br />
5 0<br />
&#8230;<br />
789 0.034<br />
&#8230;<br />
64000 0.075</p>
<p>
如果单词表中的某个次在新闻中没有出现，对应的值为零，那么这 64,000 个数，组成一个64,000维的向量。我们就用这个向量来代表这篇新闻，并成为新闻的特征向量。如果两篇新闻的特征向量相近，则对应的新闻内容相似，它们应当归在一类，反之亦然。</p>
<p>学过向量代数的人都知道，向量实际上是多维空间中有方向的线段。如果两个向量的方向一致，即夹角接近零，那么这两个向量就相近。而要确定两个向量方向是否一致，这就要用到余弦定理计算向量的夹角了。</p>
<p>余弦定理对我们每个人都不陌生，它描述了三角形中任何一个夹角和三个边的关系，换句话说，给定三角形的三条边，我们可以用余弦定理求出三角形各个角的角度。假定三角形的三条边为 a, b 和 c，对应的三个角为 A, B 和 C，那么角 A 的余弦 &#8211;</p>
<p><img style="border-right: 1px solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid" alt="" src="http://googlechinablog.com/uploaded_images/2c4eacd0e4ee4aeb29f0833be0a0442e-771570.png" border="0" /></p>
<p>如果我们将三角形的两边 b 和 c 看成是两个向量，那么上述公式等价于</p>
<p><img style="border-right: 1px solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid" alt="" src="http://googlechinablog.com/uploaded_images/cosine-a-744082.png" border="0" /></p>
<p>其中分母表示两个向量 b 和 c 的长度，分子表示两个向量的内积。举一个具体的例子，假如新闻 X 和新闻 Y 对应向量分别是<br />
x1,x2,&#8230;,x64000 和<br />
y1,y2,&#8230;,y64000,<br />
那么它们夹角的余弦等于，</p>
<p><img style="border-right: 1px solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid" alt="" src="http://googlechinablog.com/uploaded_images/cos_theta-757119.JPG" border="0" /></p>
<p>当两条新闻向量夹角的余弦等于一时，这两条新闻完全重复（用这个办法可以删除重复的网页）；当夹角的余弦接近于一时，两条新闻相似，从而可以归成一类；夹角的余弦越小，两条新闻越不相关。</p>
<p><img style="border-right: 1px solid; border-top: 1px solid; border-left: 1px solid; border-bottom: 1px solid" alt="" src="http://googlechinablog.com/uploaded_images/news-798354.jpg" border="0" /></p>
<p>我们在中学学习余弦定理时，恐怕很难想象它可以用来对新闻进行分类。在这里，我们再一次看到数学工具的用途。</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/vsm%e5%ba%94%e7%94%a8/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>空间相似度 分类</title>
		<link>http://blog.eood.cn/%e7%a9%ba%e9%97%b4%e7%9b%b8%e4%bc%bc%e5%ba%a6%e5%88%86%e7%b1%bb</link>
		<comments>http://blog.eood.cn/%e7%a9%ba%e9%97%b4%e7%9b%b8%e4%bc%bc%e5%ba%a6%e5%88%86%e7%b1%bb#comments</comments>
		<pubDate>Thu, 06 Nov 2008 17:28:44 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>
		<category><![CDATA[vsm]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/articles/150</guid>
		<description><![CDATA[在向量空间模型中，文本泛指各种机器可读的记录。用D（Document）表示，特征项（Term，用t表示）是指出现在文档D中且能够代表该文档内容的基本语言单位，主要是由词或者短语构成，文本可以用特征项集表示为D(T1，T2，&#8230;，Tn)，其中Tk是特征项，1&#60;=k&#60;=N。例如一篇文档中有a、b、c、d四个特征项，那么这篇文档就可以表示为D(a，b，c，d)。对含有n个特征项的文本而言，通常会给每个特征项赋予一定的权重表示其重要程度。即D＝D(T1，W1；T2，W2；&#8230;，Tn，Wn)，简记为D＝D(W1，W2，&#8230;，Wn)，我们把它叫做文本D的向量表示。其中Wk是Tk的权重，1&#60;=k&#60;=N。在上面那个例子中，假设a、b、c、d的权重分别为30，20，20，10，那么该文本的向量表示为D(30，20，20，10)。在向量空间模型中，两个文本D1和D2之间的内容相关度Sim(D1，D2)常用向量之间夹角的余弦值表示，公式为： 其中，W1k、W2k分别表示文本D1和D2第K个特征项的权值，1&#60;=k&#60;=N。 在自动归类中，我们可以利用类似的方法来计算待归类文档和某类目的相关度。例如文本D1的特征项为a，b，c，d，权值分别为30，20，20，10，类目C1的特征项为a，c，d，e，权值分别为40，30，20，10，则D1的向量表示为D1(30,20,20,10,0),C1的向量表示为C1（40，0，30，20，10），则根据上式计算出来的文本D1与类目C1相关度是0.86 在数学当中，n维向量是 V{v1, v2, v3, &#8230;, vn} 他的模： &#124;v&#124; = sqrt ( v1*v1 + v2*v2 + &#8230; + vn*vn ) 两个向量的点击 m*n = n1*m1 + n2*m2 + &#8230;&#8230; + nn*mn 相似度 ＝ (m*n) /(&#124;m&#124;*&#124;n&#124;) 物理意义就是两个向量的空间夹角的余弦数值 对于例子 d1*c1 = 30*40 + 20*0 + 20*30 + 10*20 + 0*10 = 2000 &#124;d1&#124; = sqrt(30*30 +20*20 [...]]]></description>
			<content:encoded><![CDATA[<p>在向量空间模型中，文本泛指各种机器可读的记录。用D（Document）表示，特征项（Term，用t表示）是指出现在文档D中且能够代表该文档内容的基本语言单位，主要是由词或者短语构成，文本可以用特征项集表示为D(T1，T2，&hellip;，Tn)，其中Tk是特征项，1&lt;=k&lt;=N。例如一篇文档中有a、b、c、d四个特征项，那么这篇文档就可以表示为D(a，b，c，d)。对含有n个特征项的文本而言，通常会给每个特征项赋予一定的权重表示其重要程度。即D＝D(T1，W1；T2，W2；&hellip;，Tn，Wn)，简记为D＝D(W1，W2，&hellip;，Wn)，我们把它叫做文本D的向量表示。其中Wk是Tk的权重，1&lt;=k&lt;=N。在上面那个例子中，假设a、b、c、d的权重分别为30，20，20，10，那么该文本的向量表示为D(30，20，20，10)。在向量空间模型中，两个文本D1和D2之间的内容相关度Sim(D1，D2)常用向量之间夹角的余弦值表示，公式为：</p>
<p><img src="http://www.xd-tech.com.cn/blog/attachments/month_0610/n20061011103816.jpg" alt="" /></p>
<p>其中，W1k、W2k分别表示文本D1和D2第K个特征项的权值，1&lt;=k&lt;=N。 <br />
在自动归类中，我们可以利用类似的方法来计算待归类文档和某类目的相关度。例如文本D1的特征项为a，b，c，d，权值分别为30，20，20，10，类目C1的特征项为a，c，d，e，权值分别为40，30，20，10，则D1的向量表示为D1(30,20,20,10,0),C1的向量表示为C1（40，0，30，20，10），则根据上式计算出来的文本D1与类目C1相关度是0.86</p>
<p>在数学当中，n维向量是 V{v1, v2, v3, &#8230;, vn}<br />
他的模： |v| = sqrt ( v1*v1 + v2*v2 + &#8230; + vn*vn )<br />
两个向量的点击 m*n = n1*m1 + n2*m2 + &#8230;&#8230; + nn*mn<br />
相似度 ＝ (m*n) /(|m|*|n|)<br />
物理意义就是两个向量的空间夹角的余弦数值<br />
对于例子<br />
d1*c1 = 30*40 + 20*0 + 20*30 + 10*20 + 0*10 = 2000<br />
|d1| = sqrt(30*30 +20*20 + 20*20 + 10*10 + 0*0) = sqrt(1800)<br />
|c1| = sqrt(40*40 + 0*0 + 30*30 + 20*20 + 10*10) = sqrt(3000)<br />
相似度 = d1*c1/(|d1|*|c1|)= 2000/sqrt(1800*3000)= 0.86066</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/%e7%a9%ba%e9%97%b4%e7%9b%b8%e4%bc%bc%e5%ba%a6%e5%88%86%e7%b1%bb/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bloom Filter perl例子</title>
		<link>http://blog.eood.cn/bloomfilterperl%e4%be%8b%e5%ad%90</link>
		<comments>http://blog.eood.cn/bloomfilterperl%e4%be%8b%e5%ad%90#comments</comments>
		<pubDate>Sun, 19 Oct 2008 18:54:45 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/articles/144</guid>
		<description><![CDATA[如果要索引的样本数量巨大，全部放在 hash 表里，在内存中肯定放不下. 因此采用一种概率的方式，用一个短一些的串来记录，把所有的key 分别通过一组 hash 函数，来映射到串上，标记为1（初始都为0），这样就建立了一个可供检索的filter。 查询某个给定值是否存在时，让他通过所有的hash函数，找到串上对应的位置，如果对应位置上都标记为 1，则这个值&#8220;可能&#8221;存在，如果有一个位标记不为1，则这个值&#8220;肯定&#8221;不存在。 参考： http://www.chmhome.com/technology/program-design/perl/20070527/13588.htm&#8230; http://www.perl.com/2004/04/08/examples/Filter.pm perl中有 Bloom::Filter 的模块 使用示例： 1 #!/usr/bin/perl -w 2 3 use strict; 4 use Bloom::Filter; 5 6 my $bf = Bloom::Filter-&#62;new( capacity =&#62; 10, error_rate =&#62; .001 ); 7 my @keys = (&#34;albert&#34;, &#34;lee&#34;, &#34;python&#34;, &#34;perl&#34;, &#34;ruby&#34;, &#34;rebol&#34;, &#34;java&#34;,&#34;C++&#34;); 8 $bf-&#62;add( @keys ); 9 [...]]]></description>
			<content:encoded><![CDATA[<p>如果要索引的样本数量巨大，全部放在 hash 表里，在内存中肯定放不下.<br />
因此采用一种概率的方式，用一个短一些的串来记录，把所有的key 分别通过一组 hash 函数，来映射到串上，标记为1（初始都为0），这样就建立了一个可供检索的filter。 查询某个给定值是否存在时，让他通过所有的hash函数，找到串上对应的位置，如果对应位置上都标记为 1，则这个值&ldquo;可能&rdquo;存在，如果有一个位标记不为1，则这个值&ldquo;肯定&rdquo;不存在。</p>
<p>参考： <a title="http://www.chmhome.com/technology/program-design/perl/20070527/13588.html" href="http://www.chmhome.com/technology/program-design/perl/20070527/13588.html">http://www.chmhome.com/technology/program-design/perl/20070527/13588.htm&#8230;</a><br />
<a title="http://www.perl.com/2004/04/08/examples/Filter.pm" href="http://www.perl.com/2004/04/08/examples/Filter.pm">http://www.perl.com/2004/04/08/examples/Filter.pm</a></p>
<p>perl中有 Bloom::Filter 的模块 使用示例：</p>
<p>1 #!/usr/bin/perl -w<br />
2<br />
3 use strict;<br />
4 use Bloom::Filter;<br />
5<br />
6 my $bf = Bloom::Filter-&gt;new( capacity =&gt; 10, error_rate =&gt; .001 );<br />
7 my @keys = (&quot;albert&quot;, &quot;lee&quot;, &quot;python&quot;, &quot;perl&quot;, &quot;ruby&quot;, &quot;rebol&quot;, &quot;java&quot;,&quot;C++&quot;);<br />
8 $bf-&gt;add( @keys );<br />
9<br />
10 while ( &lt;&gt; ) {<br />
11 chomp;<br />
12 print &quot;Found $_\n&quot; if $bf-&gt;check( $_ );<br />
13 }<br />
14</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/bloomfilterperl%e4%be%8b%e5%ad%90/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bloom Filter算法</title>
		<link>http://blog.eood.cn/bloomfilter%e7%ae%97%e6%b3%95</link>
		<comments>http://blog.eood.cn/bloomfilter%e7%ae%97%e6%b3%95#comments</comments>
		<pubDate>Sun, 19 Oct 2008 18:51:31 +0000</pubDate>
		<dc:creator>Bruce Dou</dc:creator>
				<category><![CDATA[Algorithm & Life]]></category>

		<guid isPermaLink="false">http://blog.eood.cn/articles/143</guid>
		<description><![CDATA[URL排重之 Bloom Filter算法实现（内存与外存）-Delphi版 {&#8212;&#8212;&#8212;&#8212;参考资料&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; Bloom Filter 数据结构的原理分析 Bloom Filter 数据结构广泛地应用于网络技术中，它是由 Burton Bloom 在 1970 年提出来的。 它的优点是可以有效地节省空间，缺点是不能做到精确无误，不过这个看似很郁闷的缺点却可以使用调节参数的方法有效控制， 也可以通过不同的应用手段来避免差错。Bloom Filter 数据结构有很多应用，将在下一篇文章里叙述， 而这篇文章将简要叙述这个算法的原理和分析。 问题定义：如何用简单节省的方法将一个集合中的所有元素表述出来？ 原理：有一个集合 S = ( x1, x2, &#8230; , xn), 用一个 n bit 的数组把这个集合表示出来。 使用 k 个独立的哈希函数，将 S 中的每个元素 xi 映射到这个 n bit 的数组中的某一位上， 对于 S 中的每个元素要做 k 次哈希。n bit 的数组初始化每一位为 0 。 如图所示： 0 [...]]]></description>
			<content:encoded><![CDATA[<p><span class="tpc_title">URL排重之 Bloom Filter算法实现（内存与外存）-Delphi版</span></p>
<p><span class="tpc_content">{&#8212;&#8212;&#8212;&#8212;参考资料&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
Bloom Filter 数据结构的原理分析</p>
<p>Bloom Filter 数据结构广泛地应用于网络技术中，它是由 Burton Bloom 在 1970 年提出来的。<br />
它的优点是可以有效地节省空间，缺点是不能做到精确无误，不过这个看似很郁闷的缺点却可以使用调节参数的方法有效控制，<br />
也可以通过不同的应用手段来避免差错。Bloom Filter 数据结构有很多应用，将在下一篇文章里叙述，<br />
而这篇文章将简要叙述这个算法的原理和分析。</p>
<p>问题定义：如何用简单节省的方法将一个集合中的所有元素表述出来？<br />
原理：有一个集合 S = ( x1, x2, &#8230; , xn), 用一个 n bit 的数组把这个集合表示出来。<br />
使用 k 个独立的哈希函数，将 S 中的每个元素 xi 映射到这个 n bit 的数组中的某一位上，<br />
对于 S 中的每个元素要做 k 次哈希。n bit 的数组初始化每一位为 0 。</p>
<p>如图所示：</p>
<p>0 0 0 0 0 0 0 0 0 0 0 0</p>
<p>&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> x2_______________<br />
x1________| &nbsp;<wbr></wbr> | &nbsp;<wbr></wbr> |<br />
| &nbsp;<wbr></wbr> | &nbsp;<wbr></wbr> | &nbsp;<wbr></wbr> | &nbsp;<wbr></wbr> |<br />
0 1 0 1 0 1 0 1 0 0 1 0</p>
<p>&nbsp;<wbr></wbr> x2&#8242;_______________<br />
x1&#8242;______| &nbsp;<wbr></wbr> | &nbsp;<wbr></wbr> |<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> | | | &nbsp;<wbr></wbr> | &nbsp;<wbr></wbr> |<br />
0 1 0 1 0 1 0 1 0 0 1 0</p>
<p>从上图可见，x1 , x2 被映射到 n-bit 中，来了两个查询，x1&#8242; 和 x2&#8242; ，<br />
对这两个查询也分别做 k 个哈希映射，结果 x1&#8242; 对应的值不全是 1 ，<br />
这说明在集合S中肯定不存在和 x1&#8242; 相同的元素。而 x2&#8242; 对应的 bit 都是1，这说明 x2&#8242; 有可能存在于集合中。<br />
但是它不存在的可能性也是有的，因为不能保证不同的元素的哈希值不同。</p>
<p>下面是几个关于 bloom filter 的延伸分析。<br />
1）使用 bloom filter 可以做集合的并、交运算。只需将 n-bit 数组 OR 或 AND 就可以了。<br />
但是结果并不精确。<br />
2）bloom filter 有时会用在描述一个变化的集合上。<br />
添加一个新的集合元素进入 bloom filter 很容易，而删除从集合中删除一个元素，<br />
却不是那么简单，因为会附带着把其他元素的信息也删除掉。为了解决这个问题，<br />
使用多个 bit 位取代使用一个 bit 位。每次映射到这个位置，就加 1 。<br />
}</p>
<p>{&#8212;&#8212;-Bloom Filter 个人的理解及实现方法&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
Bloom Filter是可作为URL排重算法的一种算法.<br />
它的基本思想来源于Hash表.但又不同.<br />
Hash表的思想是通过散过函数快速定位的Hash桶位置.如果Hash冲突则开链表保存.<br />
基本上一个合适的Hash函数,和合适的Hash桶大小,会使Hash冲突变得很小.<br />
因而Hash表具有极快速的添加,查找,删除功能.也非常适合用于URL排重. 但是Hash表的实现空间效率不好.<br />
而Bloom Filter是一种Hash表思想的延伸.它并不通过Hash表开链表的形式来解决冲突.<br />
而是用多个Hash函数来计算数据,而取得多个Hash数组的下标,并标记,以多个Hash函数的计算结果来稀释冲突的机率.<br />
例如用10个Hash函数分别计算同一个数据,而得到10个数组下标,通过判断这十个下标相对应的标记位的标记即可判断是否存在.</p>
<p>我的实现方法是这样的,申请一块大内存作为数组,数组每个单位为2个字节即16位的空间,用于保存10种不同Hash算法的标记位.<br />
数组起始地址.<br />
FBasePointer<br />
那 数组第I个单位的超始位置即为 FBasePointer +2*I<br />
}</span></p>
<hr style="width: 100%; height: 2px" />
<p>
<span class="tpc_content">{类设计说明:<br />
THashFuncMan 为一个Hash函数的调用结构体,同时定义Hash函数,编号和计算结果.方便使用.</p>
<p>IBloomFilter为算法算法,各种不同的程序可通过实现该接口来保证接口统一.</p>
<p>TBloomFilterBase 自己实现了10种Hash算法的一个基类.各种存储类可通过继承它来实现.当然,也可以用组合.</p>
<p>TPointerBloomFilterBase -&gt; (TBloomFilterBase,IBloomFilter) 比较完整实现了IBloomFilter算法的类. 但它操作的指针为虚拟.要子类为指针指定内容.</p>
<p>TMemoryBloomFilter-&gt;TPointerBloomFilterBase 内存存储方式的BloomFilter算法实现类<br />
TMemoryFileBloomFilter-&gt;BloomFilter 内存映射文件存储方式的BloomFilter算法实现类,外存</p>
<p>}<br />
unit uBloomFilter;</p>
<p>interface<br />
uses<br />
Classes, SysUtils, Windows, MD5, SyncObjs, SHA1;</p>
<p>const<br />
MaxHashFuncCount = 10;<br />
type<br />
//计算Hash数组下标的函数形式<br />
//备注:该定义为通用方式,而我在下面的代码应用中的散列函数的实现中并没有用到其中的参数<br />
TGetHashIndexFunc = function(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
TGetHashIndexEvent = function(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> Cardinal): Cardinal of object;</p>
<p>//Hash数组计算对象,关链函数和编号<br />
THashFuncMan = record<br />
&nbsp;<wbr></wbr> GetHashIndexFunc: TGetHashIndexEvent;<br />
&nbsp;<wbr></wbr> Index: Integer;<br />
&nbsp;<wbr></wbr> HashIndex: Cardinal;<br />
end;</p>
<p>{&#8212;&#8212;&#8212;&#8212;&#8211;BloomFilter算法接口&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;}<br />
IBloomFilter = interface<br />
['{F8E72812-E7CD-4460-9549-7920A9C762C4}']<br />
&nbsp;<wbr></wbr> function GetMaxCount: Cardinal;</p>
<p>&nbsp;<wbr></wbr> /// &lt;summary&gt;<br />
&nbsp;<wbr></wbr> /// 查找一个字符串是否已存在<br />
&nbsp;<wbr></wbr> /// &lt;/summary&gt;<br />
&nbsp;<wbr></wbr> /// &lt;param name=&quot;AStr&quot;&gt;要查找的字符串&lt;/param&gt;<br />
&nbsp;<wbr></wbr> /// &lt;param name=&quot;AAutoAdd&quot;&gt;是否自动添加&lt;/param&gt;<br />
&nbsp;<wbr></wbr> /// &lt;returns&gt;已存在返回True,不存在返回False&lt;/returns&gt;<br />
&nbsp;<wbr></wbr> function FilterData(AStr: string; AAutoAdd: Boolean): Boolean;</p>
<p>&nbsp;<wbr></wbr> //取得Hash数组的大小<br />
&nbsp;<wbr></wbr> property MaxCount: Cardinal read GetMaxCount;</p>
<p>end;</p>
<p>{&#8212;&#8212;&#8212;&#8212;BloomFilter 的Hash算法实现的类&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
&nbsp;<wbr></wbr> 各种不同的存储或是实现可继承该类实现<br />
&nbsp;<wbr></wbr> 扩展的话,也可把10个散列算法做为事件开放给外部,让外部指定,而达到更灵活的使用方式<br />
&nbsp;<wbr></wbr> 我这里只是简单实现了十个Hash函数<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;}<br />
TBloomFilterBase = class(TInterfacedObject)<br />
private<br />
&nbsp;<wbr></wbr> //备注:因对象有临界保护,故为了性能考虑,10种散列函数所须用到的MD5Digest和SHA1Digest为类全局变量.以减少计算次数.<br />
&nbsp;<wbr></wbr> FMD5Digest: TMD5Digest;<br />
&nbsp;<wbr></wbr> FSHADigest: TSHA1Digest;<br />
&nbsp;<wbr></wbr> FLock: TCriticalSection;</p>
<p>&nbsp;<wbr></wbr> //10个取得Hash数组下标的函数<br />
&nbsp;<wbr></wbr> //暂时以MD5和SHA1以四字节四字节做为单位,每个单位独立算成HashIndex.共9个<br />
&nbsp;<wbr></wbr> //GetHashIndexFunc0取MD5的四个单位相加再除模的方法算HashIndex值<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc0(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc1(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc2(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc3(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc4(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc5(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc6(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc7(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc8(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
&nbsp;<wbr></wbr> function GetHashIndexFunc9(ABuffer: PChar; ALen: Integer; AMaxCount:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Cardinal): Cardinal;<br />
protected<br />
&nbsp;<wbr></wbr> FMaxCount:Cardinal;<br />
&nbsp;<wbr></wbr> HashFuncMans: array[0..MaxHashFuncCount - 1] of THashFuncMan;<br />
&nbsp;<wbr></wbr> procedure CelHashIndex(AStr: string);<br />
public<br />
&nbsp;<wbr></wbr> constructor Create(AMaxCount : Cardinal);<br />
&nbsp;<wbr></wbr> destructor Destroy; override;<br />
end;</p>
<p>{&#8212;&#8212;&#8212;&#8212;指针操作数组的BloomFilter实现的虚类&#8212;&#8212;&#8212;&#8211;}<br />
TPointerBloomFilterBase = class(TBloomFilterBase, IBloomFilter)<br />
private<br />
&nbsp;<wbr></wbr> FLock: TCriticalSection;<br />
protected<br />
&nbsp;<wbr></wbr> //数组保存内存起始位置. 在这里采用内存指针而不是数组是为了方便内存映射文件这种外存方式和内存方式的共同使用.<br />
&nbsp;<wbr></wbr> //而定义为PChar类型只是为了指针移动相加方便,实际应该是Pointer,但Pointer与整形相加得强转,麻烦一点<br />
&nbsp;<wbr></wbr> FBasePointer: PChar;<br />
&nbsp;<wbr></wbr><br />
&nbsp;<wbr></wbr> function GetMaxCount: Cardinal;<br />
public<br />
&nbsp;<wbr></wbr> constructor Create(AMaxCount: Integer);<br />
&nbsp;<wbr></wbr> destructor Destroy; override;<br />
&nbsp;<wbr></wbr> function FilterData(AStr: string; AAutoAdd: Boolean): Boolean;<br />
&nbsp;<wbr></wbr> property MaxCount: Cardinal read GetMaxCount;</p>
<p>end;</p>
<p>{&#8212;&#8212;&#8212;&#8212;使用内存数组的的BloomFilter实现的类&#8212;&#8212;&#8212;&#8211;}<br />
TMemoryBloomFilter = class(TPointerBloomFilterBase)<br />
public<br />
&nbsp;<wbr></wbr> constructor Create(AMaxCount: Integer);<br />
&nbsp;<wbr></wbr> destructor Destroy; override;<br />
end;</p>
<p>{&#8212;&#8212;&#8212;&#8212;使用外存文件,用内存映射文件的的BloomFilter实现的类&#8212;&#8212;&#8212;&#8211;}<br />
TMemoryFileBloomFilter = class(TPointerBloomFilterBase)<br />
private<br />
&nbsp;<wbr></wbr> hFileMap: Cardinal;<br />
&nbsp;<wbr></wbr> hFile: Cardinal;<br />
public<br />
&nbsp;<wbr></wbr> constructor Create(AFileName: string; AMaxCount: Integer; ACreateNew:<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Boolean);<br />
&nbsp;<wbr></wbr> destructor Destroy; override;<br />
end;</p>
<p>implementation</p>
<p>{ TBloomFilterBase }</p>
<p>{&#8212;&#8212;&#8212;&#8212;&#8212;10个取得Hash数组下标的函数&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-} &nbsp;<wbr></wbr><br />
constructor TBloomFilterBase.Create(AMaxCount : Cardinal);<br />
var<br />
I : Integer;<br />
begin<br />
inherited Create;</p>
<p>//&#8212;-初始化计算Hash下标的函数组&#8211; 如果修改 MaxHashFuncCount 这里也要修改<br />
HashFuncMans[0].GetHashIndexFunc := GetHashIndexFunc0;<br />
HashFuncMans[1].GetHashIndexFunc := GetHashIndexFunc1;<br />
HashFuncMans[2].GetHashIndexFunc := GetHashIndexFunc2;<br />
HashFuncMans[3].GetHashIndexFunc := GetHashIndexFunc3;<br />
HashFuncMans[4].GetHashIndexFunc := GetHashIndexFunc4;<br />
HashFuncMans[5].GetHashIndexFunc := GetHashIndexFunc5;<br />
HashFuncMans[6].GetHashIndexFunc := GetHashIndexFunc6;<br />
HashFuncMans[7].GetHashIndexFunc := GetHashIndexFunc7;<br />
HashFuncMans[8].GetHashIndexFunc := GetHashIndexFunc8;<br />
HashFuncMans[9].GetHashIndexFunc := GetHashIndexFunc9;</p>
<p>for I := 0 to MaxHashFuncCount &#8211; 1 do<br />
&nbsp;<wbr></wbr> HashFuncMans[I].Index := I;</p>
<p>FLock := TCriticalSection.Create;</p>
<p>FMaxCount := AMaxCount;<br />
end;</p>
<p>destructor TBloomFilterBase.Destroy;<br />
begin<br />
FLock.Leave;<br />
inherited;<br />
end;</p>
<p>procedure TBloomFilterBase.CelHashIndex(AStr: string);<br />
var<br />
I: Integer;<br />
begin<br />
FLock.Enter;<br />
try<br />
&nbsp;<wbr></wbr> FMD5Digest := MD5Buffer(AStr[1], Length(AStr));<br />
&nbsp;<wbr></wbr> FSHADigest := SHA1Buffer(AStr[1], Length(AStr));</p>
<p>&nbsp;<wbr></wbr> for I := Low(HashFuncMans) to High(HashFuncMans) do<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> HashFuncMans[I].HashIndex :=<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> HashFuncMans[I].GetHashIndexFunc(PChar(@AStr[1]), Length(AStr),<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> FMaxCount);<br />
finally<br />
&nbsp;<wbr></wbr> FLock.Leave;<br />
end;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc0(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
var<br />
I: Integer;<br />
begin<br />
//使用MD5<br />
Result := 0;<br />
for I := 0 to 3 do<br />
&nbsp;<wbr></wbr> Result := Result + PCardinal(PChar(@FMD5Digest) + I * SizeOf(Cardinal))^;</p>
<p>Result := Result mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc1(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FMD5Digest.A) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc2(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FMD5Digest.B) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc3(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FMD5Digest.C) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc4(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result :=Cardinal(FMD5Digest.D) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc5(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FSHADigest.A) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc6(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FSHADigest.B) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc7(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FSHADigest.C) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc8(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FSHADigest.D) mod FMaxCount;<br />
end;</p>
<p>function TBloomFilterBase.GetHashIndexFunc9(ABuffer: PChar; ALen:<br />
Integer; AMaxCount: Cardinal):<br />
Cardinal;<br />
begin<br />
Result := Cardinal(FSHADigest.E) mod FMaxCount;<br />
end;</p>
<p>{ TPointerBloomFilterBase }</p>
<p>constructor TPointerBloomFilterBase.Create(AMaxCount: Integer);<br />
var<br />
I: Integer;<br />
begin<br />
inherited Create(AMaxCount);<br />
//保存大小<br />
FLock := TCriticalSection.Create;<br />
end;</p>
<p>destructor TPointerBloomFilterBase.Destroy;<br />
begin<br />
FLock.Free;<br />
inherited;<br />
end;</p>
<p>function TPointerBloomFilterBase.FilterData(AStr: string;<br />
AAutoAdd: Boolean): Boolean;<br />
var<br />
I: Integer;<br />
begin<br />
//临界保护读写.<br />
FLock.Enter;<br />
try<br />
&nbsp;<wbr></wbr> Result := True; //先假定是存在</p>
<p>//计算Hash下标<br />
&nbsp;<wbr></wbr> CelHashIndex(AStr);</p>
<p>&nbsp;<wbr></wbr> for I := 0 to MaxHashFuncCount &#8211; 1 do<br />
&nbsp;<wbr></wbr> begin<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Result := Result<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> and (<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> (PWord(FBasePointer + HashFuncMans[I].HashIndex * SizeOf(Word))^ and ($01<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> shl<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> HashFuncMans[I].Index))<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> &lt;&gt; 0);<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> if not Result then Break;<br />
&nbsp;<wbr></wbr> end;</p>
<p>&nbsp;<wbr></wbr> //如果不存在,且要求自动保存<br />
&nbsp;<wbr></wbr> if (not Result) and AAutoAdd then<br />
&nbsp;<wbr></wbr> begin<br />
&nbsp;<wbr></wbr> //添加,更改标记<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> for I := 0 to MaxHashFuncCount &#8211; 1 do<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> begin<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> PWord(FBasePointer + HashFuncMans[I].HashIndex * SizeOf(Word))^<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> &nbsp;<wbr></wbr> :=<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> &nbsp;<wbr></wbr> PWord(FBasePointer + HashFuncMans[I].HashIndex * SizeOf(Word))^ or ($01<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> &nbsp;<wbr></wbr> shl<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> &nbsp;<wbr></wbr> HashFuncMans[I].Index);<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> end;<br />
&nbsp;<wbr></wbr> end;<br />
finally<br />
&nbsp;<wbr></wbr> FLock.Leave;<br />
end;<br />
end;</p>
<p>function TPointerBloomFilterBase.GetMaxCount: Cardinal;<br />
begin<br />
Result := FMaxCount;<br />
end;</p>
<p>{ TMemoryBloomFilter }</p>
<p>constructor TMemoryBloomFilter.Create(AMaxCount: Integer);<br />
begin<br />
inherited Create(AMaxCount);<br />
GetMem(FBasePointer, FMaxCount * 2);<br />
end;</p>
<p>destructor TMemoryBloomFilter.Destroy;<br />
begin<br />
FreeMem(FBasePointer, FMaxCount * 2 );<br />
inherited;<br />
end;</p>
<p>{ TMemoryFileBloomFilter }</p>
<p>constructor TMemoryFileBloomFilter.Create(AFileName: string;<br />
AMaxCount: Integer; ACreateNew: Boolean);<br />
begin<br />
inherited Create(AMaxCount);</p>
<p>if (not ACreateNew) and (not FileExists(AFileName)) then<br />
&nbsp;<wbr></wbr> ACreateNew := True;</p>
<p>if ACreateNew then<br />
begin<br />
&nbsp;<wbr></wbr> hFile := CreateFile(PAnsiChar(AFileName)<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> , GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> , CREATE_ALWAYS, 0, 0);<br />
end<br />
else<br />
begin<br />
&nbsp;<wbr></wbr> hFile := CreateFile(PAnsiChar(AFileName), GENERIC_READ or GENERIC_WRITE,<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> FILE_SHARE_READ, nil, OPEN_ALWAYS, 0, 0);<br />
&nbsp;<wbr></wbr> //通过已存在文件取得Hash桶的容量大小<br />
&nbsp;<wbr></wbr> FMaxCount := GetFileSize(hFile, nil) div SizeOf(Word);<br />
end;<br />
if hFile = INVALID_HANDLE_VALUE then<br />
&nbsp;<wbr></wbr> raise Exception.Create(SysErrorMessage(GetLastError));</p>
<p>hFileMap := CreateFileMapping(hFile, nil, PAGE_READWRITE, 0, FMaxCount *<br />
&nbsp;<wbr></wbr> SizeOf(Word), nil);<br />
if hFileMap = 0 then<br />
&nbsp;<wbr></wbr> raise Exception.Create(&#8216;CreateFileMapping Error!! &#8216;);</p>
<p>FBasePointer := MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);<br />
if not Assigned(FBasePointer) then<br />
&nbsp;<wbr></wbr> raise Exception.Create(SysErrorMessage(GetLastError));<br />
end;</p>
<p>destructor TMemoryFileBloomFilter.Destroy;<br />
begin<br />
FlushViewOfFile(FBasePointer, 0);<br />
UnmapViewOfFile(FBasePointer);<br />
CloseHandle(hFileMap);<br />
CloseHandle(hFile);<br />
inherited;<br />
end;</p>
<p>end.<br />
</span>undefined</p>
<hr style="width: 100%; height: 2px" />
<p><span class="tpc_content">测试结果:<br />
procedure TForm1.btnTestURLClick(Sender: TObject);<br />
var<br />
BloomFilter : IBloomFilter;<br />
I : Integer;<br />
Count : Integer;<br />
SueeCount : Integer;<br />
ErrorCount : Integer;<br />
begin<br />
qry1.Close;<br />
qry1.SQL.Text := &#8216;Select DISTINCT Url From Song&#8217;;<br />
qry1.Open;<br />
Count := qry1.RecordCount;<br />
qry1.First;<br />
BloomFilter := TMemoryBloomFilter.Create(Count*4);<br />
while not qry1.Eof do<br />
begin</p>
<p>&nbsp;<wbr></wbr> If not BloomFilter.FilterData(qry1.FieldByName(&#8216;URL&#8217;).AsString,True) then<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Inc(SueeCount)<br />
&nbsp;<wbr></wbr> else<br />
&nbsp;<wbr></wbr> &nbsp;<wbr></wbr> Inc(ErrorCount);</p>
<p>&nbsp;<wbr></wbr> qry1.Next;<br />
end;<br />
qry1.Close;<br />
lbledtTestCount.Text := IntToStr(Count);<br />
lbledtSuee.Text := IntToStr(SueeCount);<br />
lbledtError.Text := IntToStr(ErrorCount);<br />
lbledtScal.Text := FloatToStr(ErrorCount/SueeCount);<br />
end;</p>
<p>以上是测试的函数,数组大小为测试数据的4倍大小.<br />
测试结果:<br />
测试URL数:97301<br />
不重复数:97300<br />
冲突数:1<br />
冲突比例:1.02774922918808E-5<br />
</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.eood.cn/bloomfilter%e7%ae%97%e6%b3%95/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.380 seconds. -->
<!-- File not cached! Super Cache Couldn't write to: wp-content/cache/wp-cache-d320aabba00d1a0b47ea059520970318.html -->

