이진 검색 트리 정의에서 중복 키가 허용됩니까?


139

이진 검색 트리의 정의를 찾으려고 노력하고 있으며 어디에서나 다른 정의를 계속 찾습니다.

어떤 하위 트리에서는 왼쪽 하위 키가 루트보다 작거나 같다고 말합니다.

어떤 하위 트리에서는 올바른 하위 키가 루트보다 크거나 같다고 말합니다.

저의 오래된 대학 데이터 구조 책은 "모든 요소에는 키가 있고 두 요소에는 동일한 키가 없습니다"라고 말합니다.

bst에 대한 보편적 인 정의가 있습니까? 특히 동일한 키의 여러 인스턴스가있는 트리로 수행 할 작업과 관련하여.

편집 : 어쩌면 내가 명확하지 않은, 내가보고있는 정의는

1) 왼쪽 <= 루트 <오른쪽

2) 왼쪽 <루트 <= 오른쪽

3) 왼쪽 <root <오른쪽으로 중복 키가 존재하지 않습니다.

답변:


78

많은 알고리즘에서 중복이 제외되도록 지정합니다. 예를 들어, MIT 알고리즘 책의 예제 알고리즘은 일반적으로 중복없이 예제를 제공합니다. 중복을 구현하는 것은 (사소한 목록이나 특정 방향으로) 매우 사소한 일입니다.

(내가 본) 대부분은 왼쪽 자식을 <=로 지정하고 오른쪽 자식을>로 지정합니다. 실제로, 오른쪽 또는 왼쪽 자식 중 하나가 루트 노드와 같도록 허용하는 BST는 중복 노드가 허용되는 검색을 완료하기 위해 추가 계산 단계가 필요합니다.

노드의 한쪽에 '='값을 삽입하려면 노드를 자식으로 배치하기 위해 해당 측면에 트리를 다시 쓰거나 노드가 그랜드로 배치되므로 중복을 저장하기 위해 노드에서 목록을 사용하는 것이 가장 좋습니다. -child, 아래 지점에서 검색 효율성을 일부 제거합니다.

대부분의 강의실 예제는 개념을 묘사하고 전달하기 위해 단순화되었습니다. 많은 실제 상황에서 쪼그리고 앉을 가치가 없습니다. 그러나 "모든 요소에는 키가 있고 두 요소에는 동일한 키가 없습니다"라는 문구는 요소 노드에서 목록을 사용하여 위반되지 않습니다.

따라서 데이터 구조 책이 말한 것과 함께하십시오!

편집하다:

이진 검색 트리의 범용 정의는 두 방향 중 하나에서 데이터 구조를 순회하는 것에 기초하여 키를 저장하고 검색하는 것을 포함합니다. 실용적인 의미에서, 값이 <> 인 경우 두 '방향'중 하나로 데이터 구조를 탐색합니다. 따라서 이러한 의미에서 중복 값은 전혀 의미가 없습니다.

이것은 BSP 또는 이진 검색 파티션과 다르지만 그다지 다릅니다. 검색 알고리즘에는 '여행'에 대한 두 가지 방향 중 하나가 있거나 수행됩니다 (성공 여부는 상관 없습니다). 따라서 중복이 실제로는 고유하기 때문에 원래의 답변이 '유니버설 정의'의 개념을 다루지 않았다고 사과합니다. 주제 (이진 검색의 일부가 아닌 성공적인 검색 후 처리하는 항목)


1
노드에서 목록을 사용할 때의 단점은 무엇입니까?
Pacerier

1
@Pacerier 목록을 유지 관리하는 대신 각 노드에서 참조 카운트를 유지하고 중복이 발생할 때 카운트를 업데이트 할 수 있다고 생각합니다. 이러한 알고리즘은 검색 및 저장에 훨씬 쉽고 효율적입니다. 또한 중복을 지원하지 않는 기존 알고리즘을 최소한으로 변경해야합니다.
SimpleGuy

50

이진 검색 트리가 빨간색 검은 색 트리이거나 모든 종류의 "트리 회전"작업을하려는 경우 중복 노드가 문제를 일으킬 수 있습니다. 트리 규칙이 다음과 같다고 상상해보십시오.

왼쪽 <루트 <= 오른쪽

이제 루트가 5이고 왼쪽 자식이 0이고 오른쪽 자식이 5 인 간단한 나무를 상상해보십시오. 루트에서 왼쪽 회전을하면 왼쪽 자식에서 5, 오른쪽 자식으로 루트에서 5가됩니다. 없어요. 이제 왼쪽 트리의 어떤 것이 루트와 같지만 위의 규칙은 left <root라고 가정합니다.

