Tải bản đầy đủ - 0 (trang)
Chapter 11.  Data Structures and Algorithms

Chapter 11.  Data Structures and Algorithms

Tải bản đầy đủ - 0trang

Introduction

Inthischapter,youwilllookatcertaindatastructuresand

algorithmsthatarenotavailableforyouintheFCLthrough

Version2.0.Examplesareprovidedforalgorithmslikehashcodecreationandstringbalancing.TheFCLdoesnotsupport

everydatastructureyoumightneed,sothischapterprovides

solutionsforpriorityanddoublequeues,binaryandn-arytrees,

sets,andamultimap,aswellasmanyotherthings.



Recipe11.1.CreatingaHashCodeforaData

Type

Problem

Youhavecreatedaclassorstructurethatwillbeusedasakey

inaHashtableorDictionary.Youneedtooverloadthe

GetHashCodemethodinordertoreturnagooddistributionofhash

values(theDiscussionsectiondefinesagooddistributionof

hashvalues).Youalsoneedtochoosethebesthash-code

algorithmtouseintheGetHashCodemethodofyourobject.



Solution

Thefollowingproceduresimplementhash-codealgorithmsand

canbeusedtooverridetheGetHashCodemethod.Includedinthe

discussionofeachmethodaretheprosandconsofusingit,as

wellaswhyyouwouldwanttouseoneinsteadofanother.

Inaddition,itisdesirable,forperformancereasons,tousethe

returnvalueoftheGetHashCodemethodtodeterminewhetherthe

datacontainedwithintwoobjectsisequal.CallingGetHashCodeto

returnahashvalueoftwoobjectsandcomparingtheirhash

valuescanbefasterthancallingthedefaultimplementationof

EqualsontheObjecttype,whichindividuallyteststheequalityof

allpertinentdatawithintwoobjects.Infact,somedevelopers

evenopttocomparehash-codevaluesreturnedfromGetHashCode

withintheiroverloadedEqualsmethod.Usingacustom

implementationoftheEqualsmethodinthisfashionisfaster

thanthedefaultimplementationoftheObject.Equalsmethod.



Thesimplehash



ThishashacceptsavariablenumberofintegervaluesandXORs

eachvaluetoobtainahashcode.Thissimplealgorithmhasa

goodchanceofproducinganadequatedistributionandgood

performance.Remembertoprofileandmeasureittoconfirm

thatitworksaswellforyourparticulardataset.Itfailswhen

youneedtointegratevaluesgreaterinsizethananinteger.Its

codeis:























publicintSimpleHash(paramsint[]values)

{

inthashCode=0;

if(values!=null)

{

foreach(intvalinvalues)

{

hashCode^=val;

}

}









return(hashCode);

}



Thefoldinghash

Thishashallowsyoutointegratethelongdatatypeintoahash

algorithm.Ittakestheupper32bitsofthelongvalueandfolds

themoverthelower32bitsofthisvalue.Theactualprocessof

foldingthetwovaluesisimplementedbyXORingthemand

usingtheresult.Onceagain,thisisagoodperforming

algorithmwithgooddistributionproperties,but,again,itfails

whenyouneedtogobeyondthelongdatatype.Asample

implementationis:





publicintFoldingHash(paramslong[]values)































