당신은 요소를 분할하는 방법이 필요합니다 맞는 것들과 버려야 할 것들. 파티션하는 방법은 항목이 얼마나 빽빽하게 있는지에 따라 달라집니다. 예를 들어 X
좌표의 정수 부분을 분할하는 것만 큼 간단하거나 좌표의 적절한 크기 조정 된 값으로 간단하게 지정할 수 있습니다. 당신이 첫 번째 패스로 상당히 빨리 좌표 X
에 필터링 할 수 있습니다 X
좌표를 취하고 그것을 위해 파티션 값을 반환하는 방법 (의 지금은 Partition
를 호출하자)을 감안할 때
노드의 수를 줄이기 위해 당신 확인해야합니다. 파티션 기능을 사용하여 올바른 배포를 얻으려면 약간의 노력이 필요할 수 있습니다.
예를 들어 부동 소수점 좌표가 -100 < X <= 100
이고 1,000,000 개가이 범위에 균등하게 분산되어 있다고 가정 해 보겠습니다. 이는 정수 값이 X
인 경우 목록을 (평균적으로) 5000 개의 항목으로 구성된 200 개의 파티션으로 나눕니다. 즉, 검색 범위의 X
차원에있는 모든 정수 단계에 대해 테스트 할 수있는 항목은 ~ 5,000 개뿐입니다.
public interface IPosition2F
{
float X { get; }
float Y { get; }
}
public class CoordMap<T> where T : IPosition2F
{
SortedDictionary<int, List<T>> map = new SortedDictionary<int,List<T>>();
readonly Func<float, int> xPartition = (x) => (int)Math.Floor(x);
public void Add(T entry)
{
int xpart = xPartition(entry.X);
List<T> col;
if (!map.TryGetValue(xpart, out col))
{
col = new List<T>();
map[xpart] = col;
}
col.Add(entry);
}
public T[] ExtractRange(float left, float top, float right, float bottom)
{
var rngLeft = xPartition(left) - 1;
var rngRight = xPartition(right) + 1;
var cols =
from keyval in map
where keyval.Key >= rngLeft && keyval.Key <= rngRight
select keyval.Value;
var cells =
from cell in cols.SelectMany(c => c)
where cell.X >= left && cell.X <= right &&
cell.Y >= top && cell.Y <= bottom
select cell;
return cells.ToArray();
}
public CoordMap()
{ }
// Create instance with custom partition function
public CoordMap(Func<float, int> partfunc)
{
xPartition = partfunc;
}
}
최종 검색 공간을 줄일 좌표 X
에 분할됩니다
는 여기에 몇 가지 코드입니다.만약 당신이 한걸음 더 나아가고 싶다면 Y
좌표에서 파티션을 나눌 수도 있습니다. 독자의 연습 문제로 남겨 둘 것입니다 :
당신의 parition 함수가 매우 정교하고 파티션의 다수가 추가 유용 할 수 있습니다 ColumnRange
기능과 유사에 : 나는 모든 편의를 위해 SortedDictionary
을 사용
public T[] ExtractRange(float left, float top, float right, float bottom)
{
var rngLeft = xPartition(left) - 1;
var rngRight = xPartition(right) + 1;
var cells =
from cell in ColumnRange(rngLeft, rngRight).SelectMany(c => c)
where cell.X >= left && cell.X <= right &&
cell.Y >= top && cell.Y <= bottom
select cell;
return cells.ToArray();
}
:
이
public IEnumerable<List<T>> ColumnRange(int left, int right)
{
using (var mapenum = map.GetEnumerator())
{
bool finished = mapenum.MoveNext();
while (!finished && mapenum.Current.Key < left)
finished = mapenum.MoveNext();
while (!finished && mapenum.Current.Key <= right)
{
yield return mapenum.Current.Value;
finished = mapenum.MoveNext();
}
}
}
ExtractRange
방법은 다음과 같이 그것을 사용할 수 있습니다 ce, 그리고 가능한 한 빨리 ExtractRange
메소드를 수행 할 수 있기 때문입니다. 작업에 더 적합한 다른 컨테이너 유형이 있습니다.
제목을 편집했습니다. "[제목에"태그 "가 포함되어 있어야합니까?] (http://meta.stackexchange.com/questions/19190/)"합의가 "아니오, 그렇지 않아야합니다"로 표시되어야합니다. –
어떤 종류의 검색어를 검색 하시겠습니까? 대답이 매우 제한적인 세트 (또는 단일 쿼리 유형) 인 경우 데이터 구조를 최적화하여 O (1) – sinelaw
개체 격자를 표시 할 수 있습니다. X와 y는 Vector2 값을 나타내는 부동 소수점이며, 특정 범위 내의 x/y 값을 가진 객체를 찾으려고합니다. 개체 전체를 찾아서 여러 속성을 업데이트해야합니다. – Euthyphro