복제본이있는 쿼드 트리


10

쿼드 트리를 구현하고 있습니다. 이 데이터 구조를 모르는 사람들을 위해 다음과 같은 작은 설명을 포함시킵니다.

쿼드 트리를 데이터 구조 및 팔진은 3 차원 공간에서 무엇 유클리드 평면이다. 쿼드 트리의 일반적인 용도는 공간 인덱싱입니다.

그것들의 작동 방식을 요약하기 위해 쿼드 트리는 최대 용량과 초기 경계 상자가있는 컬렉션입니다 (여기서 사각형이라고합시다). 최대 용량에 도달 한 쿼드 트리에 요소를 삽입하려고 할 때 쿼드 트리는 4 개의 쿼드 트리로 세분화됩니다 (기하학적 표현은 삽입하기 전에 트리보다 4 배 더 작은 면적을 갖습니다). 각 요소는 위치에 따라 하위 트리에 재배포됩니다. 사각형으로 작업 할 때 왼쪽 상단 경계.

따라서 쿼드 트리는 잎이고 그 용량보다 적은 요소를 갖거나 4 개의 쿼드 트리를 자식으로하는 나무 (보통 북서, 북동, 남서, 남동)입니다.

내 관심사는 중복을 추가하려고하면 같은 요소가 여러 번 같은 위치이거나 같은 위치에 여러 요소가있을 수 있지만 쿼드 트리는 가장자리를 처리하는 데 근본적인 문제가 있다는 것입니다.

예를 들어, 용량이 1 인 쿼드 트리와 단위 사각형을 경계 상자로 사용하는 경우 :

[(0,0),(0,1),(1,1),(1,0)]

그리고 왼쪽 상단 경계가 원점 인 사각형을 두 번 삽입하십시오 (또는 용량이 N> 1 인 쿼드 트리에서 N + 1 번 삽입하려고하는 경우)

quadtree->insert(0.0, 0.0, 0.1, 0.1)
quadtree->insert(0.0, 0.0, 0.1, 0.1)

첫 번째 인서트는 문제가되지 않습니다 : 첫 번째 삽입

그러나 첫 번째 인서트는 용량이 1이기 때문에 세분화를 트리거합니다. 두 번째 인서트, 첫 번째 세분

따라서 두 직사각형 모두 동일한 하위 트리에 배치됩니다.

그런 다음 두 요소가 동일한 쿼드 트리에 도착하고 하위 분할을 트리거합니다. 두 번째 인서트, 두 번째 세분

그리고 등 (0, 0)은 항상 생성 된 4 개 중 동일한 하위 트리에 있기 때문에 하위 재분할 방법이 무한정 실행됩니다. 즉 무한 재귀 문제가 발생합니다.

복제본이있는 쿼드 트리를 사용할 수 있습니까? (그렇지 않으면 그것을로 구현할 수 있습니다 Set)

쿼드 트리의 아키텍처를 완전히 손상시키지 않고이 문제를 어떻게 해결할 수 있습니까?


어떻게 동작하겠습니까? 구현하고 있으므로 올바른 행동을 결정해야합니다. 각 고유 좌표는 해당 좌표의 요소 목록 일 수 있습니다. 아마도 당신의 요점은 독특하게 제한되어있을 것입니다. 당신은 당신이 필요한 것을 알고 있지만 우리는하지 않습니다.
쓸모없는

@Useless 그것은 사실입니다. 그러나이 주제에 대해 많은 연구가 있었을 것입니다. 나는 바퀴를 재발 명하고 싶지 않습니다. TBH 나는 아직도이 질문이 SO, 프로그래머, SE, gamedev.SE, 심지어 수학 SE에 더 많이 속하는지 모른다.
Pierre Arlaud

답변:


3

데이터 구조를 구현하고 있으므로 구현 결정을 내려야합니다.

쿼드 트리에 고유성에 대해 구체적으로 언급하지 않는 한 (그렇지 않다는 사실을 모르는 경우) 이는 구현 결정입니다. 쿼드 트리의 정의와 직교하며 원하는대로 처리하도록 선택할 수 있습니다. 쿼드 트리는 키를 삽입하고 업데이트하는 방법을 알려주지 만 키가 고유해야하는지 또는 각 노드에 연결할 수 있는지를 알려줍니다.

구현 결정을 내리는 것이 최소한 바퀴를 재발 명하는 것은 아니며 , 적어도 자신의 구현을 처음부터 작성하는 것 이상입니다.

비교를 위해 C ++ 표준 라이브러리는 고유 세트, 고유하지 않은 다중 세트, 고유 맵 (본질적으로 키만 정렬 및 비교 한 키-값 쌍 세트) 및 고유하지 않은 멀티 맵을 제공합니다. 그것들은 모두 일반적으로 동일한 레드 블랙 트리를 사용하여 구현 되며 아키텍처를 깨뜨리는 것은 없습니다 . 단순히 레드 블랙 트리의 정의가 키의 고유성 또는 리프 노드에 저장된 유형에 대해 아무 말도하지 않기 때문입니다.

