대부분의 프로그래밍 언어에서 사전은 해시 테이블보다 선호됩니다. 그 이유는 무엇입니까?
Dictionary
의 구현 이라고 생각 했다 Hashtable
.
HashTable
합니다. 언어에 제네릭을 추가하면 제네릭 버전이라고했습니다 Dictionary
. 둘 다 해시 테이블입니다.
대부분의 프로그래밍 언어에서 사전은 해시 테이블보다 선호됩니다. 그 이유는 무엇입니까?
Dictionary
의 구현 이라고 생각 했다 Hashtable
.
HashTable
합니다. 언어에 제네릭을 추가하면 제네릭 버전이라고했습니다 Dictionary
. 둘 다 해시 테이블입니다.
답변:
그만한 가치가있는 사전 은 (개념적으로) 해시 테이블입니다.
" Dictionary<TKey, TValue>
클래스 대신 클래스를 사용하는 이유는 Hashtable
무엇입니까?" 를 의미한다면 쉬운 대답 Dictionary<TKey, TValue>
입니다. 일반적인 유형입니다.Hashtable
입니다. 즉 Dictionary<TKey, TValue>
, 임의의 객체를 삽입 할 수 없으며 취한 값을 캐스팅 할 필요가 없기 때문에 유형 안전을 얻을 수 있습니다.
흥미롭게도 Dictionary<TKey, TValue>
.NET Framework 구현 Hashtable
은 소스 코드에서이 주석에서 알 수 있듯이을 기반으로합니다 .
일반 사전은 Hashtable의 소스에서 복사되었습니다.
HashTable
(클래스) 및 Dictionary
(클래스) 해시 테이블 (개념)입니다,하지만이 HashTable
아닙니다 Dictionary
,도 아니다이다 . 그것들은 매우 유사한 방식으로 사용되며 a와 동일한 형식화되지 않은 방식으로 작동 할 수 있지만 코드를 직접 공유하지는 않습니다 (부분은 매우 유사한 방식으로 구현 될 수 있음). Dictionary
HashTable
Dictionary<Object,Object>
HashTable
Dictionary
<<< >>> Hashtable
차이점 :
Synchronized()
KeyValuePair
<<< >>> 열거 된 항목 :DictionaryEntry
Dictionary
/ Hashtable
유사점 :
GetHashCode()
방법이 필요합니다유사한 .NET 컬렉션 (사전 및 해시 테이블 대신 사용할 후보) :
ConcurrentDictionary
- 스레드 안전 (여러 스레드에서 동시에 안전하게 액세스 가능)HybridDictionary
- 최적화 된 성능 (작은 품목 및 많은 품목)OrderedDictionary
-int 인덱스를 통해 값에 액세스 할 수 있습니다 (항목이 추가 된 순서대로)SortedDictionary
-아이템 자동 정렬 된StringDictionary
- 문자열을 강력하게 입력하고 최적화StringDictionary
... btw의 +1 은 기본 생성자를 사용할 때 StringDictionary
와 다릅니다 Dictionary<string, string>
.
때문에 Dictionary
일반 클래스 (이다 Dictionary<TKey, TValue>
), 그 콘텐츠에 액세스되도록하는 (즉, 당신은에서 캐스트 할 필요가 없습니다 유형 안전 Object
당신이와 마찬가지로, Hashtable
).
비교
var customers = new Dictionary<string, Customer>();
...
Customer customer = customers["Ali G"];
에
var customers = new Hashtable();
...
Customer customer = customers["Ali G"] as Customer;
그러나 Dictionary
내부적으로 해시 테이블로 구현되므로 기술적으로 동일한 방식으로 작동합니다.
참고 : .NET에서는 Hashtable
여러 판독기 스레드와 단일 쓰기 스레드에서 사용하기에 안전한 스레드입니다.Dictionary
에 스레드 안전하지만 공용 정적 멤버는 스레드 안전하지만 모든 인스턴스 멤버는 스레드 안전을 보장하지 않습니다.
Hashtable
이 때문에 모든 사전을 다시 바꿔야 했습니다.
ConcurrentDictionary
에는 모든 공개 / 보호 메소드가 스레드 안전하도록 구현 된 클래스가 추가되었습니다 . 레거시 플랫폼을 지원할 필요가없는 경우 Hashtable
멀티 스레드 코드 를 대체 할 수 있습니다 . msdn.microsoft.com/en-us/library/dd287191.aspx
사람들은 사전이 해시 테이블과 동일하다고 말합니다.
반드시 그런 것은 아닙니다. 해시 테이블은 사전 을 구현 하는 한 가지 방법 입니다. 그 전형적인 점이며 Dictionary
클래스의 .NET에서 기본값 일 수 있지만 정의상 유일한 것은 아닙니다.
링크 된 목록이나 검색 트리를 사용하여 사전을 똑같이 잘 구현할 수 있지만 효율적이지 않습니다 (일부 메트릭의 경우 효율적).
Dictionary<K,V>
. IDictionary<K,V>
그래도 아무것도 될 수 있습니다 :)
Collections
& Generics
는 객체 그룹을 처리하는 데 유용합니다. .NET에서 모든 컬렉션 개체는 인터페이스 아래에 있으며이 인터페이스 IEnumerable
에는 ArrayList(Index-Value))
&가 HashTable(Key-Value)
있습니다. .NET 프레임 워크 2.0 후 ArrayList
및 HashTable
교환되었다 List
& Dictionary
. 이제 Arraylist
&HashTable
는 현재 프로젝트에서 더 이상 사용되지 않습니다.
의 차이에 오는 HashTable
및 Dictionary
, Dictionary
로 어디 제네릭 Hastable
일반 없습니다. 에 모든 유형의 객체를 추가 할 수 HashTable
있지만 검색하는 동안 필요한 유형으로 캐스트해야합니다. 따라서 형식이 안전하지 않습니다. 그러나dictionary
선언하면서 키와 값의 유형을 지정할 수 있으므로 검색하는 동안 캐스트 할 필요가 없습니다.
예를 보자.
해시 테이블
class HashTableProgram
{
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
foreach (DictionaryEntry de in ht)
{
int Key = (int)de.Key; //Casting
string value = de.Value.ToString(); //Casting
Console.WriteLine(Key + " " + value);
}
}
}
사전,
class DictionaryProgram
{
static void Main(string[] args)
{
Dictionary<int, string> dt = new Dictionary<int, string>();
dt.Add(1, "One");
dt.Add(2, "Two");
dt.Add(3, "Three");
foreach (KeyValuePair<int, String> kv in dt)
{
Console.WriteLine(kv.Key + " " + kv.Value);
}
}
}
사전:
존재하지 않는 키를 찾으려면 예외를 반환 / 던집니다.
복싱 및 언 박싱이 없기 때문에 해시 테이블보다 빠릅니다.
공개 정적 멤버 만 스레드로부터 안전합니다.
사전은 일반적인 유형이므로 모든 데이터 유형과 함께 사용할 수 있습니다 (생성시 키와 값 모두에 대한 데이터 유형을 지정해야 함).
예: Dictionary<string, string> <NameOfDictionaryVar> =
new Dictionary<string, string>();
Dictionay는 해시 테이블의 형태 보증 구현, Keys
그리고 Values
강력하게 형식화된다.
해시 테이블 :
존재하지 않는 키를 찾으려면 null을 반환합니다.
복싱과 언 박싱이 필요하기 때문에 사전보다 느립니다.
Hashtable의 모든 멤버는 스레드로부터 안전합니다.
해시 테이블은 일반적인 유형이 아닙니다.
Hashtable은 느슨하게 형식화 된 데이터 구조이므로 모든 유형의 키와 값을 추가 할 수 있습니다.
Dictionary.TryGetValue
C #을 사용하여 데이터 구조의 광범위한 시험 MSDN의 문서에서는 차이도 존재한다고 충돌 해결 전략 :
Hashtable 클래스는 rehashing 이라는 기술을 사용합니다 .
리 해싱은 다음과 같이 작동합니다. H 1 ... H n 해시 함수 세트가 있으며, 해시 테이블에서 항목을 삽입하거나 검색 할 때 처음에는 H 1 해시 함수가 사용됩니다. 이로 인해 충돌이 발생하면 대신 H 2 가 시도되고 필요한 경우 H n 까지 진행됩니다 .
사전은 체인 이라고하는 기술을 사용합니다 .
리 해싱을 사용하면 충돌시 해시가 다시 계산되고 해시에 해당하는 새 슬롯이 시도됩니다. 그러나 체인을 사용하면 충돌을 방지하기 위해 보조 데이터 구조가 사용됩니다 . 특히 사전의 각 슬롯에는 해당 버킷에 매핑되는 요소 배열이 있습니다. 충돌이 발생하면 충돌 요소 앞에 버킷 목록이 추가됩니다.
.NET Framework 3.5부터는 키만 필요하고 값이없는 경우 HashSet<T>
모든 장점을 제공 Dictionary<TKey, TValue>
하는가 있습니다.
따라서 a를 사용 Dictionary<MyType, object>
하고 항상 null
유형 안전 해시 테이블을 시뮬레이트하기 위해 값을 설정하면로 전환하는 것이 HashSet<T>
좋습니다.
공지 사항은 MSDN은 말한다 : "사전 <(의 <(TKEY, TValue이>)>) 클래스가로 구현 해시 테이블 "이 아닌 "<(클래스가로 구현됩니다 사전 <(TKEY, TValue>) 중>) 해시 "
Dictionary는 HashTable로 구현되지 않지만 해시 테이블의 개념에 따라 구현됩니다. 내부적으로 Microsoft는 동일한 코드를 사용하고 Object 유형의 기호를 TKey 및 TValue로 대체 할 수 있었지만 Generics를 사용했기 때문에 구현은 HashTable 클래스와 관련이 없습니다.
.NET 1.0에서는 Generics가 존재하지 않았습니다. 이것은 HashTable과 ArrayList가 처음 시작된 곳입니다.
해시 테이블 :
키 / 값은 힙에 저장하는 동안 개체 (복싱) 유형으로 변환됩니다.
힙에서 읽는 동안 키 / 값을 원하는 유형으로 변환해야합니다.
이러한 작업은 매우 비용이 많이 듭니다. 우리는 가능한 한 boxing / unboxing을 피해야합니다.
사전 : HashTable의 일반 변형.
복싱 / 언 박싱이 없습니다. 전환이 필요하지 않습니다.
Hashtable 객체는 컬렉션의 요소를 포함하는 버킷으로 구성됩니다. 버킷은 Hashtable 내에있는 요소의 가상 하위 그룹으로, 대부분의 컬렉션에서보다 쉽고 빠르게 검색 및 검색 할 수 있습니다 .
Dictionary 클래스는 Hashtable 클래스와 기능이 동일합니다. Hashtable 의 요소가 Object 유형이므로 값 유형을 저장하거나 검색하는 경우 일반적으로 boxing 및 unboxing이 발생하기 때문에 특정 유형 (Object 이외의)의 사전은 값 유형에 대해 Hashtable보다 성능이 우수 합니다.
추가 정보 : 해시 테이블 및 사전 컬렉션 유형
또 다른 중요한 차이점은 Hashtable이 스레드 안전이라는 것입니다. Hashtable에는 MR / SW (Multiple Reader / Single Writer) 스레드 안전 기능이 내장되어있어 Hashtable을 사용하면 ONE writer가 잠금없이 여러 판독기와 함께 사용할 수 있습니다.
사전의 경우 스레드 안전성이 없습니다. 스레드 안전성이 필요한 경우 자체 동기화를 구현해야합니다.
더 자세히 설명하려면 :
Hashtable은 다음을 통해 스레드 안전성을 제공합니다.
Synchronized
속성을 하여 컬렉션 주변의 스레드 안전 래퍼를 반환합니다. 랩퍼는 모든 추가 또는 제거 조작에서 전체 콜렉션을 잠그면 작동합니다. 따라서 컬렉션에 액세스하려는 각 스레드는 해당 차례가 하나의 잠금을 수행 할 때까지 기다려야합니다. 이는 확장 할 수 없으며 대규모 컬렉션의 경우 성능이 크게 저하 될 수 있습니다. 또한 디자인은 경쟁 조건으로부터 완전히 보호되지 않습니다..NET Framework 2.0 컬렉션 클래스
List<T>, Dictionary<TKey, TValue>
등은 스레드 동기화를 제공하지 않습니다. 여러 스레드에서 동시에 항목을 추가하거나 제거 할 때 사용자 코드가 모든 동기화를 제공해야합니다.
스레드 안전성뿐만 아니라 형식 안전성이 필요한 경우 .NET Framework에서 동시 컬렉션 클래스를 사용하십시오. 자세한 내용은 여기를 참조하십시오 .
또 다른 차이점은 사전에 여러 항목을 추가 할 때 항목이 추가되는 순서가 유지된다는 것입니다. Dictionary에서 항목을 검색 할 때 삽입 한 순서대로 레코드를 가져옵니다. Hashtable은 게재 신청서를 보존하지 않습니다.
Hashset
사용 시나리오에서 MR / SW 스레드 안전성 이 보장 됩니다 . MR / SW가 완전히 안전하기는했지만 삭제를 안전하게 처리하면 MR / SW 안전 비용이 크게 증가합니다. 무삭제 Dictionary
시나리오에서 최소 비용으로 MR / SW 안전성을 제공 할 수 있었지만 MS는 무삭제 시나리오를 "특별한"것으로 취급하지 않기를 원한다고 생각합니다.
대부분의 프로그래밍 언어에서 사전은 해시 테이블보다 선호됩니다.
나는 이것이 사실이라고 생각하지 않는다. 대부분의 언어는 그들이 선호 하는 용어 에 따라 하나 또는 다른 언어를 가진다 .
그러나 C #에서 분명한 이유는 C # HashTables와 System.Collections 네임 스페이스의 다른 멤버가 거의 사용되지 않기 때문입니다. 그들은 C # V1.1에 존재했습니다. C # 2.0에서 System.Collections.Generic 네임 스페이스의 Generic 클래스로 대체되었습니다.
.NET Reflector 를 사용하여 내가 본 것에 따르면 :
[Serializable, ComVisible(true)]
public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable
{
// Fields
private Hashtable hashtable;
// Methods
protected DictionaryBase();
public void Clear();
.
.
.
}
Take note of these lines
// Fields
private Hashtable hashtable;
따라서 DictionaryBase가 내부적으로 HashTable을 사용하는지 확인할 수 있습니다.