이진 검색 트리에서 삭제 후 자식 노드 할당 이유는 무엇입니까?

user2052015

BST 삭제 메커니즘을 배우는 동안 이해하지 못한 점이 있습니다. Delete (Node * p, int key)가 호출 될 때마다 할당 (p-> rchild =, p-> lchild =)이있는 이유를 설명해 주시겠습니까? 사실, 저는 Delete (Node * p, int key) 메서드가 변이없이 계속 반환되므로 트리가 변경되지 않는다고 생각했습니다.

그리고 설명을 찾고있는 동안이 문장을 우연히 발견했습니다.

삭제 후 할당해야합니다. 그렇지 않으면 중복 노드가 생깁니다.

이 진술에 동의하면 설명해 주시겠습니까?

Node* BST::Delete(Node *p, int key) {
    Node* q;
 
    if (p == nullptr){
        return nullptr;
    }
 
    if (p->lchild == nullptr && p->rchild == nullptr){
        if (p == root){
            root = nullptr;
        }
        delete p;
        return nullptr;
    }
 
    if (key < p->data){
        p->lchild = Delete(p->lchild, key);
    } else if (key > p->data){
        p->rchild = Delete(p->rchild, key);
    } else {
        if (Height(p->lchild) > Height(p->rchild)){
            q = InPre(p->lchild);
            p->data = q->data;
            p->lchild = Delete(p->lchild, q->data);
        } else {
            q = InSucc(p->rchild);
            p->data = q->data;
            p->rchild = Delete(p->rchild, q->data);
        }
    }
    return p;
}
Tricot

호출 할 때마다 할당 ( p->rchild =, p->lchild =) 이있는 이유는 Delete(Node* p, int key)무엇입니까?

데이터가 발견되면 목표는 노드가 하나 더 적은 트리를 갖는 것입니다. 알고리즘은 값 교환 메커니즘을 사용하여 실제로 제거 될 노드가 항상 리프 노드인지 확인합니다. 리프 노드 삭제는 두 가지 작업으로 구성됩니다.

  1. 기억에서 제거;
  2. 삭제 된이 노드를 참조하는 자식 포인터가 null 포인터로 설정되도록 부모의 업데이트입니다.

알고리즘이 해당 리프 노드에 대해 바로 반복되므로이 단계에서 부모 노드에 사용할 수있는 참조가 없기 때문에 null 포인터를 부모에 설정할 수 없습니다. 그 위해 발신자는 발신자가 있기 때문에, 뭔가해야 않는 부모에 대한 참조를 가지고있다.

따라서 재귀 순회가 리프 노드에 도달하면 호출자에게이 노드를 분리해야 함을 전달해야합니다. 이것은 null 포인터를 반환함으로써 이루어지며, 합의는 호출자 (현재 노드 p가 부모)가 반환 된 포인터를 관련 자식 포인터에 할당해야한다는 것입니다. 이렇게하면 삭제 된 노드가 트리의 나머지 부분에서 실제로 분리됩니다.

사실 저는 그 Delete(Node* p, int key)방법이 변이없이 계속 돌아 오므로 나무가 변하지 않는다고 생각했습니다 .

확실히 트리는 노드가 삭제되도록 어떻게 든 변경되어야합니다. 변경은 p->lchild또는 에 대한 할당에서 발생합니다.p->rchild

나는이 문장을 우연히 발견했습니다.

삭제 후 할당해야합니다. 그렇지 않으면 중복 노드가 생깁니다.

사실입니다. 예제 트리를 보겠습니다.

                 7
                / \
               3   8
              / \   \
             1   5   9
            /   / \ 
           0   4   6

이제 우리가을 호출하면 어떻게되는지 봅시다 Delete(root, 3). p값이 7 인 노드를 가리 킵니다. 재귀 호출을 사용하여 왼쪽으로 이동합니다.

p->lchild = Delete(p->lchild, key);

재귀 적 실행 컨텍스트에서 우리 p는 값이 3 인 노드를 가리키는 새로운 것을 얻습니다. 이것은 우리가 찾고있는 값입니다. 그래서 우리는 외부 else블록으로 들어갑니다. 해당 노드 아래의 하위 트리 높이가 같기 때문에 내부 else블록에 들어갑니다. 거기에서 우리는 다음을 할당합니다.

q = InSucc(p->rchild);

