해시 테이블과 이진 트리


30

사전을 구현할 때 ( '고객 ID별로 고객 데이터를 조회하고 싶습니다') 사용되는 일반적인 데이터 구조는 해시 테이블과 이진 검색 트리입니다. 예를 들어 C ++ STL 라이브러리는 (균형) 이진 검색 트리를 사용하여 사전을 구현하고 (맵이라고 함) .NET 프레임 워크는 해시 테이블을 사용합니다.

이러한 데이터 구조의 장단점은 무엇입니까? 특정 상황에서 합리적인 다른 옵션이 있습니까?

키가 강력한 기본 구조를 갖는 경우, 특히 1과 n 사이의 정수 또는 다른 것에는 관심이 없습니다.


1
나는 당신을 화나게 할 것이지만 "1과 n 사이의 정수"라고 말할 수는 없습니다.이 경우 배열은 다른 모든 데이터 구조를 능가하기 때문입니다 :-). "문자열"은 공정하고 대부분의 상황에 적용됩니다.
jmad

@jmad 그는 그 사건에 관심 이 없다고 말했다 .
Joe

@ 조 나는 이것을 고려한 것이 분명하다고 생각했다. 어쨌든 이것이 최악의 열쇠를 제시 할 이유가 아닙니다.
jmad

1
실제로 .NET에는 트리를 사용하여 구현 된 사전과 해시 테이블을 사용하여 구현 된 사전이 모두 있습니다 (2011 표준 이후 C ++도 마찬가지).
sepp2k

답변:


26

이 주제에 대한 전체 논문이 작성 될 수 있습니다. 몇 가지 중요한 사항을 다루고 다른 데이터 구조에 대한 논의를 최소한으로 유지합니다 (실제로 많은 변형이 있음). 이 답변에서 은 사전의 키 수입니다.

짧은 대답은 대부분의 경우 해시 테이블이 더 빠르지 만 최악의 경우 매우 나쁠 수 있다는 것입니다. 검색 트리는 최악의 상황길들이 는 등 많은 장점이 있지만 일반적인 경우에는 다소 느립니다.

영형(())영형2()

2영형(1)

해시 테이블의 일반적인 문제는 복잡성이 보장되지 않는다는 것입니다.영형(1)

  • 또한, 테이블이 가득 차는 지점이 있습니다. 이런 일이 발생하면 (또는 그보다 약간 전에) 테이블을 확장해야하며, 비용 으로 모든 요소를 ​​이동해야합니다 . 이는 많은 요소가 추가 될 때 "저렴한"동작을 유발할 수 있습니다.영형()
  • 입력이 몇 가지 해시 값에 대해 충돌 할 수 있습니다. 이것은 자연스럽게 거의 발생하지 않지만, 침입자가 입력을 선택하면 보안 문제가 될 수 있습니다. 이는 일부 서버의 속도를 상당히 저하시키는 방법입니다. 이 문제로 인해 일부 프로그래밍 언어 구현 (예 : Perl 및 Python)이 일반 오래된 해시 테이블에서 해시 테이블이 빌드 될 때 선택된 임의의 숫자를 포함하는 해시 함수로 전환되었으며이 임의의 데이텀을 잘 분산시키는 해시 함수와 함께 ( 의 곱하기 상수가 증가 ) 또는 이진 검색 트리로 증가합니다. 암호화 해시를 사용하여 충돌을 피할 수는 있지만 실제로 암호화 해시는 계산 속도가 매우 느리기 때문에 실제로는 수행되지 않습니다.영형(1)

데이터 지역성 을 믹스에 던지면 해시 테이블의 성능이 저하됩니다. 관련 요소를 멀리 떨어져 저장하기 때문에 정확하게 작동합니다. 즉, 응용 프로그램이 접두사를 순서대로 공유하는 요소를 찾는 경우 캐시 효과의 이점을 얻지 못합니다. 응용 프로그램이 본질적으로 무작위 조회를하는 경우에는 관련이 없습니다.

