您的位置:首页 > 编程语言

游戏编程精粹学习 - 使用Bloom过滤来提高计算性能(BloomFilter)

2018-05-05 10:07 513 查看

原文在《游戏编程精粹2》的1.2中,BloomFilter是一种可以快速检测是否存在集合包含关系的数据结构,但有一定的误识别率。

 

该结构的优点

  • 判断包含关系时效率较高,粗略测试了下比List快一倍(不拆分哈希)
  • 由于内部是位数组BitArray,做交集并集几乎不产生开销

 

该结构的缺点

  • 有一定的误识别率
  • 使用情境有限

 

 

我在Github找了一个BloomFilter的库(这个库使用时会产生大量GC,但学习来用够了):

https://github.com/joeyrobert/bloomfilter

 

首先构建一个长度为N的位数组,将传入数据的哈希值按位拆分成不同段,每一个段作为一个Key放入这个长度为N的位数组。

判断包含时再把对象的多个key与位数组进行比较即可。

 

当然既然都存在误判率,而且是以效率为优先的话,也可以不按位拆分哈希,我写了一个最简单的版本:

public class MyBloomFilter<T>
{
BitArray mBitArray;

public MyBloomFilter(int bitLength)
{
mBitArray = new BitArray(bitLength);
}

public void Add(T obj)
{
var key = Mathf.Abs(obj.GetHashCode()) % mBitArray.Length;

mBitArray[key] = true;
}

public bool Contains(T obj)
{
var key = Mathf.Abs(obj.GetHashCode()) % mBitArray.Length;
return mBitArray[key];
}
}

 

注意C#已经内置了位数组这样的数据结构BitArray。

 

结合之前的可预测随机数(http://www.cnblogs.com/hont/p/8716586.html),我写了这样一个例子

using System.Collections.Generic;
using UnityEngine;

public class HerbGenerator : MonoBehaviour
{
public int x;
public int y;
public int probability = 70;
List<HerbObject> mCreatedHerbList = new List<HerbObject>();
MyBloomFilter<int> mCollectedHerbList = new MyBloomFilter<int>(64);

void Update()
{
GetArea(x - 3, y - 3, x + 3, y + 3);

if (Input.GetMouseButtonDown(0))
{
var hit = default(RaycastHit);
var isHit = Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit);
if (isHit)
{
var herbObject = hit.transform.GetComponent<HerbObject>();
mCollectedHerbList.Add(herbObject.seed);

Destroy(hit.transform.gameObject);
}
}
}

void GetArea(int beginX, int beginY, int endX, int endY)
{
for (int i = 0; i < mCreatedHerbList.Count; i++)
{
if (!mCreatedHerbList[i]) continue;
Destroy(mCreatedHerbList[i].gameObject);
}

var cacheState = Random.state;

mCreatedHerbList.Clear();

float spacingScale = 1f;//增加间距防止两颗草药同时消失.
for (int x = beginX, k = 0; x < endX; x++)
{
for (int y = beginY; y < endY; y++, k++)
{
var seed = 1000 + x + y * (endX - beginX);

if (mCollectedHerbList.Contains(seed)) continue;

Random.InitState(seed);
var r = (int)(Random.value * 100);

if (r % 100 < probability)
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
var herbObject = cube.AddComponent<HerbObject>();
herbObject.seed = seed;

cube.transform.position = new Vector3(x * spacingScale, 0, y * spacingScale);

GalaxyBuild(r, cube);

mCreatedHerbList.Add(herbObject);
}
}
}

Random.state = cacheState;
}

void GalaxyBuild(int seed, GameObject go)
{
var cacheState = Random.state;
Random.InitState(seed);
var meshRenderer = go.GetComponent<MeshRenderer>();
switch ((int)(Random.value * 100 % 3))
{
case 0://草药类型1
meshRenderer.material.color = Color.red;
break;

case 1://草药类型2
meshRenderer.material.color = Color.blue;
break;

case 2://草药类型3
meshRenderer.material.color = Color.green;
break;
}

Random.state = cacheState;
}
}
HerbGenerator  

 

出现误判时会发生A草药采完后B草药同时消失的情况,只能增加草药刷新的间距来缓解这个问题。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