Ez már a második. És látszólag nem is fejlődött semmit. Persze ez nem igaz, mert a forráskód 3-szor akkora, mint az előző számban. Meg még az exe mérete is nőtt. Ezek a feltűnő változások A nem feltűnőek: van indexfile, ami azt jelenti, hogy az adatbázis könnyebben rendezhető. Esetünkben mindig rendezett. Rendezett adatbázisban pedig sokkal gyorsabb, és sokkal másabb (nyelvtan rulez) a keresés. Az az egy byte kihasználatlan adat a rekordban értelmet kap, amire a múltkor azt mondtuk, hogy reserved. Ezzel vannak megjelölve a törölt rekordok. Tehát a rekordokat fizikailag nem töröljük, csak logikailag, ebből következik, hogy tudunk undeletelni is. Nem sok, nem látványos, de annál bonyolultabb.

Szóval az indexelt adatkezelés. Arra való, hogy az adatokat ne kelljen minden egyes rendezésnél valójában fizikailag is rendezni (cuccos lenne) , hanem csak logikailag. Meg kell jegyeznünk, hogy melyik helyhez hányadik elemet rendeljük.

Nem egy világbajnok ábra, de a célnak megfelel. Az indexfile az a hely, ahol az elemek sorrendje eltárolódik Az indexfile első eleme a logikailag első elemet határozza meg, a második a másodikat, és így tovább. Tehát esetünkben az elemek sorrendje: Rekord5,Rekord1,Rekord2,Rekord4,Rekord3

Ez lenne.

Érdekes dolog egy ilyen rendezett adatbázisban a keresés. Mert ugye mit csináltunk eddig? Ha kerestünk egy rekordot, az adatbázis minden egyes rekordját össze kellett hasonlítani a mintával, amíg meg nem találtuk. A helyzet most egészen más, hiszen támaszkodhatunk az adatok rendezett mivoltára.

Ha keresünk egy elemet, kapásból megnézhetjük, hogy elvileg benne lehet-e az adatbázisban. Összehasonlítjuk a legelsővel, ha ennél kisebb, akkor tutira nincs benne. Hiszen mivel rendezettek az adatok, biztos, hogy az elsőnél nincs kisebb. Ugyanez a játék az utolsó elemmel. Ha annál nagyobb, akkor hót zicher (remélem jól írtam) hogy nem lehet benne. Ha viszont a kettő között van, akkor elvileg benne lehet. (egyáltalán nem biztos, hogy benne is van) Ilyenkor keresnünk kell. Ezt egy intervallumfelezéses technikával a legkönnyebb megoldani. Hogy ez mi takar, arra egy bugyuta példával szeretnék fényt deríteni. Valaki kitalál egy számot 0-100-ig, és ezt ki kell találni. Hogy a leggyorsabb:

 

nagyobb mint 50? Igen (50=(0+100)/2)
nagyobb mint 75? nem (75=(50+100)/2)
nagyobb mint 64? Igen (64=(75+50)/2)
nagyobb mint 68? Igen (68=(64+75)/2)

és így tovább.

 

Addig szűkítjük az intervallumot, amíg az intervallum egyetlenegy szám nem lesz. Ha szerencsénk van, akkor pedig már útközben is beletrafálhattunk. Kiszámolható, hogy mindenképpen kevesebb, mint 7 rákérdezésből meg leghet találni egy 0 és 100 közötti számot. (hiszen 100 kisebb mint 2 a hetediken) Egy 1024-es számhalmazból pedig legfeljebb 10 hasonlítással. Minél nagyobb a halmaz, annál nagyobb a különbség az eddigi módszerünk, és ez között.Ugyanígy megy ez rekordokkal is. Csak egy dologra kell figyelni. A kezdő intervallum legyen legalább 3 elemű. Nézzük a függvényt:

 

 

int search(char *nev,int *poz) //kereses rendezett adatbazisban { int i=0,h,hl,ll,found=0; long oldpos; DATTYPE rek; if (!records) {*poz=0;return(0);} //ha nincs meg elem oldpos=ftell(datfile); //intervallum vegpontjai ll=0; hl=records-1; //benn van e az intervallumban: fseek(datfile,(long) ndx[ll]*sizeof(DATTYPE),SEEK_SET); fread(&rek,sizeof(DATTYPE),1,datfile); if (strcmp(nev,rek.nev)==0) {*poz=0;fseek(datfile,oldpos,SEEK_SET);return(1);} if (strcmp(nev,rek.nev)<0) {*poz=0;fseek(datfile,oldpos,SEEK_SET);return(0);} if (strcmp(nev,rek.nev)>0) { fseek(datfile,(long) ndx[hl]*sizeof(DATTYPE),SEEK_SET); fread(&rek,sizeof(DATTYPE),1,datfile); if (strcmp(nev,rek.nev)>0) {*poz=records;fseek(datfile,oldpos,SEEK_SET);return(0);} if (strcmp(nev,rek.nev)==0) {*poz=records-1;fseek(datfile,oldpos,SEEK_SET);return(1);} if (strcmp(nev,rek.nev)<0 && records==2) {*poz=1;fseek(datfile,oldpos,SEEK_SET);return(0);} } //tutira benn van az intervallumban, ami legalabb 3 elemu while(ll!=hl-1 && !found) { i=(ll+hl)/2; fseek(datfile,(long) ndx[i]*sizeof(DATTYPE),SEEK_SET); fread(&rek,sizeof(DATTYPE),1,datfile); h=strcmp(nev,rek.nev); if (h<0) hl=i; if (h>0) ll=i; if (h==0) found=1; } if (!found && h>0) i++; *poz=i; fseek(datfile,oldpos,SEEK_SET); return(found); }

