分享

BloomFilter算法的C#简化版,主要应用于URL消重 - King's blog ...

 jijo 2009-08-27

C#代码 复制代码
  1. using System;   
  2. using System.Collections;   
  3. using System.Text;   
  4. using NUnit.Framework;   
  5. namespace OurAlgorithmCollections   
  6. {   
  7.  public class BloomFilter   
  8.  {    
  9.  /// <summary>   
  10.  /// BitArray用来替代内存块,在C/C++中可使用BITMAP替代   
  11.  /// </summary>   
  12.  private static BitArray bitArray = null;   
  13.   
  14.  private int size = -1;   
  15.   
  16.  /// <summary>   
  17.  /// 构造函数,初始化分配内存   
  18.  /// </summary>   
  19.  /// <param name="size">分配的内存大小,必须保证被2整除</param>   
  20.  public BloomFilter(int size)   
  21.  {   
  22.  if (size % 2 == 0)   
  23.  {   
  24.  bitArray = new BitArray(size, false);   
  25.  this.size = size;   
  26.  }   
  27.  else  
  28.  {   
  29.  throw new Exception("错误的长度,不能被2整除");   
  30.  }   
  31.  }   
  32.   
  33.  /// <summary>   
  34.  /// 将str加入Bloomfilter,主要是HASH后找到指定位置置true   
  35.  /// </summary>   
  36.  /// <param name="str">字符串</param>   
  37.  public void Add(string str)   
  38.  {   
  39.  int[] offsetList = getOffset(str);   
  40.  if (offsetList != null)   
  41.  {   
  42.  put(offsetList[0]);   
  43.  put(offsetList[1]);   
  44.  }   
  45.  else  
  46.  {   
  47.  throw new Exception("字符串不能为空");   
  48.  }   
  49.  }   
  50.   
  51.  /// <summary>   
  52.  /// 判断该字符串是否重复   
  53.  /// </summary>   
  54.  /// <param name="str">字符串</param>   
  55.  /// <returns>true重复反之则false</returns>   
  56.  public Boolean Contains(string str)   
  57.  {   
  58.  int[] offsetList = getOffset(str);   
  59.  if (offsetList != null)   
  60.  {   
  61.  if ((get(offsetList[0]) == true) && (get(offsetList[1]) == true))   
  62.  {   
  63.  return true;   
  64.  }   
  65.   
  66.  }   
  67.  return false;   
  68.  }   
  69.   
  70.  /// <summary>   
  71.  /// 返回内存块指定位置状态   
  72.  /// </summary>   
  73.  /// <param name="offset">位置</param>   
  74.  /// <returns>状态为TRUE还是FALSE 为TRUE则被占用</returns>   
  75.  private Boolean get(int offset)   
  76.  {    
  77.  return bitArray[offset];   
  78.  }   
  79.   
  80.  /// <summary>   
  81.  /// 改变指定位置状态   
  82.  /// </summary>   
  83.  /// <param name="offset">位置</param>   
  84.  /// <returns>改变成功返回TRUE否则返回FALSE</returns>   
  85.  private Boolean put(int offset)   
  86.  {   
  87.  //try   
  88.  //{   
  89.  if (bitArray[offset])   
  90.  {   
  91.  return false;   
  92.  }   
  93.  bitArray[offset] = true;   
  94.  //}   
  95.  //catch (Exception e)   
  96.  //{   
  97.  // Console.WriteLine(offset);   
  98.  //}   
  99.  return true;   
  100.  }   
  101.   
  102.  private int[] getOffset(string str)   
  103.  {   
  104.  if (String.IsNullOrEmpty(str) != true)   
  105.  {   
  106.  int[] offsetList = new int[2];   
  107.  string tmpCode = Hash(str).ToString();   
  108.  int hashCode = Hash2(tmpCode);   
  109.  int offset = Math.Abs(hashCode % (size / 2) - 1);   
  110.  offsetList[0] = offset;   
  111.  hashCode = Hash3(str);   
  112.  offset = size - Math.Abs(hashCode % (size / 2))-1;   
  113.  offsetList[1] = offset;   
  114.  return offsetList;   
  115.  }   
  116.  return null;   
  117.  }   
  118.  /// <summary>   
  119.  /// 内存块大小   
  120.  /// </summary>   
  121.  public int Size   
  122.  {   
  123.  get { return size;}   
  124.  }   
  125.   
  126.  /// <summary>   
  127.  /// 获取字符串HASHCODE   
  128.  /// </summary>   
  129.  /// <param name="val">字符串</param>   
  130.  /// <returns>HASHCODE</returns>   
  131.  private int Hash(string val)   
  132.  {   
  133.  return val.GetHashCode();   
  134.  }   
  135.   
  136.  /// <summary>   
  137.  /// 获取字符串HASHCODE   
  138.  /// </summary>   
  139.  /// <param name="val">字符串</param>   
  140.  /// <returns>HASHCODE</returns>   
  141.  private int Hash2(string val)   
  142.  {   
  143.  int hash = 0;   
  144.   
  145.  for (int i = 0; i < val.Length; i++)   
  146.  {   
  147.  hash += val[i];   
  148.  hash += (hash << 10);   
  149.  hash ^= (hash >> 6);   
  150.  }   
  151.  hash += (hash << 3);   
  152.  hash ^= (hash >> 11);   
  153.  hash += (hash << 15);   
  154.  return hash;   
  155.  }   
  156.   
  157.  /// <summary>   
  158.  /// 获取字符串HASHCODE   
  159.  /// </summary>   
  160.  /// <param name="val">字符串</param>   
  161.  /// <returns>HASHCODE</returns>   
  162.  private int Hash3(string str)   
  163.  {   
  164.  long hash = 0;   
  165.   
  166.  for (int i = 0; i < str.Length; i++)   
  167.  {   
  168.  if ((i & 1) == 0)   
  169.  {   
  170.  hash ^= ((hash << 7) ^ str[i] ^ (hash >> 3));   
  171.  }   
  172.  else  
  173.  {   
  174.  hash ^= (~((hash << 11) ^ str[i] ^ (hash >> 5)));   
  175.  }   
  176.  }   
  177.  unchecked  
  178.  {   
  179.  return (int)hash;   
  180.  }   
  181.  }   
  182.   
  183.  }   
  184.  [TestFixture]    
  185.  public class TestBloomFilter   
  186.  {   
  187.  System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();   
  188.  BloomFilter bf = new BloomFilter(10485760);   
  189.  const int maxNum=100000;   
  190.  double count = 0;   
  191.  [Test]   
  192.  public void TestAdd()   
  193.  {   
  194.  watch.Reset();   
  195.  watch.Start();   
  196.  for (int i = 0; i <maxNum; i++)   
  197.  {   
  198.  if (bf.Contains(i.ToString()) != true)   
  199.  {   
  200.  bf.Add(i.ToString());   
  201.  }   
  202.  else  
  203.  {   
  204.  //Console.Write("发生碰撞数字:");   
  205.  //Console.WriteLine(i);   
  206.  count++;   
  207.  }   
  208.  }   
  209.  watch.Stop();   
  210.  Console.WriteLine("碰撞概率:"+ (count/(double)maxNum*100) + "%");   
  211.  Console.Write("运行时间:");   
  212.  Console.WriteLine(watch.ElapsedMilliseconds.ToString() + "ms");   
  213.  }   
  214.  }   
  215. }  
C#代码 复制代码
  1. BloomFilter中文布隆过滤器,主要应用于消重和拼写检查,以上实例实现了一个针对字符串重复检查的过滤器,具体碰撞概率跟内存分配大小及HASH函数有关,可通过增加HASH函数次数或增加内存分配来减小碰撞,具体测试方式可参考测试代码。   
  2. 其算法主要是通过整块的内存申请,得到线性的连续空间,该空间所有位置上默认状态为0,对待测试重复的对象HASH后取模,模数为内存块的大小以控制取模后的值范围在内存可分配范围内,取模的值对应位置上改变状态为1,通过对测试对象重复前面的HASH 取模 对应位置改变状态为1的方式来保存对象在空间内的状态,如有测试对象所有对应空间位置的状态为1则可判断该对象存在重复。 <DIV class=editmark>[Last Modified By King, at 2008-03-07 15:40:57]</DIV>  
C#代码 复制代码
  1.   
C#代码 复制代码
  1.   

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多