이런 용도로 적합한 자료 구조가 있을까요?(C++구현)

klara의 이미지

구체적인 예를 들어 보겠습니다.
어떤 금속 표면을 xy평면이라고 하면, 수천~수만개의 (x, y)점에 대한 온도 데이터가 있습니다.
이때, 임의의 (x, y)점에 대한 온도를, 그 점에서 가장 '가까운' 세 점의 온도 데이터의 평균으로 정의합니다.
어떤 점이 주어지면, 그로부터 가장 가까운 세점을 빠르게 찾아낼 필요가 있습니다.

이게 평면이 아니라 1차원상의 데이터라면 std::map::lower_bound 등을 이용하여, 간단하게 가장 가까운 점을 찾아낼수 있는데,
이게 2차원상의 데이터라, 일단 현재는 map의 map으로 어떻게 지저분한 코드로 구현을 하고 있습니다.
그런데 혹시 이런 용도에 적합한 자료구조가 혹시 존재하나 하여 질문드립니다.
가능하면 C++구현도 같이 소개해주시면 더욱 감사하겠습니다.

kasi의 이미지

map보다 2차원 배열이 더 간단하지 않을까요?
얼마나 빠르게 해야되는지 모르겠으나
몇천 몇만개 정도면 가까운 거리의 점들부터
루프 돌려서 체크해도 괜찮을꺼 같은데요.

sblade의 이미지

를 참고하세요.
http://en.wikipedia.org/wiki/Kd_tree

graphics 등에서 워낙 자주 사용되는 구조이므로 c++ 구현은 많이 있을 듯 싶습니다.

그런데 수만개라면 저라면 그냥 linear search (for문 돌리는 것)부터 해볼 것 같군요. 요즘 컴퓨터가 워낙 빨라서. :-)

그리고 2차원 데이터라고 해도 map 을 이중으로 써서 점들의 온도를 기록할 게 아니라, (x,y) -> T 로 기록하시는 게 좋을 듯 싶습니다.

feanor의 이미지

가장 가까운 점(들)을 찾는데는 들로네 삼각망을 이용하는 것이 정석입니다.
http://en.wikipedia.org/wiki/Delaunay_triangulation

CGAL에 CGAL::Point_set_2.nearest_neighbors(Point p, int k)로 구현되어 있습니다.
http://www.cgal.org/

bugiii의 이미지

거리를 구해야 하는 점의 갯수를 줄여야 한다는 것이로군요. 게임에 주로 사용하는 것들을 한번 적용해보시는 것은 어떨지요.

간단하게 해볼만 한 것은, 첫번째로 각 축별로 좌표를 정렬해서 검색하는 것입니다.

먼저, 모든 좌표를 각 축별로 정렬해 놓습니다. 측정된 좌표들이 고정이라면 한번만 해놓으면 되는 것이고요. (게임에서는 여러 객체들이 생기고 사라지지만, 정렬되어 있는 자료구조에 어떤 것을 넣는 빼는 것은 크게 문제될 것은 없습니다.)

입력되는 좌표값을 각 축별로 정렬되어 있는 자료구조에서 각각 검색하고, 이렇게 나온 좌표들의 교집합을 구합니다. 검색할 범위는 적절히 정하시면 될 듯 하고요.

이렇게 해서 나오는 좌표는 많아야 수십개정도일 것이므로, 이 점들과의 거리를 구해서 3개를 뽑아내시면 됩니다.

다른 방법으로는, 미리 좌표들을 격자로 구분해놓고 검색 범위를 줄일 수도 있습니다.

2D 게임에서는 보통 4등분으로 격자를 여러 단계로 미리 만들어 놓고 빠르게 검색하기도 합니다. 입력되는 좌표에 따라 처음 4등분 한 곳을 결정하고 그 한 곳의 4등분 된 격자에서 다시 찾는 과정을 반복하면, 최종적으로 검색할 양을 상당히 줄일 수 있습니다. 3차원이면 8등분으로 하게 됩니다. 어떤 응용에서는 이 등분의 크기를 객체의 밀도에 따라 다르게 하기도 하며, 등분 깊이의 레벨을 조절하기도 합니다. 격자의 경계를 약간 밀어서 경계선에 있는 물체 문제를 피하기도 합니다.

게임에 사용하는 트리 형태보다는 어느정도 한계를 정할 수 있는 상황이므로, 적절한 격자들을 미리 촘촘하게 배열해서 입력된 좌표가 어느 격자에 속하는지 구하고 주변 격자들의 점을 포함해서 점간 거리를 구하는 것도 크게 문제되지 않을 것으로 보입니다.

Quadtree, Octree로 검색하시면 되고, http://en.wikipedia.org/wiki/File:Point_quadtree.svg 이 그림 한장이면 바로 이해하실 수 있습니다.

좀 더 적극적으로 해볼만 한 것은 BSP 변형으로 고정된 구조물로 이루어진 공간에서 어떤 점이 어떤 공간에 있는지를 빠르게 검색할 수도 있습니다만, 배꼽이 커질 듯하고요.

snowall의 이미지

어쨌든 가장 가까운 점 1개를 찾으면, 그 점 빼고 다시 2개 더 찾으면 되니까 결국은 가장 가까운 점 찾는 알고리즘이네요.

효율적인지는 모르겠지만 이런 방법도 가능할 것 같은데요
(x, y, T, index)를 x좌표에 대한 정렬한 배열을 X, y좌표에 대한 정렬한 배열을 Y라고 놓고
(a, b)에서, 가령 a-10 < x < a+10, b-10 < y < b+10인 영역의 index를 뽑아옵니다.
즉, (a, b)근처에 네모칸을 쳐놓고 그 안에 있는 것들만 골라옵니다. 그 다음에 그것들끼리만 비교해서 가장 가까운 점을 찾아보면 되겠죠. 측정지점의 밀도에 따라 달라지겠지만, 최초 10짜리 네모칸에서 실패하면 측정지점을 늘려서 한번 더 해야 합니다. 그게 단점이네요;

index의 교집합을 골라내는 것도 빠르게 하려면 정렬된 내용을 2차원 linked list에 넣어놓고서 검색하면 조금 더 빠를 것 같습니다.

물론 이 방법은 그냥 전체 다 검색하는 것과 복잡도는 동일하지만, 대부분의 계산을 미리 정렬해 놓고나서 하기 때문에, 만약 온도 측정의 위치가 변하지 않는다면 써볼만할 것 같습니다.

예전에 회사 다닐때 비슷한 걸 구현한 적이 있었는데요, 그땐 주소를 입력하면 주소지 GPS값과 DB에 입력된 주소들의 GPS값을 비교해서 가장 가까운 주소들 3개를 추천해주는 시스템이었는데, 그땐 DB에 입력된 주소들이 200개 정도여서 그냥 다 비교했었습니다.

--------------------------
피할 수 있을때 즐겨라!
http://snowall.tistory.com

피할 수 있을때 즐겨라! http://melotopia.net/b

klara의 이미지

하룻밤 사이에 다양한 답변을 달아주셔서 감사합니다.
알려주신 방법들에 대해 찾아보고 공부해봐야겠습니다.
최종적으로 프로그램에 적용하기 전까지는 완료를 달아두는 것은 미루어 두겠습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.