검색 트리를 선호하는 또 다른 요소는 변경 불가능한 데이터 구조라는 것입니다. 트리의 사본을 가져 와서 일부 요소를 변경해야하는 경우 대부분의 데이터 구조를 공유 할 수 있습니다. 해시 테이블의 복사본을 가져 오는 경우 전체 포인터 배열을 복사해야합니다. 또한 순전히 기능적인 언어로 작업하는 경우 해시 테이블은 종종 옵션이 아닙니다.

문자열을 넘어 서면 해시 테이블과 이진 검색 트리는 키의 데이터 유형에 대해 다른 요구 사항을 만듭니다. 해시 테이블에는 해시 함수가 필요합니다 (키에서 정수까지 , 이진 검색 트리에는 총 순서가 필요하지만 키가 저장된 데이터 구조에 충분한 공간이있는 경우 해시를 캐시 할 수 있습니다. 비교 결과 (이진 연산)를 캐싱하는 것은 종종 비실용적입니다. 반면에, 비교는 바로 가기의 이점을 얻을 수 있습니다. 키가 처음 몇 바이트 내에서 종종 다른 경우, 음의 비교는 매우 빠릅니다.케이1케이2h(케이1)=h(케이2)

특히 키 순서 를 필요로하는 경우 (예 : 알파벳 순서로 키를 나열하려는 경우) 해시 테이블은 도움이되지 않습니다 (키를 정렬해야 함). 직접 검색 트리를 순회 할 수 있습니다.

이진 검색 트리와 해시 테이블을 해시 트리 형식으로 결합 할 수 있습니다 . 해시 트리는 해시에 따라 검색 트리에 키를 저장합니다. 예를 들어, 계산하기 쉬운 순서 관계가없는 데이터에 대해 작업하려는 순수 기능 프로그래밍 언어에서 유용합니다.

키가 문자열 (또는 정수) 인 경우 trie 는 다른 옵션이 될 수 있습니다. trie는 트리이지만 검색 트리와 다르게 색인화됩니다. 키를 이진법으로 작성하고 0을 위해 왼쪽으로 가고 1을 위해 오른쪽으로갑니다. 액세스 비용은 키 길이에 비례합니다. 중간 노드를 제거하기 위해 트리를 압축 할 수 있습니다. 이것은 patricia trie 또는 기수 나무 로 알려져 있습니다. 기수 트리는 특히 많은 키가 공통 접두사를 공유하는 경우 균형 트리보다 성능이 뛰어납니다.


2
BST도 나쁜 데이터 지역성을 가지고 있지 않습니까?
svick

@svick 노드가 할당되는 방법에 따라 그렇지 않을 수도 있습니다. 트리의 특성을 높이면 실행 시간을 훼손하지 않고 도움을 줄 수 있습니다 (비용은 더 크고 복잡한 코드 임).
Gilles 'SO- 악마 중지'

2
BST에서는 "순서대로"요소를 쉽게 얻을 수 있으며, 해시 테이블의 경우 문제가되지 않습니다.
vonbrand

보안상의 이유 외에, 평균 사례가 이진 트리보다 나은 경우 해시 테이블에 최악의 시간이 나쁜 경우 왜 중요한가? 유틸리티 / 사용자 편의가 트리를 마치는 데 걸리는 시간과 대략 선형 관계가 있다고 생각하므로 예상되는 (평균) 값이 모두 중요합니다.
Kelmikra

@ Kyth'Py1k "완료 할 나무"는 무엇을 의미합니까? 해시 테이블의 요점은 전체 트리가 아닌 한 번에 하나의 값에 액세스하는 것입니다. 그렇지 않으면 목록이나 배열이 더 잘 작동합니다. 평균값이 중요한 상황 (예 : 실시간 제약 조건이있는 경우와 같이 항상 그런 것은 아님)에서도, 주어진 상황에서 이루어진 요청에 대한 평균값입니다. — 예를 들어 특정 접두사에 바이어스.
Gilles 'SO- 악 그만
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.