빨간색 / 검은 색 나무가 때때로 순서를 벗어나는 이유를 알아 내려고 몇 시간을 보냈습니다. 문제는 위에서 설명한 것입니다. 바라건대 누군가가 이것을 읽고 미래에 디버깅 시간을 절약 할 수 있기를 바랍니다!


18
동일한 노드가 있으면 회전하지 마십시오! 다음 단계로 이동하여 회전하십시오.
Rich

2
다른 해결 방법은 트리 규칙을로 변경 left <= node <= right하거나 값 이 처음 표시 되기 전에 만 삽입 하는 것입니다.
paxdiablo 2016 년

실제로 어떤 문제가 발생할 수 있습니까? 왼쪽 <= node <= 오른쪽으로 확인하면 모든 빨강-검정 트리 작업이 어쨌든 잘 수행됩니다.
Björn Lindqvist

39

세 가지 정의는 모두 수용 가능하고 정확합니다. 그들은 BST의 다른 변형을 정의합니다.

대학 데이터 구조의 책은 그 정의가 유일한 것이 아니라는 것을 명확히하지 못했습니다.

확실히, 복제를 허용하면 복잡성이 추가됩니다. "left <= root <right"정의를 사용하고 다음과 같은 트리가있는 경우 :

      3
    /   \
  2       4

이 트리에 "3"복제 키를 추가하면 다음과 같은 결과가 발생합니다.

      3
    /   \
  2       4
    \
     3

중복은 연속적인 수준이 아닙니다.

이는 위와 같이 BST 표현에서 복제를 허용 할 때 큰 문제입니다. 복제는 여러 레벨로 분리 될 수 있으므로 복제의 존재를 확인하는 것은 노드의 직계 자식을 확인하는 것만 큼 간단하지 않습니다.

이 문제를 피할 수있는 옵션은 중복을 구조적으로 (별도의 노드로) 나타내지 않고 대신 키 발생 횟수를 계산하는 카운터를 사용하는 것입니다. 이전 예제는 다음과 같은 트리를 갖습니다.

      3(1)
    /     \
  2(1)     4(1)

중복 "3"키를 삽입하면 다음과 같이됩니다.

      3(2)
    /     \
  2(1)     4(1)

이는 일부 추가 바이트 및 카운터 작업을 희생하면서 조회, 제거 및 삽입 작업을 단순화합니다.


나는 이것이 내가 사용하고있는 교과서에 언급되지 않은 것에 매우 놀랐습니다. 교수 중 하나를 언급하거나 중복 키도 문제의 SMH ... 사실 않았다
Oloff BIERMANN

22

BST에서, 노드의 왼쪽에서 내림차순의 모든 값은 노드 자체보다 작거나 같습니다 (나중에 참조). 유사하게, 노드의 오른쪽에서 내림차순의 모든 값은 노드 값보다 크거나 같습니다 (a) .

일부 BST는 중복 값을 허용하도록 선택할 수 있으므로 위의 "또는 같음"한정자입니다.

다음 예는 명확 할 수 있습니다.

            |
      +--- 14 ---+
      |          |
+--- 13    +--- 22 ---+
|          |          |
1         16    +--- 29 ---+
                |          |
               28         29

여기에는 중복을 허용하는 BST가 표시됩니다. 값을 찾으려면 루트 노드에서 시작하여 검색 값이 노드 값보다 작거나 큰지 여부에 따라 왼쪽 또는 오른쪽 하위 트리로 내려갑니다.

다음과 같은 방법으로 재귀 적으로 수행 할 수 있습니다.

def hasVal (node, srchval):
    if node == NULL:
         return false
    if node.val == srchval:
        return true
    if node.val > srchval:
        return hasVal (node.left, srchval)
    return hasVal (node.right, srchval)

그리고 그것을 호출 :

foundIt = hasVal (rootNode, valToLookFor)

중복은 동일한 값을 가진 다른 노드에 대한 값을 찾은 후에 계속 검색해야 할 수 있으므로 약간 복잡합니다.


(a)는 당신이 할 수 소원을 제공, 그래서 당신은 당신이 특정 키를 검색하는 방법을 실제로 일종의 그 반대 방향을 조정해야합니다. BST는 오름차순이든 내림차순이든 상관없이 정렬 된 순서 만 유지하면됩니다.


