2012-01-14 1 views
1

사전에 anagram 단어를 찾으려면 Dictionary<Dictionary<char,int>, List<string>>의 알고리즘을 구현하고 싶습니다.사전에 대한 액세스 시간 <사전 <char,int>, 목록 <string>>은 아직 O (1)입니까?

이 사전에 내 맞춤형 EqualityComparer을 구현해야하므로 액세스 시간은 여전히 ​​O (1) 즉 O (1)입니까?

두 번째 질문은 EqualityComparer의 일부로 GetHashCode()을 구현해야합니다. Dictionary<Dictionary<char,int>, List<string>>에 대해 GetHashCode()을 결정하는 효율적인 방법은 무엇입니까?

방금이 방법을 생각해 냈습니다. 더 좋은 대안이 있습니까?

public int GetHashCode(Dictionary<char, int> obj) 
    { 
     unchecked 
     { 
      int hashCode = 17; 
      foreach (var item in obj) 
      { 
       hashCode += 23 * item.Key.GetHashCode(); 
      } 
      return hashCode; 
     } 
    } 

모든 조언을 부탁드립니다. 감사!

+3

변경 가능한 키가있는 사전은 –

+0

통증의 처방입니다. 그러나 전형적인 .net 코드 벤에서 가장 일반적인 사전 키가 아닙니까? – ioWint

+1

은 가장 일반적인 사전 키가 아닙니까? 아니요, 사전 및 기타 컬렉션 유형은 다른 사전의 키로 자주 사용되지 않습니다. –

답변

2

Dictionary를 키로 사용하는 대신 "need"를 "d1e2n1"이라는 문자열로 변환하는 것은 어떻습니까? 이 문자열을 만들려면 이진 트리를 사용할 수 있습니다. 문자는 키로 사용되고 문자는 값으로 사용됩니다. 바이너리 트리는 자동으로 키에 의해 정렬됩니다. 이는 사전에 해당하지 않습니다.

이진 표현과 XOR 연산을 결합하여 단일 해시 값에서 조합 해시 값을 계산할 수 있습니다. C#을, 당신은 같은 것을 할 것입니다 : 정렬되지 않은 목록의 항목을 찾기

public override int GetHashCode() 
{ 
    // Combine hashcode of a and b 
    return a.GetHashCode()^b.GetHashCode(); 
} 

오 (N) 작업입니다. 이진 검색이 사용되는 경우 정렬 된 목록에서 항목을 찾는 것은 O (log (n)) 연산입니다.

사전의 목록에서 단어를 찾는 것은 O (1 + n) 연산 또는 O (1 + log (n)) 연산과 동일합니다. 이는 O (log (n)) 연산과 동일합니다.


EDIT 다음 단어에 대한 이러한 정의를 이용

private string GetFrequency(string word) 
{ 
    var dict = new SortedDictionary<char, int>(); // Implemented as binary tree 
    foreach (char c in word.ToLower()) { 
     int count; 
     if (dict.TryGetValue(c, out count)) { 
      dict[c] += 1; 
     } else { 
      dict[c] = 1; 
     } 
    } 
    return dict.Aggregate(new StringBuilder(), (sb, item) => sb.Append(item.Key).Append(item.Value), sb => sb.ToString()); 
} 

:

var anagrams = new Dictionary<string, List<string>>(); 
foreach (string word in words) { 
    string key = GetFrequency(word); 
    List<string> list; 
    if (anagrams.TryGetValue(key, out list)) { 
     list.Add(word); 
    } else { 
     list = new List<string> { word }; 
     anagrams.Add(key, list); 
    } 
} 

그것은 키를 얻기 위하여이 방법을 사용한다 : 여기서

가 가능한 구현 ...

var words = new List<string> { "need", "eden", "team", "meat", "meta", "Nat", "tan" }; 

이 테스트 ...

foreach (var item in anagrams.OrderBy(x => x.Key)) { 
    Console.WriteLine(); 
    Console.WriteLine(item.Key + ":"); 
    foreach (string word in item.Value.OrderBy(w => w)) { 
     Console.WriteLine(" " + word); 
    } 
} 

...이 출력

생산
a1e1m1t1: 
    meat 
    meta 
    team 

a1n1t1: 
    Nat 
    tan 

d1e2n1: 
    eden 
    need 

EDIT # 2 : 시험 결과가 될

private string GetFrequencyByBenVoigt(string word) 
{ 
    char[] chars = word.ToLower().ToCharArray(); 
    Array.Sort(chars); 
    return new string(chars); 
} 

벤 보이트 의해 제안 여기

주파수 계산이다

aemt: 
    meat 
    meta 
    team 

ant: 
    Nat 
    tan 

deen: 
    eden 
    need 
+0

일반적으로 좋은 아이디어이지만, "deen"(알파벳순으로 정렬하고 반복을 보존하는 방법)은 어떨까요? –

+0

사실 가능한 한, 분석에서 단어의 사전으로 CharacterHashMap을 가져온 후에 문자열로 만들고 키로 사용할 수 있습니다. 하지만 문자열 표현을 얻기 전에 CharacterHashMap을 정렬해야합니다. – ioWint

+0

그리고 일부는 내가 anagram 아니지만 자신의 HashCode 동등하지만 Comprarison 실패 두 단어가 발생한다면 어떻게 더 잘 이해할 수 있습니까? 그들이 사전에 어떻게 저장 될까요? http://stackoverflow.com/a/3809835/253032 – ioWint

1

컨테이너 내용을 기반으로하는 해시 코드는 컨테이너의 항목 수에 O(n)이됩니다. 사전을 다른 유형으로 랩핑하고 해시 코드를 캐시하여 한 번 계산하면되므로 ... 사전보다는 해당 데이터를 저장하는 몇 가지 효율적인 방법을 생각할 수 있습니다.

+0

이론상의 O (1) 액세스 시간은 언제입니까? 이 시나리오를 위해 제안을 제안 할 의향이 있습니까? – ioWint

+0

사전에 의해 내부적으로 사용되는 해시 테이블이 크기에 비해 몇 개의 항목 만 포함하고 해시 코드의 분포가 양호한 경우 O (1)에 도달합니다. Microsoft의 사전 구현은 성능이 떨어지기 전에 해시 테이블 크기를 자동으로 증가시킵니다. –

+0

@Oliver : 각 요소의 복잡도는 선형이지만 사전의 요소 수에는 선형이 아닙니다. –

2

Dictionary<TKey, TValue>의 액세스 시간은 O (1)에 접근하지만 정확히 일치하지는 않습니다. 이상적인 시나리오 (좋은 배포/충돌이 거의 없음)에서는 O (1) 인 것으로 생각할 수 있습니다. GetHashCode 값의 변화가 적어 충돌이 많이 발생하는 경우 액세스 시간이 저하되고 O (N)에 접근 할 수 있습니다.