이것은 q값이 4 인 노드를 참조합니다. 이제 중복이 발생합니다. 데이터를 q에서 p. 이는 트리에서 값 3을 삭제하는 것으로 귀결됩니다.

p->data = q->data;

그러나 이제 우리는 트리에서 값 4의 두 배가됩니다.

                 7
                / \
               4*  8
              / \   \
             1   5   9
            /   / \ 
           0   4*  6

따라서 알고리즘은 (오른쪽) 자식으로 내려 가고 이제 해당 하위 트리에서 값이 4 인 노드를 삭제하려고합니다.

p->rchild = Delete(p->rchild, q->data);

이 새로운 재귀 호출에서 우리 p는 값이 5 인 노드를 참조 하는 새로운 것을 다시 얻습니다 . 왼쪽으로 이동합니다.이 할당은 나중에 중요한 역할을합니다.

p->lchild = Delete(p->lchild, key);

이 마지막 재귀 호출에는 p우리가 찾고 있던 값이 4 인 노드를 참조 하는 새로운 항목 이 있습니다.

이번에는 이 노드가 리프 노드이기 때문에 if가있는 블록으로 끝납니다 delete. 노드가 해제되고 널 포인터가 호출자에게 리턴됩니다. 여기서부터 우리는 트리를 역 추적하기 시작합니다.

따라서 한 수준 위로, 값이 5 인 노드에서 재귀 호출 (널 포인터)에서 반환 값을 가져와 할당합니다.

p->lchild = Delete(p->lchild, key);

이 중요한 할당은 트리에서 중복 노드 (값 4)를 분리합니다. 이 할당이 이루어지지 않았을 경우 해제 된 메모리를 가리키고 있더라도 중복 값이있는 해당 노드에 대한 참조가 여전히 있음을 알 수 있습니다.

이제 나무가 최종 모양이되었습니다.

                 7
                / \
               4   8
              / \   \
             1   5   9
            /     \ 
           0       6

역 추적은 계속해서 루트로 돌아갑니다. 또한 일부 자식 포인터에 대한 할당이 이루어 지지만 이러한 모든 경우 return p;에서 호출자의 자식 포인터의 원래 값인을 반환 한 것처럼 트리를 변경하지 않습니다 .

곤충

주석에서 언급했듯이 코드에는 버그가 있습니다. 리프 노드를 삭제할 때이 노드에 실제로 삭제할 값이 있는지 확인하지 않습니다. 따라서 트리에서 발생하지 않는 값으로이 메서드를 호출하면 다른 값이있는 리프 노드를 삭제하게됩니다. 위의 예제 트리에서 :를 호출 Delete(root, 10)하면 값이 9 인 노드가 삭제됩니다.

이 버그를 수정하려면 다음 if블록을 이동하십시오 .