중복 사례의 경우 올바른 하위 항목이 node.val == srchval : 절의 현재 노드와 동일한 지 확인한 다음 올바르게 진행됩니까?
bneil

9

Cormen, Leiserson, Rivest 및 Stein의 세 번째 버전 인 "Introduction to algorithms"책에서 BST (Binary Search Tree)는 중복허용하는 것으로 명시 적으로 정의됩니다 . 그림 12.1과 다음 (287 페이지)에서 볼 수 있습니다.

"이진 검색 트리의 키는 항상 이진 검색 트리 속성을 만족하는 등의 방식으로 저장됩니다하자가 x. 이진 검색 트리의 노드 수를하는 경우는 y왼쪽 하위 트리에서 노드 xy:key <= x:key. 경우 y입니다 오른쪽 하위 트리의 노드 x다음, y:key >= x:key. "

또한, 레드 - 블랙 트리는 다음 페이지 (308)에 다음과 같이 정의된다

"적색 검정 트리는 노드 당 하나의 추가 비트 저장소가있는 이진 검색 트리입니다."

따라서이 책에 정의 된 적갈색 트리는 중복을 지원합니다.


4

모든 정의가 유효합니다. 구현에서 일관성이 유지되는 한 (항상 동일한 노드를 오른쪽에 두거나 항상 왼쪽에 두거나 절대 허용하지 마십시오) 괜찮습니다. 나는 그것을 허용하지 않는 것이 가장 일반적이라고 생각하지만, 그들이 허용되고 왼쪽이나 오른쪽에 배치하면 여전히 BST입니다.


1
중복 키가 포함 된 데이터 세트가있는 경우 해당 항목은 모두 다른 방법 (링크 된 목록 등)을 통해 트리의 1 노드 내에 저장해야합니다. 트리에는 고유 키만 포함되어야합니다.
nickf

1
또한 위키에서 오른쪽 서브 트리에는 루트의 "보다 크거나 같은"값이 포함되어 있습니다. 따라서 위키 정의는 모순적입니다.
SoapBox

1
+1 : 사람들마다 다른 정의를 사용합니다. 새로운 BST를 구현하는 경우 중복 항목에 대해 어떤 가정을하고 있는지 명시해야합니다.
Mr Fooz

1
중복을 허용하면 합의가 (왼쪽 <= 루트 <= 오른쪽)처럼 보입니다. 그러나 BST에 대한 일부 사람들의 정의는 딥을 허용하지 않습니다. 또는 일부 사람들은 추가적인 복잡성을 피하기 위해 그런 식으로 가르 칠 수도 있습니다.
팀 메리 필드

1
틀렸다! 왼쪽 <= 루트 <오른쪽 OR 왼쪽 <루트 <= 오른쪽, OR 왼쪽> 루트> = 오른쪽 OR 왼쪽> = 루트> 오른쪽
Mitch Wheat

3

빨강-검정 트리 구현 작업 빨강-검정 삽입 회전으로 제약 조건을 풀어야한다는 것을 깨달을 때까지 여러 키로 나무를 유효성 검사하는 데 문제가 발생했습니다.

left <= root <= right

내가보고있는 문서 중 중복 키를 허용하지 않고 회전 방법을 다시 작성하고 싶지 않기 때문에 노드 내에서 여러 값을 허용하도록 노드를 수정하기로 결정했으며 중복 키는 입력하지 않았습니다. 나무.


2

당신이 말한 세 가지 사실은 모두 사실입니다.

  • 키는 독특합니다
  • 왼쪽에는이 키보다 작은 키가 있습니다
  • 오른쪽에는이 키보다 큰 키가 있습니다

트리를 뒤집고 작은 키를 오른쪽에 놓을 수 있다고 생각하지만 실제로 "왼쪽"과 "오른쪽"개념은 바로 왼쪽입니다. 실제로 왼쪽이없는 데이터 구조에 대해 생각할 수 있도록하는 시각적 개념 또는 맞습니다, 그래서 그것은 중요하지 않습니다.


1

1.) 왼쪽 <= 루트 <오른쪽

2.) 왼쪽 <루트 <= 오른쪽

3.) left <root <right, 중복 키가 존재하지 않도록하십시오.

알고리즘 책을 찾아야 할 수도 있지만 머리 꼭대기에서 벗어난 것은 (3) 정식 형태입니다.