Az ndx tömb valójában az indexfile. Persze az indexelésnek csak akkor van értelme, ha az indexfile-t bennt tudjuk tartani a memóriában. A datfile, pedig az adatbázisunk. A függvény 2 paramétert vesz át. Az egyik a rekord nev mezője. Az adatok név szerint vannak rendezve. A másik paraméter az a memóriacím, ahova a megtalalált elem indexét beteszi. Ha nem talált pontosan olyan elemet, ami kellett volna, akkor az legközelebbi elemet teszi be, ami még éppen nagyobb. A függvény visszatérési értéke, az, hogy megtalálta-e a keresett elemet. Ennyit a keresésről.Ugye mindenkinek feltűnt, hogy a stringeket a cmpstr() függvénnyel hasonlítja össze, ami azt jelenti, hogy az ASCII kódok szerint rendez. Tehát se magyar karakterek, se kisbetü-nagybetü. Kell írni egy normális összehasonlító függvényt.

Ez eddig szép, de egy ilyen adatbázist valahogy létre is kell tudni hozni. Ha beteszünk egy elemet, akkor az indexeket át kell rendezni úgy, hogy továbbra is minden rendezett maradjon. Meg kell keresni azt a helyet ahova be kell szúrni a rekordot, az innen magasabb indexeket eggyel feljebb léptetni, és beírni az üresen maradt helyre az új rekord fizikai helyét. A beszúrási helyet könnyen meg lehet találni, csak végig kell futtatni egy keresést. Igy meg fogjuk kapni azt az elemet ami a legjobban hasonlít rá, de még nagyobb. Ennek a helyére kell benyomulni, miután feljebbraktuk. Függvény:

 

int insertndx(int recordnum, DATTYPE rekord) { int poz,i=0; if (search(rekord.nev,&poz)) return(0); //mar van ilyen elem for(i=records;i>poz;i--) ndx[i]=ndx[i-1]; //arreb pakoljuk az indexeket ndx[poz]=recordnum; //benyomjuk az ujat return(1); }

A függvény 2 paramétert kér. Az egyik a rekord fizikai helye, a másik a rekord adatai. A rekord adatai alapján megkeresi a helyét, majd végrehajtja az átmozgatósdit.

Ennek megfelelően az uj szám bevitele:

void uj() { DATTYPE rek; fseek(datfile,0,SEEK_END); do { clrscr(); printf("Kerem az adatokat\n\n"); printf("Nev : "); fflush(stdin); gets(rek.nev); printf("Telefonszam : "); fflush(stdin); gets(rek.szam); printf("Lakcim : "); fflush(stdin); gets(rek.cim); rek.reserved=0; fseek(datfile,0,SEEK_END); if (insertndx(ftell(datfile)/sizeof(DATTYPE),rek)) { fwrite(&rek, sizeof(DATTYPE), 1, datfile); records++; } else printf("Ilyen nev mar van \n"); printf("\n\nVan meg adat? (i/n) "); } while(tolower(getch())!='n'); } // uj
Ez lenne a lényeg.
Aztán még a törlés:
void torol(void) { DATTYPE rek; int pos; char string[30]; clrscr(); printf("Kerem a nevet! "); fflush(stdin); gets(string); if (!search(string,&pos)) printf("Ilyen nevet nem talaltam\n"); else { fseek(datfile,(long) ndx[pos]*sizeof(DATTYPE),SEEK_SET); fread(&rek,sizeof(DATTYPE),1,datfile); rek.reserved=1; fseek(datfile,(long) ndx[pos]*sizeof(DATTYPE),SEEK_SET); fwrite(&rek,sizeof(DATTYPE),1,datfile); deletendx(pos); records--; printf("Torolve..."); } bill(); }

A függvény nem csinál mást, mint a törölt rekord reserved mezőjét 1-re állítja, és törli az indexek közül. Ennek hatására logikailag már nem szerepel a sorrendben, tehát az adatbázisban. A rekord az összes adatával sértetlenül ott marad a helyén. Ez teszi lehetővé, hogy a törlést lehessen érvényteleníteni:

 

void undelete() { DATTYPE rek; int p,pos,found=0; char string[30];clrscr(); printf("Kerem a nevet! "); fflush(stdin); gets(string); fseek(datfile,0,SEEK_SET); while (!feof(datfile) && !found) { if (fread(&rek,sizeof(DATTYPE),1,datfile) && rek.reserved==1 && strcmp(rek.nev,string)==0) { found=1; printf("A torolt adatot megtalaltam.\n"); if (search(string,&pos)) printf("Nem lehet visszaallitani, mar letezik aznos nevu.\n"); else { fseek(datfile,SEEK_CUR,-sizeof(DATTYPE)); rek.reserved=0; insertndx(ftell(datfile)/sizeof(DATTYPE),rek); records++; fwrite(&rek,sizeof(DATTYPE),1,datfile); printf("Visszaallitva\n"); } } } if (!found) printf("Nem talaltam."); bill(); }

Nem tesz mást, mint visszarakja az indexek közé, és a reserved mezőt 0-ra állítja.
Ennek megfelelően persze a módosítást is át kell írni.

Röviden ennyi.