2010-07-27 3 views
2

빨간색 - 검은 색 트리에서 회전 할 때 특정 노드의 부모가 누구인지 알아야합니다. 그러나 노드에는 오른쪽 또는 왼쪽 자식에 대한 참조 만 있습니다.레드 - 블랙 트리 - 노드의 부모를 찾는 방법?

나는 노드 인스턴스 변수에 "parent"를 주려고했으나 이런 이유 때문에 그렇게할만한 가치가 있다고 생각하지 않으며 회전 당 부모 참조를 변경하기에는 너무 복잡 할 것이라고 생각합니다.

public class Node { 
    private left; 
    private right; 
    private isRed; 
    private parent; //I don't think this is good idea 
} 

그래서 제 해결책은 검색을 사용하여 부모를 찾는 findParent() 메소드를 작성하는 것입니다. 노드의 부모를 찾는 다른 방법이 있다면 궁금합니다.

내 솔루션 :

샘플 나무 : 당신은 노드 (25)의 부모를 찾으려면

50 
    /\ 
    25 75 

, 당신은 같은 것을 통과 :

Node parent = findParent(Node25.value); 

을하고 node50을 반환합니다.

protected Node findParent(int val) { 
     if(root == null) { 
      return null; 
     } 
     Node current = root; 
     Node parent = current; 
     while(true) { 
      if(current.val == val) { //found 
       return parent; 
      } 
      if(current == null) { //not found 
       return null; 
      } 
      parent = current; 
      if(current.val > val) { //go left 
       current = current.left; 
      } 
      else { //go right 
       current = current.right; 
      } 
     } 
    } 
+1

내가 틀릴 수도 있지만 일반적인 방법은 호출 스택의 매개 변수로 부모를 회전 함수로 전달하는 것입니다. – mikera

+0

libavl을 살펴 봐야합니다. 올바른 방법은 검색 할 때 조상을 스택에 보관하는 것입니다. – user172818

답변

3

내가 노드 인스턴스를 변수 "부모"를주고 있지만, 단지 이런 이유로 나는

그렇게 당신의 노드가 parent 참조가 갖는 그 가치가 있다고 생각하지 않는 생각 하나 추가 포인터가 필요합니다/노드 당 참조. 주어진 노드에 대한 부모를 알아야 할 때마다 트리를 탐색해야하는 것과 비교하십시오.

이는

  1. 추가 참조를 유지하고, 노드를 수정할 때마다 최신으로 유지 비용 간의 트레이드 오프입니다.

나는이 두 가지 옵션 사이의 선택은 다소 주관적이라고 생각 주어진 노드의 부모를 찾기 위해 트리를 통과 할 수 있지만 개인적으로 나는 단순히 추적을 유지하도록 선택할 것 갖는

  • 계산상의 비용과 복잡성 parent 참조. 당신을위한 기준점으로

    java.util.TreeMap은 레드 - 블랙 트리로 left, rightparent 참조를 포함 Entry 노드를 구현됩니다.

  • +0

    나는 주관적이라고 생각하지 않습니다. R-B 트리를 가지고있는 거리를 가려한다면, 빠른 작업을 추구 할 때 어떤 것을 희생해야하기 때문일 것입니다. 당신이 기억을 위해 발목을 잡고 있다면 배열을 사용하지 않는 것이 어떻습니까? –

    +0

    글쎄, 데이터 구조를 유지할 필요가 없다는 트레이드 오프는 계산상의 복잡성이 약간 증가 할 때 가치가 있다고 말할 수있는 알고리즘이 있다고 생각합니다. 개인적으로 나는 이것이 그 중 하나라고 생각하지 않습니다. 나는 방금 넓은 대답을 피하기를 원했습니다. –

    1

    부모를 저장하는 것보다 확실히 저장하는 것이 좋습니다. 상위 참조를 업데이트하는 것은 그렇게 복잡하지 않습니다.

    2

    피벗 노드로 이동하기 위해 이전 부모를 캐시 할 수 있습니다. 또는 한 단계 이상의 "실행 취소"수준이 필요할 경우 스택으로 이동할 각 노드를 캐시 할 수 있습니다.

    이 캐시는 순환 알고리즘에 대해 로컬 변수가되므로 트리에서 더 이상 공간이 필요하지 않으며 값 비싼 추가 순회가 필요하지 않습니다.

    0

    부모 포인터 사용은 선택 사항입니다.부모 포인터를 사용하지 않으면 재귀를 사용하여 삽입/삭제 작업을 작성해야합니다 (재귀 메서드 호출은 스택에 대한 부모 정보를 유지함). 트리를 따라 이동할 때 부모 스택을 유지하는 반복 버전을 작성해야합니다. 레드 - 블랙 트리의

    아주 좋은 설명을 여기에 부모 포인터없이 포함 rbtree 구현의 숫자에 대한 설명을 포함

    http://adtinfo.org/

    찾을 수 있습니다.

    당신은 공간에 저장 하시겠습니까 (그리고 그것으로 충분 공평)을 rbtree 구현의 정말 좋은 설명은 여기

    http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx

    당신이 노드의 검색에 대해 기술 한 방법을 발견 할 수있는 경우 삽입/삭제 구현에 의해 사용된다면 부모는 매우 비효율적이다. 포인터를 사용하거나 재귀를 사용하십시오.

    0

    부모 포인터 외에 부모를 다시 묻는 또 다른 해결책은 조상 스택을 유지하는 것입니다.

    Red Black Tree

    일반적으로 삽입하는 알고리즘은 다음과 같습니다 :

    가정하자 누군가가 다음과 같은 트리에 (23)를 삽입하고자는 트리에있는 경우 23이 될 것이다

    1. 찾기 노드

    2. 이미 23이있는 경우 반송 오류

    3. 23이 없으면 거기에 넣으십시오.

    4. 필요에 따라 리 밸런싱/채색 루틴을 실행하십시오.

    지금, 스택 접근 방식을 사용하여, 당신은 당신의 트리의 레벨 당 하나 개의 노드를 지원할만큼 큰 스택을 할당 당신이 덮여 있어야합니다 (I는 2 * 천장 (LOG2 (수)) + 2가 생각). 삽입이나 삭제를 위해 할당 된 스택을 유지하고 삽입을 시작할 때마다 그냥 지울 수 있습니다.

    그래서 루트를보세요. 그것을 스택에 밀어 넣습니다. 23은 루트 값보다 큽니다. 따라서 오른쪽으로 가십시오. 이제 노드 현재 노드 (값 21)를 스택으로 푸시합니다. 23이 트리에 있으면 현재 노드의 오른쪽에 있어야합니다. 그러나 현재 노드의 오른쪽에있는 노드는 null입니다. 따라서 null-sentinel은 값을 가진 노드로 대체되어야합니다. 부모는 (가장 최근에 푸시 된) 스택 맨 위에있는 항목이며, 조부모는 다음 라인에 있습니다 ... 등등. 당신이 배우는 것처럼 보이기 때문에 자바는 스택 인터페이스를 제공하므로 필요하지 않습니다. 자신의 스택을 개발하여이를 수행하십시오. 그냥 그들의 것을 사용하십시오.

    이것이 부모 포인터 접근법보다 나은지 여부는 논란의 여지가 있습니다. 부모 포인터 접근 방식을 사용하면 부수적 인 데이터 구조를 유지하거나 재귀를 광범위하게 사용해야 할 필요성을 없앨 수 있습니다. 즉, 리 밸런싱/채색 루틴을 적용 할 때 현재 노드의 부모를 쿼리하는 것보다 나은 방법입니다.

    관련 문제