(1) 또는 (2) 만 중복 노드를 허용하기 시작하면 나오게 하고 당신은 나무 자체 (보다는 목록이 포함 된 노드)에서 중복 된 노드를 넣어.


left <= root <= right가 왜 이상적이지 않은지 설명해 주시겠습니까?
Helin Wang

@paxdiablo의 허용 답변을 살펴보십시오 >=. 와 중복 값이 ​​존재할 수 있음을 알 수 있습니다 . 이상적인 것은 요구 사항에 따라 다르지만 중복 값이 ​​많고 중복이 구조에 존재하도록 허용하면 bst가 선형이 될 수 있습니다 (예 : O (n)).
Robert Paulson 3

1

중복 키 • 동일한 키를 가진 데이터 항목이 둘 이상있는 경우 어떻게됩니까? – 이것은 적갈색 나무에서 약간의 문제를 나타냅니다. – 동일한 키를 가진 노드는 같은 키를 가진 다른 노드의 양쪽에 분산되어 있어야합니다. – 즉, 키가 50, 50, 50 순서로 도착하면 • 두 번째 50은 첫 번째 오른쪽으로 가고 세 번째 50은 첫 번째 왼쪽으로 가길 원합니다. • 그렇지 않으면 트리의 균형이 맞지 않습니다. • 이것은 삽입 알고리즘의 일종의 무작위 화 프로세스에 의해 처리 될 수 있습니다. – 그러나 동일한 키를 가진 모든 항목을 찾아야하는 경우 검색 프로세스가 더 복잡해집니다. • 동일한 키를 사용하여 항목을 무법 화하는 것이 더 간단합니다. –이 토론에서는 중복이 허용되지 않는다고 가정합니다.

중복 키가 포함 된 트리의 각 노드에 대해 링크 된 목록을 작성하고 목록에 데이터를 저장할 수 있습니다.


1

@Robert Paulson의 답변에 더 많은 정보를 추가하고 싶습니다.

노드에 키와 데이터가 있다고 가정 해 봅시다. 따라서 동일한 키를 가진 노드는 다른 데이터를 포함 할 수 있습니다.
(따라서 검색시 동일한 키를 가진 모든 노드를 찾아야합니다)

1) 왼쪽 <= 현재 <오른쪽

2) 왼쪽 <cur <= 오른쪽

3) 왼쪽 <= 현재 <= 오른쪽

4) left <cur <right && cur 는 동일한 키를 가진 형제 노드 를 포함합니다 .

5) 왼쪽 <cur <오른쪽으로 중복 키가 존재하지 않습니다.

1) & 2) 비뚤어 짐을 방지하기 위해 나무에 회전 관련 기능 이없는 경우 제대로 작동합니다 .
그러나이 형태는 작동하지 않습니다AVL 트리레드 - 블랙 트리 회전 교장을 깰 것이기 때문에.
search ()가 키가있는 노드를 찾더라도 중복 키가있는 노드의 리프 노드로 이동해야합니다.
검색 시간 복잡성 만들기 = theta (logN)

3) 회전 관련 기능이있는 모든 형태의 BST와 잘 작동합니다.
그러나 검색에는 BST 사용 목적을 망치는 O (n)이 필요 합니다.
3) 교장과 함께 아래에 나무가 있다고 가정 해보십시오.

         12
       /    \
     10     20
    /  \    /
   9   11  12 
      /      \
    10       12

이 트리에서 search (12) 를 수행 하더라도 루트에서 12를 찾더라도 왼쪽과 오른쪽 자식을 계속 검색하여 중복 키를 찾아야합니다.
내가 말했듯이 이것은 O (n) 시간이 걸립니다.

4) 내가 개인적으로 좋아하는 것입니다. 형제 가 동일한 키를 가진 노드를 의미 한다고 가정 해 봅시다 .
위의 트리를 아래로 변경할 수 있습니다.

         12 - 12 - 12
       /    \
10 - 10     20
    /  \    /
   9   11  12

이제 중복 키를 위해 하위를 탐색 할 필요가 없기 때문에 모든 검색에 O (logN)가 사용됩니다.
또한이 보안 주체는 AVL 또는 RB 트리 와도 잘 작동합니다 .


0

요소 순서 관계 <=는 전체 순서 이므로 관계는 반복적이어야하지만 일반적으로 이진 검색 트리 (일명 BST)는 중복이없는 트리입니다.

그렇지 않으면 중복이있는 경우 동일한 삭제 기능을 두 번 이상 실행해야합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.