마지막으로, 이것에 대한 연구가 있다고 생각되면 찾으면 토론 할 수 있습니다. 어쩌면 내가 간과 한 쿼드 트리 불변 또는 더 나은 성능을 허용하는 추가 제약이있을 수 있습니다.


내 문제는 고유성이 요구되는 문서를 찾을 수 없다는 것입니다. 그러나 내 예를 보았을 경우 동일한 요소를 여러 번 포함하면 실제 문제임을 알 수 있습니다.
Pierre Arlaud 2016 년

트리 유형의 구조의 경우 값이있는 노드에 때때로 중복에 대해 증가 및 감소하는 "count"필드가 제공되지 않습니까?
J Trana

2

여기에 오해가 있다고 생각합니다.

내가 이해하는 것처럼 모든 쿼드 트리 노드에는 점으로 색인 된 값이 포함되어 있습니다. 즉, 트리플 (x, y, value)을 포함합니다.

또한 자식 노드에 대한 4 개의 포인터를 포함하며 null 일 수 있습니다. 키와 자식 링크 사이에는 알고리즘 관계가 있습니다.

삽입물은 다음과 같아야합니다.

quadtree->insert(0.0, 0.0, value1)
quadtree->insert(0.0, 0.0, value2)

첫 번째 삽입은 (부모) 노드를 작성하고 값을 삽입합니다.

두 번째 삽입은 하위 노드를 작성하고 그에 연결하여 값을 삽입합니다 (첫 번째 값과 동일 할 수 있음).

어떤 자식 노드가 인스턴스화되는지는 알고리즘에 따라 다릅니다. 알고리즘이 [x) 형식이고 좌표 공간이 [0,1) 범위에있는 경우 각 자식은 [0,0.5) 범위에 이르고 점은 NW 자식에 배치됩니다.

무한 재귀가 없습니다.


그래서 당신은 세분화가 내 구현에 문제가있을 때 노드 를 자식 쿼드 트리 에 재배포하는 방법을 말하고 있습니까?
Pierre Arlaud 2018 년

아마도 문제는 값을 (부모의) 위치에서 더 나은 곳 (자식의)으로 옮기려고한다는 것입니다. 이것은 실제로 어떻게 이루어지지 않았습니다. 어디에서나 가치가 있습니다. 그러나 그것은 두 개의 동일한 점이 다른 노드에 배치 될 수 있다는 흥미로운 결과를 가져옵니다 (그러나 항상 관련된 부모와 자식).
david.pfx

2

내가 접하게 된 일반적인 해결책 (게임이 아닌 시각화 문제에서)은 항상 교체하거나 교체하지 않는 점 중 하나를 버리는 것입니다.

나는 유리한 점은 쉬운 일이라고 생각합니다.


2

나는 당신이 거의 같은 크기의 요소를 인덱싱한다고 가정하고 있습니다. 그렇지 않으면 인생이 복잡하거나 느리거나 둘 다입니다 ...…

쿼드 트리 노드에는 고정 용량이 필요 하지 않습니다 . 용량은

  • 메모리 나 디스크에서 각 트리 노드의 크기를 고정 할 수 있습니다 . 트리 노드에 가변 크기의 요소 집합이 포함되어 있고 공간 할당 시스템을 사용하는 경우에는 필요하지 않습니다. (예 : 메모리의 java / c # 객체)
  • 노드를 분할 할시기를 결정하십시오.
    • “n”개 이상의 지구 요소가 포함 된 노드가 요소의 위치에 따라 정의 된 경우 노드가 분할되도록 규칙을 다시 정의 할 수 있습니다.
    • 또는“ 복합 요소”를 사용하여 같은 위치에 여러 요소가있는 경우 이러한 여러 요소 목록이 포함 된 새 요소를 소개합니다.

2

공간 인덱싱 문제를 처리 할 때는 실제로 공간 해시 또는 개인적으로 좋아하는 일반 오래된 그리드부터 시작하는 것이 좋습니다.

여기에 이미지 설명을 입력하십시오

... 그리고 드문 표현을 허용하는 트리 구조로 이동하기 전에 그 약점을 먼저 이해하십시오.

명백한 약점 중 하나는 많은 빈 셀에서 메모리를 낭비 할 수 있다는 것입니다 (실제로 구현 된 그리드에는 실제로 삽입 할 수십억 개의 노드가없는 한 셀당 32 비트 이상이 필요하지 않음). 또 다른 하나는 셀 크기보다 크고 보통 수십 개의 셀에 걸쳐있는 중간 크기의 요소가있는 경우 중간 크기의 요소를 이상적인 것보다 훨씬 많은 셀에 삽입하는 데 많은 메모리를 낭비 할 수 있다는 것입니다. 마찬가지로 공간 쿼리를 수행 할 때 이상적인 것보다 더 많은 셀을 확인해야 할 수도 있습니다.

그러나 그리드를 사용하여 특정 입력에 대해 가능한 한 최적의 상태로 만들려면 유일하게 cell size생각하고 고민하는 데 너무 많은 시간을 허비하지 않으므로 이것이 데이터 구조입니다. 사용하지 않는 이유를 찾을 때까지 공간 인덱싱 문제. 구현하기가 더럽 기 때문에 단일 런타임 입력 이상의 것을 피할 필요가 없습니다.

평범한 오래된 그리드에서 많은 것을 얻을 수 있으며 실제로 상용 소프트웨어에 사용되는 쿼드 트리 및 kd 트리 구현을 평범한 오래된 그리드로 교체하여 실제로 구현했습니다. ,하지만 저자는 그리드를 세우는 데 소비 한 20 분보다 훨씬 많은 시간을 보냈습니다). 충돌 감지를 위해 그리드를 사용하여 다른 곳에서 질문에 대답하기 위해 채찍질 한 작은 내용이 있습니다 (실제로 최적화되지 않았고 몇 시간 만 일했습니다.) 그리고 이런 종류의 충돌 감지를 구현 한 것은 처음이었습니다.)

