28. juli 2005 - 13:53
Der er
18 kommentarer og 1 løsning
Binarysearch i filer med strenge
Hej Jeg har lavet en lille binarysearch der søger i en fil efter et tal og returnerer postnummeret. Filen er sorteret korrekt, og jeg kører med fastfeltformat. Min lille funktion virker også fint, men kun til tal. Nu vil jeg gerne have den til at fungere med strenge, og altså bogstaver. Hvordan gør jeg det? jeg kunne også godt tænke mig kommentarere til min kode. public int FileBinarySearch(string sFilename, long iRecordsize, int iStart, int iLength, int iSearchFor) { FileInfo fi = new FileInfo(sFilename); FileStream fs = new FileStream(sFilename, FileMode.Open); BinaryReader br = new BinaryReader(fs); int iPosts = (int)(fi.Length/iRecordsize); int iCurrentPost = (iPosts/2); int iIndex = -1; int iMin=0,iMax=iPosts; if(iCurrentPost%2!=0) iCurrentPost-=1; int tmp=0; while(iIndex<0) { tmp=0; fs.Seek((iCurrentPost*iRecordsize)-iRecordsize+iStart,SeekOrigin.Begin); char[] ch = br.ReadChars(iLength); int iFoundInt = atoi(ch); if(iFoundInt==iSearchFor) iIndex = iCurrentPost; else if(iFoundInt > iSearchFor) { iMax = iCurrentPost; tmp = iMax - (iMax - iMin)/2; if(iCurrentPost==tmp) iCurrentPost--; else iCurrentPost=tmp; if(iMin+1 == iMax) break; } else { iMin = iCurrentPost; tmp = iMin + (iMax - iMin)/2; if(tmp==iCurrentPost) iCurrentPost++; else iCurrentPost = tmp; if(iMin+1 == iMax) break; } if(iCurrentPost > iPosts || iCurrentPost < 1 ) break; } br.Close(); fs.Close(); return iIndex; }
Annonceindlæg fra Thales
mindst kode: konverter fra byte[] (eller char[] som det ser ud som om du bruger) til String og sammenlign på dem hurtigst kode: lav noget som kan sammenligne byte arrays
jeg tror iøvrigt at koden kan pyntes lidt (men jeg vil først kunne komme med et forslag i aften)
Hvordan kan jeg sammenligne strenge, og finde ud af om det jeg søger ligger før eller efter min nuværende position? Kan du give et eks. på hurtigst kode? Det er også vær at bemærke at min fil indeholder en masse 0x00 som fyldstof til felterne så de får den rigtige længde på feltet. Så felternes data er som et chararray med /0.
Slettet bruger
28. juli 2005 - 21:24
#4
Det er lige nøjagtig det her jeg også mangler, glæder mig til arnes eks! :o)
Jeg er først lige startet nu. :-)
Super, jeg glæder mig til resultatet. Kan ikke rigtigt få det til at fungere selv.
Her er et eksempel med string compareordinal: using System; using System.IO; using System.Text; class TestClass { private const string FILE_NAME = @"C:\bin.dat"; public static void CreateTestFile() { BinaryWriter bw = new BinaryWriter(new FileStream(FILE_NAME, FileMode.Create, FileAccess.Write)); bw.Write(Encoding.Default.GetBytes("AAAA")); bw.Write(1); bw.Write(Encoding.Default.GetBytes("BBBB")); bw.Write(2); bw.Write(Encoding.Default.GetBytes("CCCC")); bw.Write(3); bw.Write(Encoding.Default.GetBytes("DDDD")); bw.Write(4); bw.Write(Encoding.Default.GetBytes("EEEE")); bw.Write(5); bw.Close(); } public static int Find2(string s) { int reclen = 8; int nrec = (int)((new FileInfo(FILE_NAME)).Length / reclen); BinaryReader br = new BinaryReader(new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read)); int first = 0; int last = nrec - 1; while(first <= last) { int mid = (first + last) / 2; br.BaseStream.Position = mid * reclen; string fs = Encoding.Default.GetString(br.ReadBytes(4)); int fi = br.ReadInt32(); if(String.CompareOrdinal(fs,s) == 0) { return fi; } else if(String.CompareOrdinal(fs,s) < 0) { first = mid + 1; } else { last = mid - 1; } } br.Close(); return -1; } public static void Main(string[] args) { CreateTestFile(); Console.WriteLine(Find2("AAAA")); Console.WriteLine(Find2("BBBB")); Console.WriteLine(Find2("CCCC")); Console.WriteLine(Find2("DDDD")); Console.WriteLine(Find2("EEEE")); Console.WriteLine(Find2("XXXX")); } }
fil formatet er: 4 byte med bogstaver 4 byte med en integer
Og med noget byte compare: using System; using System.IO; using System.Text; class TestClass { private const string FILE_NAME = @"C:\bin.dat"; public static void CreateTestFile() { BinaryWriter bw = new BinaryWriter(new FileStream(FILE_NAME, FileMode.Create, FileAccess.Write)); bw.Write(Encoding.Default.GetBytes("AAAA")); bw.Write(1); bw.Write(Encoding.Default.GetBytes("BBBB")); bw.Write(2); bw.Write(Encoding.Default.GetBytes("CCCC")); bw.Write(3); bw.Write(Encoding.Default.GetBytes("DDDD")); bw.Write(4); bw.Write(Encoding.Default.GetBytes("EEEE")); bw.Write(5); bw.Close(); } private static int BCompare(byte[] b1, byte[] b2, int n) { for(int i = 0; i < n; i++) { if(b1[i] < b2[i]) { return -1; } else if(b1[i] > b2[i]) { return 1; } } return 0; } public static int Find2(string s) { byte[] b = Encoding.Default.GetBytes(s); int reclen = 8; int nrec = (int)((new FileInfo(FILE_NAME)).Length / reclen); BinaryReader br = new BinaryReader(new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read)); int first = 0; int last = nrec - 1; while(first <= last) { int mid = (first + last) / 2; br.BaseStream.Position = mid * reclen; byte[] fb = br.ReadBytes(4); int fi = br.ReadInt32(); if(BCompare(fb,b,4) == 0) { return fi; } else if(BCompare(fb,b,4) < 0) { first = mid + 1; } else { last = mid - 1; } } br.Close(); return -1; } public static void Main(string[] args) { CreateTestFile(); Console.WriteLine(Find2("AAAA")); Console.WriteLine(Find2("BBBB")); Console.WriteLine(Find2("CCCC")); Console.WriteLine(Find2("DDDD")); Console.WriteLine(Find2("EEEE")); Console.WriteLine(Find2("XXXX")); } }
28. juli 2005 - 22:29
#10
Jeg ved dog ikke om den byte compare reelt er så meget hurtigere end string compare, men ...
28. juli 2005 - 22:36
#11
Det ser rigtigt godt ud. Tak Arne. Der var lige en god string compare funktion, som jeg ikke kendte, den vil jeg kunne bruge. Jeg prøver at teste de to forskellige metoder, og se hvad der er hurtigst. Super tak for hjælpen, jeg vender tilbage i morgen.
28. juli 2005 - 22:51
#12
Den normale Compare metode har detmed at ville være hjælpsom og AA svarer så til Å etc.
28. juli 2005 - 22:59
#13
Ja det kan selvfølgelig godt skabe problemer - men til mit brug tror jeg ikke at det giver problemer.
28. juli 2005 - 23:01
#14
Fint nok men da jeg valgte "AAAA" som test string så var jeg ligesom nødt til at vælge CompareOrdinal.
28. juli 2005 - 23:06
#15
Ooooh - nu forstår jeg hvad du siger. Det er meget rart at man kan vælge om den skal være hjælpsom eller ej.
29. juli 2005 - 09:51
#16
Hej Arne Jeg har kun fået testet string compare. Den fungerer fint bortset fra at den sorterer 10 før 9, kan man lave om på det?
29. juli 2005 - 11:12
#17
10 er jo før 9 - alfabetisk hvis du sammenligner int.Parse(s1) med int.Parse(s2) må du få en numerisk sammenligning
01. august 2005 - 09:22
#18
Tak for hjælpen. Jeg fik den sorteret anderledes, så det var ikke noget problem. Men stringcompare virker ellers fint. Har desværre ikke fået testet bytecompare. Vil du smide et svar ?
01. august 2005 - 09:28
#19
kommer her
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.