if (p->lchild == nullptr && p->rchild == nullptr){

... 외부 else블록 내부에 있는 첫 번째 문장입니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

이진 검색 트리에서 두 자식이있는 노드 삭제

분류에서Dev

파이썬의 이진 검색 트리에서 노드를 삭제합니까?

분류에서Dev

이진 검색 트리에서 루트 노드 삭제 문제

분류에서Dev

이진 검색 트리 노드 제거 : 제거를 위해 통과 할 하위 트리를 결정하는 방법은 무엇입니까? (노드에 두 개의 자식이있는 경우)

분류에서Dev

이진 검색 트리에서 이상한 노드 삭제

분류에서Dev

C ++ 이진 검색 트리에서 노드 삭제

분류에서Dev

Java의 이진 검색 트리에서 노드 삭제

분류에서Dev

이진 검색 트리에서 삭제 된 노드 반환

분류에서Dev

이진 검색 트리에서 노드를 삭제하려고 할 때 SEGFAULT 가져 오기

분류에서Dev

이진 검색 트리의 루트 노드 삭제

분류에서Dev

Java를 사용하여 이진 검색 트리에서 노드 삭제

분류에서Dev

이진 검색 트리의 모든 노드 삭제

분류에서Dev

이진 검색 트리 제거 노드

분류에서Dev

이진 검색 트리에서 주어진 노드를 인쇄하는 방법은 무엇입니까?

분류에서Dev

2 개의 노드가있는 이진 검색 트리에서 다른 방법으로 노드를 삭제 하시겠습니까?

분류에서Dev

이진 검색 트리에서 노드 제거

분류에서Dev

이진 트리에서 노드 삭제

분류에서Dev

검색 및 나열에서 리소스를 삭제하는 진정한 휴식 방법은 무엇입니까?

분류에서Dev

한 자식 노드의 이진 트리 삭제

분류에서Dev

이진 검색 트리, 템플릿 구조 노드에 포인터 할당

분류에서Dev

선택이 변경된 후 VirtualStringTree에서 선택한 노드를 검색하는 방법은 무엇입니까?

분류에서Dev

JavaScript에서 자식 노드가 클릭 이벤트를 발생시킬 때 부모 노드를 삭제하는 방법은 무엇입니까?

분류에서Dev

복합 하위 자체에서 이벤트가 발생할 때 VBox에서 복합 하위 노드를 삭제하는 방법은 무엇입니까?

분류에서Dev

람다 할당 연산자를 삭제하는 이유는 무엇입니까?

분류에서Dev

ElementTree가 모든 자식 노드를 삭제하지 않는 이유는 무엇입니까?

분류에서Dev

삭제 기능이 BST에서 노드를 삭제하지 않는 이유는 무엇입니까?

분류에서Dev

이 코드에서 '숫자'유형을 'never'유형에 할당 할 수없는 이유는 무엇입니까?

분류에서Dev

자바 스크립트에서 테이블의 행을 삭제할 수없는 이유는 무엇입니까?

분류에서Dev

EF Core에서 모든 API 호출 후 DbContext가 자동으로 삭제되는 이유는 무엇입니까?

Related 관련 기사

  1. 1

    이진 검색 트리에서 두 자식이있는 노드 삭제

  2. 2

    파이썬의 이진 검색 트리에서 노드를 삭제합니까?

  3. 3

    이진 검색 트리에서 루트 노드 삭제 문제

  4. 4

    이진 검색 트리 노드 제거 : 제거를 위해 통과 할 하위 트리를 결정하는 방법은 무엇입니까? (노드에 두 개의 자식이있는 경우)

  5. 5

    이진 검색 트리에서 이상한 노드 삭제

  6. 6

    C ++ 이진 검색 트리에서 노드 삭제

  7. 7

    Java의 이진 검색 트리에서 노드 삭제

  8. 8

    이진 검색 트리에서 삭제 된 노드 반환

  9. 9

    이진 검색 트리에서 노드를 삭제하려고 할 때 SEGFAULT 가져 오기

  10. 10

    이진 검색 트리의 루트 노드 삭제

  11. 11

    Java를 사용하여 이진 검색 트리에서 노드 삭제

  12. 12

    이진 검색 트리의 모든 노드 삭제

  13. 13

    이진 검색 트리 제거 노드

  14. 14

    이진 검색 트리에서 주어진 노드를 인쇄하는 방법은 무엇입니까?

  15. 15

    2 개의 노드가있는 이진 검색 트리에서 다른 방법으로 노드를 삭제 하시겠습니까?

  16. 16

    이진 검색 트리에서 노드 제거

  17. 17

    이진 트리에서 노드 삭제

  18. 18

    검색 및 나열에서 리소스를 삭제하는 진정한 휴식 방법은 무엇입니까?

  19. 19

    한 자식 노드의 이진 트리 삭제

  20. 20

    이진 검색 트리, 템플릿 구조 노드에 포인터 할당

  21. 21

    선택이 변경된 후 VirtualStringTree에서 선택한 노드를 검색하는 방법은 무엇입니까?

  22. 22

    JavaScript에서 자식 노드가 클릭 이벤트를 발생시킬 때 부모 노드를 삭제하는 방법은 무엇입니까?

  23. 23

    복합 하위 자체에서 이벤트가 발생할 때 VBox에서 복합 하위 노드를 삭제하는 방법은 무엇입니까?

  24. 24

    람다 할당 연산자를 삭제하는 이유는 무엇입니까?

  25. 25

    ElementTree가 모든 자식 노드를 삭제하지 않는 이유는 무엇입니까?

  26. 26

    삭제 기능이 BST에서 노드를 삭제하지 않는 이유는 무엇입니까?

  27. 27

    이 코드에서 '숫자'유형을 'never'유형에 할당 할 수없는 이유는 무엇입니까?

  28. 28

    자바 스크립트에서 테이블의 행을 삭제할 수없는 이유는 무엇입니까?

  29. 29

    EF Core에서 모든 API 호출 후 DbContext가 자동으로 삭제되는 이유는 무엇입니까?

뜨겁다태그

보관