여기에 이미지 설명을 입력하십시오

그리드의 또 다른 약점 (그러나 많은 공간 색인 구조의 일반적인 약점)은 동일한 위치의 많은 점과 같이 많은 일치 또는 겹치는 요소를 삽입하면 정확히 동일한 셀에 삽입된다는 것입니다 ) 및 해당 셀을 순회 할 때 성능이 저하됩니다. 마찬가지로 셀 크기보다 훨씬 더 큰 방대한 요소 를 삽입하는 경우 셀의 보트로드에 삽입하고 많은 메모리를 사용하고 보드 전체의 공간 쿼리에 필요한 시간을 단축해야합니다. .

그러나, 위의 두 요소와 일치하는 요소와 거대한 요소가 실제로 모든 공간 색인 구조에 문제가됩니다 . 평범한 오래된 그리드는 실제로 이러한 병리학 적 사례를 다른 많은 것보다 조금 더 잘 처리합니다. 적어도 셀을 반복해서 세분화하고 싶지 않기 때문입니다.

그리드로 시작하여 쿼드 트리 또는 KD 트리와 같은 방향으로 작업 할 때 해결하려는 주요 문제는 너무 많은 셀에 요소가 삽입되어 셀이 너무 많으며 이 유형의 조밀 한 표현으로 너무 많은 셀을 확인해야합니다.

그러나 쿼드 트리를 그리드에 대한 최적화로 생각하면특정 사용 사례의 경우 쿼드 트리 노드의 재귀 적 하위 분할의 깊이를 제한하기 위해 여전히 "최소 셀 크기"라는 개념을 생각하는 데 도움이됩니다. 그렇게 할 때, 쿼드 트리의 최악의 시나리오는 여전히 나뭇잎에서 밀도가 높은 그리드로 저하됩니다. 그 대신 루트에서 그리드 셀로가는 데 로그 시간이 필요하기 때문에 그리드보다 효율이 떨어집니다. 일정한 시간. 그러나 최소 셀 크기를 생각하면 무한 루프 / 재귀 시나리오를 피할 수 있습니다. 대규모 요소의 경우 느슨한 쿼드 트리와 같은 일부 변형이 있으며 반드시 균등하게 분할되지 않고 하위 노드에 대해 AABB가 겹칠 수 있습니다. BVH는 노드를 균등하게 세분화하지 않는 공간 인덱싱 구조로도 흥미 롭습니다. 트리 구조와 일치하는 요소의 경우 가장 중요한 것은 하위 구획에 제한을 두는 것입니다 (또는 다른 사람들이 제안한 것처럼 거부하거나 잎을 결정할 때 잎의 고유 한 수의 요소에 기여하지 않는 것처럼 처리하는 방법을 찾으십시오. 세분화해야 함). 노드가 중앙값을 분할해야하는지 여부를 결정할 때 하나의 차원 만 고려하면되므로 Kd 트리는 일치하는 요소가 많은 입력을 예상하는 경우에도 유용 할 수 있습니다.


quadtrees의 업데이트로 누군가가 충돌 감지를 효율적으로 수행하는 방법에 대해 다소 광범위한 질문을했지만 결국 그것들을 구현하는 방법에 대한 용기를 쏟았습니다. 또한 귀하의 질문에 답변해야합니다 : stackoverflow.com/questions/41946007/…
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.