{

inthashCode=0;

if(values!=null)

{

inttempLowerVal=0;

inttempUpperVal=0;

foreach(longvalinvalues)

{

tempLowerVal=(int)(val&0x000000007FFFFF

tempUpperVal=(int)((val>>32)&0xFFFFFF

hashCode^=tempLowerVal^tempUpperVal;

}

}









return(hashCode);

}



Thecontainedobjectcache

Thishashobtainsthehashcodesfromavariablenumberof

objecttypes.Theonlytypesthatshouldbepassedintothis

methodarereference-typefieldscontainedwithinyourobject.

ThismethodXORsallthevaluesreturnedbytheGetHashCode

methodofeachobject.Itssourcecodeis:





















publicintContainedObjHash(paramsobject[]values)

{

inthashCode=0;

if(values!=null)

{

foreach(objectvalinvalues)

{

hashCode^=val.GetHashCode();

}







}









return(hashCode);

}



TheCryptoHashmethod

Potentiallythebestmethodofobtainingahashvalueforan

objectistousethehashingclassesbuiltintotheFCL.The

CryptoHashmethodreturnsahashvalueforsomeinputusingthe

MACTripleDESclass.Thismethodreturnsaverygooddistribution

forthehashvalue,althoughyoumaypayforitinperformance.

Ifyoudonotrequireanear-perfecthashvalueandarelooking

foranexcellentdistribution,considerusingthisapproachto

calculateahashvalue:







privatereadonlybyte[]Key=newbyte[16]{1,122,3,11,

77,34,99,45



















publicintCryptoHash(stringstrValue)

{

inthashCode=0;

if(strValue!=null)

{

byte[]encodedUnHashedString=

Encoding.Unicode.GetBytes(strValue);















//Replacethefollowingkeywithyourown

//keyvalue.

MACTripleDEShashingObj=newMACTripleDES(Key)

byte[]code=

hashingObj.ComputeHash(encodedUnHashedS







//UsetheBitConverterclasstotakethe

















//first4bytes,foldthemoverthelast4byt

//andusethemasanintforthehashcode.

inthashCodeStart=BitConverter.ToInt32(code,

inthashCodeEnd=BitConverter.ToInt32(code,4)

hashCode=hashCodeStart^hashCodeEnd;

}









return(hashCode);

}



TheCryptoHashmethodusinganonstring

Thismethodshowshowother,nonstringdatatypescanbeused

withthebuilt-inhashingclassestoobtainahashcode.This

methodconvertsanumericvaluetoastringandthentoabyte

array.Thearrayisthenusedtocreatethehashvalueusingthe

SHA256Managedclass.Finally,thefirstfourvaluesinthebytearray

areconcatenatedtogethertoobtainahashcode.Thecodeis:







privatereadonlybyte[]Key=newbyte[16]{1,122,3,11,

77,34,99,45















publicintCryptoHash(longlongValue)

{

inthashCode=0;

byte[]encodedUnHashedString=

Encoding.Unicode.GetBytes(longValue.ToS









MACTripleDEShashingObj=newMACTripleDES(Key);

byte[]code=hashingObj.ComputeHash(encodedUnHashe











//UsetheBitConverterclasstotakethe

//first4bytes,foldthemoverthelast4bytes

//andusethemasanintforthehashcode.









inthashCodeStart=BitConverter.ToInt32(code,0);

inthashCodeEnd=BitConverter.ToInt32(code,4);







hashCode=hashCodeStart^hashCodeEnd;









return(hashCode);

}



Theshiftandaddhash

Thismethoduseseachcharacterintheinputstring,strValue,to

determineahashvalue.Thisalgorithmproducesagood

distributionofhashcodesevenwhenitisfedsimilarstrings.

However,itwillbreakdownwhenlongstringsthatendwiththe

samecharactersarepassed.Whilethismaynothappenmany

timeswithyourapplications,itissomethingtobeawareof.If

performanceiscritical,thisisanexcellentmethodtouse.Its

codeis:











publicintShiftAndAddHash(stringstrValue)

{

inthashCode=0;

longworkHashCode=0;

























if(strValue!=null)

{

for(intcounter=0;counter
{

workHashCode=(workHashCode<<(counter%

(int)strValue[counter];

}

workHashCode=workHashCode%(127);

}

hashCode=(int)workHashCode;









return(hashCode);

}



Thecalculatedhash

Thismethodisaratherwidelyacceptedmethodofcreatinga

goodhashvaluethatacceptsseveraldifferentdatatypesand

usesadifferentalgorithmtocomputethehashvalueforeach.

Itcalculatesthehashcodeasfollows:

ItassignsanarbitraryoddprimarynumbertotheHashCode

variable.Thisvariablewilleventuallycontainthefinalhash

code.Goodprimarynumberstouseare3,5,7,11,13,17,

19,23,29,31,37,41,43,47,53,59,61,or67.Obviously,

othersexistbeyondthisset,butthisshouldgiveyouagood

startingpoint.

Fornumerictypesequaltoorlessthanthesizeofanint

andchardatatypes,itmultipliesthecurrentHashCodebythe

primarynumberselectedandthenaddstothisvaluethe

valueofthenumerictypecasttoaninteger.

Fornumerictypesgreaterthanthesizeofanint,it

multipliesthecurrentHashCodebytheprimarynumber

selectedandthenaddstothisthefoldedversionofthis

numericvalue.(Formoreinformationonfolding,see"The

foldinghash"methodearlierinthisrecipe.)

Forchar,floating-point,ordecimaldatatypes,itmultiplies

thecurrentHashCodebytheprimarynumberselected,casts

thenumericvaluetoaninteger,andthenusesthefolding



methodtocalculateitsvalue.

Forbooldatatypes,itmultipliesthecurrentHashCodebythe

primarynumberselectedandthenaddsa1fortrueand0

forfalse(youcanreversethisbehaviorifyouwish).

Forobjectdatatypes,itmultipliesthecurrentHashCodebythe

primarynumberselectedandthenaddsthereturnvalueof

GetHashCodecalledonthisobject.Ifanobjectissettonull,

usethevalue0inyourcalculations.

Foranarrayorcollection,itdeterminesthecontained

type(s)anduseseachelementofthearrayorcollectionto

calculatethehashvalue,asfollows(inthecaseofan

integerarraynamedMyArray):



{



}



foreach(intelementinmyArray)

hashCode=(hashCode*31)+element;



Thisalgorithmwillproduceagooddistributedhashcodefor

yourobjectandhastheaddedbenefitofbeingabletoemploy

anydatatype.Thisisahigh-performingalgorithmforsimple,

moderatelycomplex,andevenmanycomplexobjects.However,

forextremelycomplexobjectsonesthatcontainmanylarge

arrays,largeHashtables,orotherobjectsthatuseaslowerhashcodealgorithmthisalgorithmwillstartperformingbadly.Inthis

extremecase,youmaywanttoconsiderswitchingtoanother

hash-codealgorithmtospeedperformanceorsimplyparing

downtheamountoffieldsusedinthecalculation.Becarefulif

youchoosethissecondmethodtoincreaseperformance;you

couldinadvertentlycausethealgorithmtoproducesimilar

valuesfordifferingobjects.Thecodeforthecalculatedhash



methodis:

























publicintCalcHash(shortsomeShort,intsomeInt,long

floatsomeFloat,objectsomeObject)

{

inthashCode=7;

hashCode=hashCode*31+(int)someShort;

hashCode=hashCode*31+someInt;

hashCode=hashCode*31+

(int)(someLong^(someLong>>3

longsomeFloatToLong=(long)someFloat;

hashCode=hashCode*31+

(int)(someFloatToLong^(someFloatToLong>















if(someObject!=null)

{

hashCode=hashCode*31+

someObject.GetHashCode();

}









return(hashCode);

}



Thestring-concatenationhash

Thistechniqueconvertsitsinputintoastringandthenuses

thatstring'sGetHashCodemethodtoautomaticallygenerateahash

codeforanobject.Itacceptsanintegerarray,butyoucan

substituteanytypethatcanbeconvertedintoastring.Youcan

alsouseseveraldifferenttypesofargumentsasinputtothis

method.Thismethoditeratesthrougheachintegerinthearray

passedasanargumenttothemethod.TheToStringmethodis

calledoneachvaluetoreturnastring.TheToStringmethodof

anintdatatypereturnsthevaluecontainedinthatint.Each



stringvalueisappendedtothestringvariableHashString.Finally,

theGetHashCodemethodiscalledontheHashStringvariableto

returnasuitablehashcode.

Thismethodissimpleandefficient,butitdoesnotworkwell

withobjectsthathavenotoverriddentheToStringmethodto

returnsomethingotherthantheirdatatype.Itmaybebestto

simplycalltheGetHashCodemethodoneachoftheseobjects

individually.Youshoulduseyourownjudgmentandtherules

foundinthisrecipetomakeyourdecision.











publicintConcatStringGetHashCode(int[]someIntArray)

{

inthashCode=0;

StringBuilderhashString=newStringBuilder();





















if(someIntArray!=null)

{

foreach(intiinsomeIntArray)

{

hashString.Append(i.ToString()+"^");

}

}

hashCode=hashString.GetHashCode();









return(hashCode);

}



Thefollowingusingdirectivesmustbeaddedtoanyfile

containingthiscode:









usingSystem;

usingSystem.Text;

usingSystem.Security.Cryptography;



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 11.  Data Structures and Algorithms

Tải bản đầy đủ ngay(0 tr)

×