HashTable 과 HashSet 의 유형 함정
12868 단어 Hashtable
우선 나 는 모든 문자열 이 나타 나 는 횟수 를 Hashtable 로 집계 했다.
그리고 나 서 나 는 이 문자열 의 쓸모없는 단 어 를 사전 으로 걸 러 내야 한 다 는 것 을 알 게 되 었 다. 그래서 나 는 또 하나의 HashSet 를 통계 사전 으로 정의 했다.
나의 최초의 코드 는 다음 과 같다.
1 Stopwatch st = new Stopwatch();//
2 Hashtable queryTable = TopK.GetHashtable();// HashTable
3 HashSet<string> test = new HashSet<string>();
4 string path = "dic.txt";
5 if (File.Exists(path))
6 {
7
8 using (StreamReader sr = new StreamReader(path, System.Text.Encoding.Default))
9 {
10 string s = string.Empty;
11 while (!string.IsNullOrEmpty(s = sr.ReadLine()))
12 {
13 test.Add(s);
14 }
15 }
16 }//
17 Hashtable queryTable2 = new Hashtable();
18 List<string> teststring = new List<string>();
19 var aa = teststring[0];
20 foreach (var key in queryTable.Keys)// Hashtable key
21 {
22
23 if (!test.Contains(key))
24 {
25 queryTable2.Add(key, queryTable[key]);
26 }
27
28 }
29 st.Stop();
30 Console.WriteLine(st.ElapsedMilliseconds);
31 Console.Read();
한눈 에 보기에 이 코드 는 아무런 오류 가 없 었 다. (HashTable 에는 120 여 만 개의 문자열 이 있 고 사전 에는 11 만 개의 문자열 이 있다.)
그런데 내 가 운행 한 후에 오 랜 만 에 결과 가 나 오지 않 았 다. 마침내 콘 솔 에서 2400000 을 수출 했 는데 2400 초 를 운행 했다!
곰 곰 이 생각해 본 후에 먼저 사전 을 불 러 오 는 데 시간 이 걸 릴 수 없 으 며, 유일 하 게 시간 이 걸 릴 수 있 는 것 은 바로 이 문장 이다.
1 foreach (var key in queryTable.Keys)// Hashtable key
2 {
3
4 if (!test.Contains(key))
5 {
6 queryTable2.Add(key, queryTable[key]);
7 }
8
9 }
test 는 HashSet 형식 입 니 다. 검색, 즉 contains 방법의 시간 복잡 도 는 O (1) 여야 합 니 다. 그렇게 오래 걸 리 지 말 아야 합 니 다. var 가 정의 한 key, 포장 / 분해 로 인 한 것 입 니까?
그리고 나 서 나 는 var 를 string 으로 바 꾸 었 다.
1 foreach (string key in queryTable.Keys)// Hashtable key
2 {
3
4 if (!test.Contains(key))
5 {
6 queryTable2.Add(key, queryTable[key]);
7 }
8
9 }
결 과 는 15 초 만 에 콘 솔 에서 실행 결 과 를 출력 했다. 1537
그러나 MSDN 에서 var 에 대한 정 의 는:
방법 범위 에서 설명 하 는 변 수 는 암시 적 형식 var 를 가 질 수 있 습 니 다.암시 적 형식의 로 컬 변 수 는 강 한 형식 변수 입 니 다.
그런데 제 HashTable 에 있 는 key 는 문자열 을 추 가 했 습 니 다. 그리고 HashTable. add 방법의 원형 을 찾 았 습 니 다.
1 public virtual void Add ( 2 Object key, 3 Object value 4 )
真是坑啊,原来Hashtable在添加元素的时候,自动转化成了object类型
为了一探究竟,再用ILspy查看底层源代码,
找到if (!test.Contains(key))这一句
修改前
1 IL_00a4: ldloc.s CS$5$0001 2 IL_00a6: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() 3 IL_00ab: stloc.s key 4 IL_00ad: nop 5 IL_00ae: ldloc.2 6 IL_00af: ldloc.s key 7 IL_00b1: call bool [System.Core]System.Linq.Enumerable::Contains<object>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, !!0) 8 IL_00b6: stloc.s CS$4$0000 9 IL_00b8: ldloc.s CS$4$0000 10 IL_00ba: brtrue.s IL_00d0
컴 파 일 러 의 기본 키 는 object 형식 이기 때문에 IEnumerable 인터페이스의 Contains 방법 을 호출 했 습 니 다. mscorlib] System. collections. Generic. IEnumerable ` 1 , !!0)
(HashSet 은 IEnumerable 을 실현 했다) 즉, HashSet 의 모든 요 소 를 끊임없이 호출 하 는 Equals 방법 과 key 를 비교 하 는 것 이다.
어쩐지 그렇게 오래 운행 하 더 라 니.
수정 후1 IL_00a4: ldloc.s CS$5$0001 2 IL_00a6: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() 3 IL_00ab: castclass [mscorlib]System.String 4 IL_00b0: stloc.s key 5 IL_00b2: nop 6 IL_00b3: ldloc.2 7 IL_00b4: ldloc.s key 8 IL_00b6: callvirt instance bool class [System.Core]System.Collections.Generic.HashSet`1<string>::Contains(!0) 9 IL_00bb: stloc.s CS$4$0000 10 IL_00bd: ldloc.s CS$4$0000 11 IL_00bf: brtrue.s IL_00d5
이때 서 야 정상 적 인 HashSet 의 Contains 를 호출 하여 [System. Core] System. Collections. Generic. HashSet ` 1 < string >: Contains (! 0)
시간 복잡 도 O (1)
곰 곰 이 생각해 보면 여기 또 하나의 함정 은 바로 HashSet. Contains (object a) 를 호출 하 는 것 이다.
첫 번 째 는 우리 가 평소에 알 고 있 는 IEnumerator 의 인 터 페 이 스 를 호출 하여 모든 요소 와 매개 변수 a 를 비교 (Equals 방법 을 호출) 하여 a 가 HashSet 에 있 는 지 판단 하 는 것 이다.
두 번 째 는 범 형 이 HashSet. Contains < T > (T a) 를 실현 하 는 것 입 니 다. T 는 우리 가 HashSet 을 정의 할 때 지정 한 유형 입 니 다. 이때 Contains 는 해시 표 형식 으로 a 를 찾 을 수 있 습 니 다.
우리 가 사용 할 때 유형 T 를 지정 하지 않 으 면 ,컴 파 일 러 는 자동 으로 최적화 되 고 컴 파 일 러 는 a 가 T 유형 인지 아 닌 지 를 판단 합 니 다.
T 타 입 이면 컴 파 일 러 는 두 번 째 구현 을 자동 으로 호출 하고, 그렇지 않 으 면 첫 번 째 구현 을 호출 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
hive0.13 mapjoin hashtable에서 찾을 수 없는 버그온라인 작업 오류: 이것은 사실mapjoin의 버그입니다.mapjoin은 작은 테이블을 통해hashtable를 생성한 다음distributecache에 넣고, 뒤의task는distributecache를 통해 로컬로 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.