# Shkenca > Informatikë dhe Internet > Arti i programimit >  C - Strukturat e të dhënave (Matricat, Listat, Pemët)

## demolition man

Pershendetje cuna !
Kam nje  problem me nje ushtrim dhe kerkoj ndihmen tuaj   Me pak fjale :

duhet qe te shkruaj disa record ne nje file
cdo record  ka dy kampe  (nje string   dhe nje int) 
...
*struct record {
char  personi [20];
int  num;
};

struct record r;
struct record  *rPtr;
rPtr= &r;
int dim=sizeof(r);

strcopy(r.personi, "Naim Frasheri ");
r.num =17;

int  fd;
fd = fopen("file.txt",O_WRONLY) ;

write (fd ,rPtr ,dim);
close (fd);*
Duke  ekzekutuar  kete kod  arrij te   shkruaj ne FILE  kampin e pare pra STRINGEN  "Naim Frasheri"
ndersa  kampin dyte (pra numrin ) qe eshte  INT  nuk  e shkruaj dot ne FILE   . Ne vend te   17 gjej te shkrojtura  karaktere  te tjere 

Kush mund te me thote se ku qedron gabimi  dhe si mund  ta  korrigjoj

*Dhe nje  ushtrim tjeter  :*Duhet  qe nderkohe  qe  shtoj  rekorde  te rinj ne FILE  , gjithe rekordet duhen te jene  te renditur  sipas 
kampit  te  pare (String) sipas rendit alfabetik

Ju falenderoj per  pergjigjet e mundshme .

----------


## cunimartum

rPtr->num = 17
(*rPtr).num  = 17   \\  " . " me shume precedense se *

Duket sikur po ndryshon adresen jo permbajtjen prandaj dhe shef junk.

----------


## edspace

Më duket se problemi qëndron tek funksioni write() që printon char dhe jo ints. Numrin 17 mundohet ta interpretojë si një karakter të ASCII dhe prandaj nxjerr shkronja të panjohura. 

Ky kod punon:


```

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct record 
{
    char personi [20];
    int num;
};

int main (void)
{
    struct record r;
    struct record *rPtr = &r;
   
    strcpy(r.personi, "Naim Frasheri ");
    r.num =17;
    
    FILE * fd;
    fd = fopen("file.txt","w") ;  //ndryshoje "w" në O_WRONLY për linux
    
    fprintf( fd, "%s%d", rPtr->personi, rPtr->num);
    close (fd);
} 



```

----------


## demolition man

Faleminderit cuna per  pergjigjet

Po persa i perket pjeses se dyte  , dmth   renditjen e rekordeve ne file sipas kampit STRING  (dmth siaps alfabetit)   keni  ndonje  ide ??

Gjith te mirat !

----------


## qoska

nje pyetje kisha do gjithmone qe ta kesh file ne text dmth te lexueshem edhe nga editore te tjere ???

----------


## werewolf

Pse nuk i mban te renditura ne nje linked list rekordet, dhe ne fund ti shkruash ne file? eshte menyra me e thjeshte( dhe e vetmja qe me vjen ne mendje per momentin)!!!


qoska, nese eshte i hapur ne write nga nje proces, sbesoj se hapet nga 1 file tjeter...

----------


## edspace

Shiko programin më poshtë. 
- Lexon një skedar me dy kollona të ndara me tab '\t'.
- I hedh rekordet në një matricë (array)
- Rendit matricën sipas alfabetit
- Shkruan përsëri skedarin me rekordet të renditur sipas alfabetit

Leximi i rekordeve mbaron kur gjen rreshtin e parë bosh, ose kur arrin fundin e skedarit. 

Maksimumi i rekordeve është 30 por mund ta ndryshosh sipas dëshirës duke ndryshuar variablën REK_MAX. 

Kam komentuar gjithçka por mos nguro të pyesësh. 
Skedari i bashkëngjitur ZIP ka kodin main.c dhe databaza.txt.

Unë e shkruajta në windows por duhet të punojë edhe në linux. 
E përpilova me Dev C++

Ja një shëmbull i skedarit para se të përdoret programi:



```
Pashko Vasa	354
Gjergj Fishta	614
Ndre Mjeda	459
Andon Zako Çajupi	130
Naim Frashëri	755
Jeronim De Rada	223
```


Kodi i programit në C:



```

// Autori: Edi, edspace ET comcast PIKE net
// Pershkrimi: 
//     Lexon dhe shkruan rekorde ne nje skedar sipas renditjes alfabetike
//     Rekordi permban 2 kollona te ndara me tab 
//
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

const REK_MAX = 30;  // numri maksimal per rekordet

struct rekord // struktura e nje rekordi
{ 
    char personi [20];  // emri i personit deri ne 20 shkronja
    int num;            // numri
}; 

//********************************************************************
// Hap skedarin db dhe hidh rekordet ne matricen r
// Kthen numrin e rekordeve ne skedar ose -1 nqs nuk hapet skedari
//
int lexo_databaze( const char db [], struct rekord * r);

//********************************************************************
// Hap skedarin db dhe shkruar nr rekorde nga matrica r
// Kthen 0 nqs ndodh gabim
//
int shkruaj_databaze(const char db [], const struct rekord * r, const size_t nr);

//********************************************************************
// Krahaso dy rekorde duke u bazuar mbi personin. 
// Ky funksion perdoret per renditjen e rekordeve
// emrat 0 konsiderohen si te pavlefshem dhe renditen ne fund 
// Kthejme: -1 nqs r1<r2, 0 nqs r1=r2,  1 nqs r1>r1
// A < Z < 0
//
int rekord_krah ( const struct rekord * r1, const struct rekord * r2);


//********************************************************************
// MAIN
//
int main (void) 
{ 
   const char db [] = "databaza.txt"; // emri i skedarit ku do ruhet info
    
   // tregues per array me rekorde
   struct rekord * r = NULL;
   
   // kerkojme memorjen per REK_MAX rekorde
   r = calloc( REK_MAX, sizeof(struct rekord) );
   
   if( r == NULL )  // nqs nuk ka memorje te mjaftueshme
   {
       printf("GABIM: Nuk ka memorje te mjaftueshme");   
       return 1;
   }       
   
   int nr_rekordeve = lexo_databaze( db, r );
   
   if ( nr_rekordeve == -1 )
   {
       printf("GABIM: Nuk mund te hapej skedari %s", db);
   }
   
   qsort (r, REK_MAX, sizeof (struct rekord), (const void *)rekord_krah);  
    
   // ketu mund te ndryshosh matricen duke shtuar rekorde te tjera

   if( !shkruaj_databaze( db, r, nr_rekordeve ) )
   {
       printf("GABIM: Nuk mund te hapej skedari %s", db);
       return 1;
   }    
   
   return 0;   // mbaruam
} 

//************************************************************************
// Lexojme rekordet nga databaza
//
int lexo_databaze( const char db [], struct rekord * r)
{
   FILE * inskedari; // tregues per skedarin

   if(!(inskedari = fopen(db, "r"))) 
   {
       return -1; // nqs nuk hapim dot skedarin kthejme kodin -1 (gabim)
   }    
    
   int i = 0;
   char rresht [100];  // buffer per 1 rresht (maksimumi 100 shkronja)
  
   while(i < REK_MAX )   // marrim REK_MAX rekorde nga skedari
   {
       fgets( rresht, 100, inskedari);   // marrim rreshtin

       // nqs eshte rreshti i fundit, dalim jashte
       if( feof(inskedari) || strlen(rresht) == 1) break;  
       
       // marrim emrin e personit qe ndahet me tab nga numri
       strncpy( r[i].personi, strtok (rresht,"\t"), 20 ); 
       r[i].num = atoi( strtok (NULL," \n") );    // marrim numrin        
       i++;
   }

   fclose(inskedari);   // mbyllim skedarin
   
   return i;       // numri i rekordeve qe gjetem ne skedar
}   

//************************************************************************
// Shkruajme rekordet ne databaze
//
int shkruaj_databaze( const char db [], const struct rekord * r, size_t nr )
{
   FILE * outskedari; // tregues per skedarin
  
   // nqs nuk hapim dot skedarin per te shkruar
   if(!(outskedari = fopen(db, "w+"))) // 
   {
       return 0; // nqs nuk hapim dot skedarin kthejme kodin 0 (gabim)
   }    
   
   int i;
   
   for (i = 0; i < nr; i++)  // shkruajme rekordet
   {    // emri dhe numri jane te ndara me tab
       fprintf (outskedari, "%s\t%d\n", r[i].personi, r[i].num);
   }    
  
   fclose (outskedari);  // mbyllim skedarin
   
   return 1;
}

//************************************************************************
// Krahasojme rekordet e databazes
//  
int rekord_krah (const struct rekord * r1, const struct rekord * r2)
{
    if( strcmp("\0", r1->personi) == 0 ) return 1;    // zeron e vendosim ne fund
    if( strcmp("\0", r2->personi) == 0 ) return -1;   // zeron e vendosim ne fund
    return strcmp (r1->personi, r2->personi);        // krahasojme dy fjale
} 



```


Skedari pas ekzekutimit të programit:



```
Andon Zako Çajupi	130
Gjergj Fishta	614
Jeronim De Rada	223
Naim Frashëri	755
Ndre Mjeda	459
Pashko Vasa	354
```

----------


## gjigandi

nuk e ka te percaktuar numrin e rekordeve qe do shkruaj ne file, prandaj smund te perdori matrice!

----------


## edspace

Gjithnjë ka një kufizim sepse kompjuteri nuk ka memorje pa kufi. Çfarëdo strukture të përdorë për ruajtjen e informacionit, qoftë kjo me matrica, vektorë, hash, kapica, lista zinxhir, etj, gjithnjë do ketë një limit. 

30 që kam vënë unë mund të ndryshohet në 3000, ose 30,000 për aq kohë sa sistemi ka memorje të mjaftueshme. Ky numër është për numrin maksimal të rekordeve, por programi lexon dhe shkruan vetëm rekordet që kanë informacion dhe jo ato që janë bosh. 

Nqs skedari ka vetëm 6 rekorde si në shëmbullin më lart, atëherë 24 rekordet e tjera janë bosh dhe programi nuk i shkruan. 

Zgjidhja tjetër për të kursyer memorje (jo për të hequr kufizimet) është me matrica dinamike por ka komplikime të tjera. 

Ndryshoje kodin tim që të punojë më mirë ose sill ndonjë zgjidhjen tënde.

----------


## edspace

Sapo provova programin me një skedar me 400.000 (4-qind mijë) rekorde të tipit:



```
asdfasdf1	800
asdfasdf2	801
asdfasdf3	802
asdfasdf4	803
...	...
```

E krijova në excel që ka limit 65.000 rekorde dhe pastaj e hapa me një editor tjetër dhe bëra copy-paste disa herë deri sa u bë një skedar rreth 7MB me 400.000 rekorde. Rekordet i rendita me fuksionin rand() te excelit. 

Programi më lart i lexoi, i renditi dhe i shkruajti prapë në skedar brënda 30 sekondave. 

Kompjuteri është 2.6GHz dhe ka 256MB memorje (windows XP). 

Jo keq apo jo?

Po ke kohë të lirë, provoje me 500.000+ deri sa të gjesh limitet e kompjuterit tënd.

----------


## zeus

-------------------------------------------------------

Mendoj se Gjigandi ka te drejte! Perdorimi i nje matrice eshte i papershtatshem.

Per te renditur permbajtjen ne nje file mund te perdoret edhe nje liste e renditur siç thote nje koleg me lart po perseri me duket e papershtatshme sepse mendoj se qellimi nuk eshte qe ky shoku jone thjesht te mbaroje detyren, po te mesoje te punoje me nje file. Une ne fakt C nuk mbaj mend shume tani se e kam bere para 6 vjeteve po per ta mbajtur kete file gjithnje te renditur: cdo rekord i ri duhet krahasuar me ato ekzistueset dhe duhet pozicionuar ne vendin qe i takon sipas rendit rrites ose zbrites. Nuk e di nese kjo mund te behet me nje file ashtu siç behet psh me nje liste. Nese nuk mund te realizohet me nje file te vetem mund te perdoren file ndihmes.

-------------------------------------------------------

----------


## edspace

Cila është arsyeja që të duket i papërshtatshëm përdorimi i matricave? Gjigandi zuri në gojë përcaktimin e madhësisë dhe ajo është disi me vënd por nga provat që bëra, programi është shumë i shpejtë edhe për 1.000.000+ rekorde, prandaj kufizimi i matricës nuk është problem.

Sugjerimi që jep ti me përdorimin e skedarëve nuk është praktik sepse për çdo rresht që do shtohet, ti duhet ta krahasosh me rreshtat e tjerë dhe këtë do ta bësh duke lexuar skedarin. Leximi i hard diskut është shumë herë më i ngadaltë se leximi i memorjes dhe programi do ishte tepër i ngadaltë. Prandaj mënyra që kam ndjekur, lexon dhe shkruan në disk vetëm njëherë. Krahasimi dhe renditja bëhet në memorje që është shumë e shpejtë. 

Duke përdorur listat zinxhir i vetmi përmirësim do ishte se programi do zinte më pak memorje. Në anën tjetër, nqs do bëje krahasimin në skedar ose me lista zinxhir, do duhej të shkruaje një funksion më vete për renditjen dhe kjo nuk është gjë e lehtë. Unë përdora funksionin qsort që është standart i C dhe është shkruajtur nga ekspertët. 

Përdorimi i matricave të lejon përdorimin e treguesve [i] dhe kjo është shumë e rëndësishme kur punon me rekorde që lexohen ose ndryshohen shpesh. (psh: katalogu i librarisë, llogaritë e bankave, faturat e shitjes, etj).

Një zgjidhje pak më e mirë do ishin matricat dinamike, por edhe këto kanë problemet e tyre.

----------


## zeus

-------------------------------------------------------------

Besoj se detyra eshte e qarte: sa here shtoj 1 rekord duhet te pozicionohet ne vendin e duhur. Mos bej sikur nuk kupton kush eshte problemi i matricave! Nqs une deklaroj nje matricë me 20 elementë dhe te nesermen ne mengjes dua te shtoj elementin e 21 duhet te ndryshoj 1 rresht te programit (ne mos me shume) dhe kete duhet ta bej sa here kam nevoje per me shume rekorde. Pastaj nuk me duket e arsyeshme kur duhet te shtoj nje element ne nje bashkesi (qoftë kjo matrice, file apo list) elementesh te renditur te aplikoj quicksort çdo herë! Nejse ai ka mendjen e tij e le te beje si te doje...

P.S. Eshte thjesht nje debat konstruktiv (shpresoj) pa tone polemike!   :shkelje syri: 

-------------------------------------------------------------

----------


## IlirDeda

Mua me duket se perdorimi i vektoreve eshte mjaft i pershatshem per problemin ne fjale. Sic thote edhe Edi nje permiresim mund te ishte perdorimi i vektoreve dinamike. Nje permiresim tjeter mund te ishte nese dihet se sa rreshta ka skedari. Ne kete rastin e fundit mund te rezervohet aq memorie sa duhet dhe jo me teper. Kjo praktike eshte shume e perhapur. P.sh. cdo format fotosh qe njoh une (p.sh. BMP) ne fillim te skedarit ka te dhena per foton (sa pixel jane, sa ngjyra jane etj.).

Sic e tha edhe Edi, renditja e nje skedari in-place (pa e ngarkuar te teren ne memorie) ka problemin qe eshte shume e ngadalshme. Por sigurisht qe nese nuk ke memorie te mjaftueshme ne disk do e besh (keshtu vepronin databazat dikur).
Nje verejtje qe do beja ne lidhje me kete rast eshte qe skedari duhet te jete binar. Eshte teper e veshtire te renditesh nje skedar tekst si ai qe perdori Edi in-place.

Nga ana tjeter nuk mendoj se eshte e sugjerueshme perdorimi i listave ne kete rast. Renditja e listave kerkon te shkruash funksione speciale dhe eshte e sigurte qe do jete shume me e ngadalshme se renditja e vektoreve.

Nje strukture qe mund te perdoret ketu dhe qe shumekujt i kujton listat (por nuk eshte liste) eshte pema (tree). Pema eshte nje strukture ku elementet renditen gjate futjes. Futja e nje elementi ne peme kushton log time ndersa ne nje vektor kushton constant time. Por renditja e nje vektori kushton n*log(n) time kurse renditja e nje peme nuk kushton asgje sepse pema eshte e renditur.

Do ishte interesante qe ndokush te bente eksperimente me vektore dhe peme dhe te krahasonte shpejtesine e programeve. Une besoj se vektori duhet te jete me i shpejte por edhe shpejtesia e pemes duhet te jete e pranueshme.

----------


## edspace

Gjeta kohën e lirë për të rindërtuar programin më lart me strukturën e pemës që ka përmëndur edhe Iliri. U mundova të shkruaja kod sa më të shpejtë në mënyrë që të barazohej sa më mirë me kodin e shkruajtur për matricën dhe të mund të bëheshin krahasime domethënëse për të dyja strukturat. 
Jepni mendimet tuaja për ndryshimet në kod nqs shikoni mundësi për përmirësime. 

Sipas eksperimenteve që bëra, Matrica ngelet metoda më e mirë për këtë program por edhe Pema nuk është larg. Që të dyja strukturat kanë vështirësi me renditjen e rekordeve; matrica me funksionin qsort, ndërsa pema me funksionin hedh_ne_peme. Nxjerrja e rekordeve nga pema është më e ngadaltë, dhe po ashtu edhe lirimi i memorjes. Funksioni për të shtuar një nyje të re në pemë është shkruajtur në menyrën përsëritëse (me while) sepse metoda rekursive ishte shumë e ngadaltë. Nxjerrja nga pema dhe lirimi i memorjes bëhet në mënyrën rekursive për të shmangur kodin e gjatë me mënyrat përsëritëse. 

Më poshtë janë rezultatet e të dy versioneve
1. Matrica (array) me përmasë të paracaktuar për 1.500.000 rekorde
2. Pema (tree) (pa kufizim për memorjen)

Sistemi i përdorur: Pentium 4 2.66 GHz, 256 MB memorje
Sistemi Operativ: Windows XP SP1
Përpiluesi: Dev-C++ 4.9.9.1 me GCC/MinGW 3.3.1

Do ishte mirë që programet të testoheshin në disa sisteme para se të nxjerrim konkluzione. 

Koha e harxhuar nga programet në bazë të numrit të rekordeve


```
# Rekordeve	Matrica (ms)	Pema (ms)
  125.000	  470		  610
  250.000	  910		1.251
  500.000	1.790		2.600
  750.000	2.653		4.130
1.000.000	3.500		7.000
1.250.000	5.900		8.800
1.500.000	7.500		11000
```


Analiza e funksioneve të Matricës Statike (array)


```
Funksioni		% kohes
rekord_krah		80,23
strcmp			 9,30
shkruaj_databaze	 5,81	
lexo_databaze		 2,33
fgets			 2,33
```

Analiza e funksioneve të Pemës


```
Funksioni		% kohes
hidh_ne_peme		52,70
shkruaj_databaze	21,96
liro_memorje		19,26
lexo_databaze		 3,38
fgets			 1,42
strcmp			 0,71
```

shkruaj_databaze dhe liro_memorje jane rekursive. 


Skedarët e kodit janë bashkëngjitur më poshtë. 

Kodi në C për Matricën


```

// Autori: Edi, edspace ET comcast PIKE net
// Pershkrimi: 
//     Lexon dhe shkruan rekorde ne nje skedar sipas renditjes alfabetike
//     Rekordi permban 2 kolona te ndara me tab 
//
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <time.h>

typedef struct rekord rekord;

const REK_MAX = 1500000;  // numri maksimal per rekordet

struct rekord // struktura e nje rekordi
{ 
    char personi [20];  // emri i personit deri ne 20 shkronja
    int num;            // numri
}; 

//********************************************************************
// Hap skedarin db dhe hidh rekordet ne matricen r
// Kthen numrin e rekordeve ne skedar ose -1 nqs nuk hapet skedari
//
int lexo_databaze( const char db [], rekord * r);

//********************************************************************
// Hap skedarin db dhe shkruar nr rekorde nga matrica r
// Kthen 0 nqs ndodh gabim
//
int shkruaj_databaze(const char db [], const rekord * r, const size_t nr);

//********************************************************************
// Krahaso dy rekorde duke u bazuar mbi personin. 
// Ky funksion perdoret per renditjen e rekordeve
// emrat 0 konsiderohen si te pavlefshem dhe renditen ne fund 
// Kthejme: -1 nqs r1<r2, 0 nqs r1=r2,  1 nqs r1>r1
// A < Z < 0
//
int rekord_krah ( const rekord * r1, const rekord * r2);


//********************************************************************
// MAIN
//
int main (void) 
{ 
   clock_t koha1 = clock(); 

   const char db [] = "databaza.txt"; // emri i skedarit ku do ruhet info
   const char db1 [] = "databaza2.txt"; // emri i skedarit ku do ruhet info
    
   // tregues per array me rekorde
   rekord * r = NULL;
   
   // kerkojme memorjen per REK_MAX rekorde
   r = calloc( REK_MAX, sizeof(rekord) );
   
   if( r == NULL )  // nqs nuk ka memorje te mjaftueshme
   {
       printf("GABIM: Nuk ka memorje te mjaftueshme\n");   
       return 1;
   }       
   
   int nr_rekordeve = lexo_databaze( db, r );
   
   if ( nr_rekordeve == -1 )
   {
       printf("GABIM: Nuk mund te hapej skedari %s\n", db);
   }
   
   qsort (r, nr_rekordeve, sizeof (rekord), (const void *)rekord_krah);  
     
   if( !shkruaj_databaze( db1, r, nr_rekordeve ) )
   {
       printf("GABIM: Nuk mund te hapej skedari %s\n", db1);
       return 1;
   }    
   
   free(r);
   
   printf("Koha e ekzekutimit: %ld", clock() - koha1);
   
   return 0;   // mbaruam
} 

//************************************************************************
// Lexojme rekordet nga databaza
//
int lexo_databaze( const char db [], rekord * r)
{
   FILE * inskedari; // tregues per skedarin

   if(!(inskedari = fopen(db, "r"))) 
   {
       return -1; // nqs nuk hapim dot skedarin kthejme kodin -1 (gabim)
   }    
    
   int i = 0;
   char rresht [100];  // buffer per 1 rresht (maksimumi 100 shkronja)
  
   while(i < REK_MAX )   // marrim REK_MAX rekorde nga skedari
   {
       fgets( rresht, 100, inskedari);   // marrim rreshtin

       // nqs eshte rreshti i fundit, dalim jashte
       if( feof(inskedari) || strlen(rresht) == 1) break;  
       
       // marrim emrin e personit qe ndahet me tab nga numri
       strncpy( r[i].personi, strtok (rresht,"\t"), 20 ); 
       r[i].num = atoi( strtok (NULL," \n") );    // marrim numrin        
       i++;

   }

   fclose(inskedari);   // mbyllim skedarin
   
   return i;       // numri i rekordeve qe gjetem ne skedar
}   

//************************************************************************
// Shkruajme rekordet ne databaze
//
int shkruaj_databaze( const char db [], const rekord * r, size_t nr )
{
   FILE * outskedari; // tregues per skedarin
  
   // nqs nuk hapim dot skedarin per te shkruar
   if(!(outskedari = fopen(db, "w+"))) // 
   {
       return 0; // nqs nuk hapim dot skedarin kthejme kodin 0 (gabim)
   }    
   
   int i;
   
   for (i = 0; i < nr; i++)  // shkruajme rekordet
   {    // emri dhe numri jane te ndara me tab
       fprintf (outskedari, "%s\t%d\n", r[i].personi, r[i].num);
   }    
  
   fclose (outskedari);  // mbyllim skedarin
   
   return 1;
}

//************************************************************************
// Krahasojme rekordet e databazes
//  
int rekord_krah (const rekord * r1, const rekord * r2)
{
    if( strcmp("\0", r1->personi) == 0 ) return 1;  // zeron e vendosim ne fund
    if( strcmp("\0", r2->personi) == 0 ) return -1; // zeron e vendosim ne fund
    return strcmp (r1->personi, r2->personi);       // krahasojme dy fjale
}

// fund 



```


Kodi në C për Pemën


```

// Autori: Edi, edspace ET comcast PIKE net
// Pershkrimi: 
//     Lexon dhe shkruan rekorde ne nje skedar sipas renditjes alfabetike
//     Rekordi permban 2 kolona te ndara me tab 
//
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <time.h> 

typedef struct rekord rekord;
typedef struct nyje nyje;
typedef nyje* peme;

struct rekord // struktura e nje rekordi
{ 
    char personi [20];  // emri i personit deri ne 20 shkronja
    int num;            // numri
}; 

struct nyje {
   rekord  data;
   nyje * majtas;
   nyje * djathtas;
};

//********************************************************************
// Hap skedarin db dhe kthe pemen me rekorde
//
peme lexo_databaze( const char db []);

//********************************************************************
// Shkruaj rekordet e pemes p ne db
//
void shkruaj_databaze(FILE * db, peme p);

//********************************************************************
// Hidh/ngjit nyjen n ne pemen p sipas rendit alfabetik
//
void hidh_ne_peme( nyje * n, peme  p);

//********************************************************************
// liro memorjen e nje peme ne menyren rekursive 
// liro degen majtas, liro degen djathtas, liro renjen
//
void liro_memorje(peme p);

    
//********************************************************************
// MAIN
//
int main (void) 
{ 
   clock_t koha1 = clock(); 
   
   const char db [] = "databaza.txt"; // emri i skedarit ku do ruhet info
   const char db1 [] = "databaza2.txt"; // emri i skedarit ku do ruhet info
    
   peme p = NULL;

   p = lexo_databaze( db );
   
   if( p == NULL )  
   {
       printf("GABIM: Nuk mund te lexonim databazen\n");   
       return 1;
   }
   
   FILE * outskedari; // tregues per skedarin
   
   if(!(outskedari = fopen(db1, "w+"))) // 
   {
       printf("GABIM: Nuk mund te hapej skedari %s\n", db1);
       return 1;
   }    
   
   shkruaj_databaze(outskedari, p);
   
   fclose(outskedari);
   
   liro_memorje(p);
   
   printf("Koha e ekzekutimit: %ld", clock() - koha1);
   
   return 0;   // mbaruam
} 

//************************************************************************
// Lexojme rekordet nga databaza
//
peme lexo_databaze( const char db [] )
{
   FILE * inskedari; // tregues per skedarin
   char rresht [100];  // buffer per 1 rresht (maksimumi 100 shkronja)

   if(!(inskedari = fopen(db, "r"))) 
   {
       printf("Nuk mund te hapej skedari %s\n", db);
       return NULL; 
   }    
   
   // ************* formojme renjen e pemes ***********************
   // Ky bllok eshte ndare nga While per te shmangur nje kusht (if) brenda while
   //
   if( fgets( rresht, 100, inskedari) == NULL )
   {
       fclose(inskedari);
       return NULL;
   }    
   if( strlen(rresht) == 1 )
   {
       fclose(inskedari);
       return NULL;
   }    
   
   peme p = calloc(1, sizeof(nyje) );
    
   // assert(p!=NULL);
   strncpy( p->data.personi, strtok (rresht, "\t"), 20 ); 
   p->data.num = atoi( strtok (NULL, " \n") );    // marrim numrin        
   p->majtas = NULL;
   p->djathtas = NULL;
   
   nyje * n = NULL;
   
   // ************* formojme nyjet e tjera ***********************
   //
   while( fgets( rresht, 100, inskedari)!= NULL )   
   {
       // nqs eshte rreshti i fundit, dalim jashte
       if( strlen(rresht) == 1 ) break;  
       
       n = calloc(1, sizeof(nyje) );
       
       if( n == NULL ) 
       {
           liro_memorje( p );
           fclose(inskedari);
           return NULL;
       }        
       
       // marrim emrin e personit qe ndahet me tab nga numri
       strncpy( n->data.personi, strtok (rresht, "\t"), 20 ); 
       n->data.num = atoi( strtok (NULL, " \n") );    // marrim numrin        
       n->majtas = NULL;
       n->djathtas = NULL;
       
       hidh_ne_peme(n, p);
       
   }
   
   fclose(inskedari);   // mbyllim skedarin
   
   return p; // kthejme pemen
}   

//************************************************************************
// Shkruaj databazen ne db nga pema p sipas renditjes alfabetike
//
void shkruaj_databaze (FILE* db, peme p)
{
   if (p != NULL) 
   {
      shkruaj_databaze(db, p->majtas);
      fprintf(db, "%s\t%d\n", p->data.personi, p->data.num);
      shkruaj_databaze(db, p->djathtas);
   }
}

//************************************************************************
// Hidh/Ngjit nyjen n ne pemen p
// Programuar me perseritje sepse menyra rekursive eshte me e ngadalte
//
void hidh_ne_peme( nyje * n, peme p)
{     
   while(1)
   {
       if( strcmp( n->data.personi, p->data.personi ) <= 0 )
       {
           if( p->majtas == NULL )
           {
               p->majtas = n;
               return;
           }    
           else p = p->majtas;
       }
       else 
       {
           if( p->djathtas == NULL )
           {
               p->djathtas = n;
               return;
           }    
           else p = p->djathtas;
       }
   }    
}    


//************************************************************************
// Liro memorjen e pemes p
//
void liro_memorje(peme p)
{
    if( p == NULL ) return; // fakultative sepse edhe free(null) ben return 
    if(p->majtas != NULL) liro_memorje(p->majtas);
    if(p->djathtas != NULL) liro_memorje(p->djathtas);
    
    free(p);
    p = NULL;  // fakultative
}

// fund 



```

----------


## werewolf

cool!
megjithate une qendroj me mendimin se nuk duhet perdorur matrica kur nuk te jepet dimensioni i inputit, pasi sic eshte shkruajtur me lart, nese e ke matricen me 100 rekorde, dhe kur arrin ne fud shef qe duhet te shkruaj 101  :buzeqeshje: , ca do behet?????? do ndryshohet dimensioni i matrices, rikompilohet programi dhe do shkruhen prape 101 rekordet???
nje nga gjerat qe me kane ngel ne mend ne keto vite eshte se:" Kur nuk e di dimensionin e inputit, DUHET perdorur struktura dinamike(mgjs me vektor & matrice mund te punoj me shpejt programi)". Te dyja kane te mirat dhe te keqijat e tyre........ne kete rast me mire te perdoren pemet. 

hej edi, nuk do ishte me mire qe rekordet,  te hidheshin ne peme kur i merr ne input dhe ne fund te shkruheshin ne file? Keshtu i beje All in 1 ?
. Je madh plako, ke shume durim.....!
 po mos te kisha nje thes me provime dhe projektet(3 projekte), mbase do kisha bere ndo1 code.....
bye

----------


## edspace

Për eksperimentet që bëra unë, kufizimi i matricës ishte 1 milion e 500 mijë. Kur matrica mund të ketë përmasa të tilla nuk është nevoja ta ndryshosh programin sepse kufizime të tilla nuk arrihen, ose mund të arrihen shumë shumë rrallë. Një skedar me 1.500.000 rekorde është rreth 30MB. Skedarë të tillë bëhen të pa menaxhueshëm dhe është më mirë të ndahen në dy tre skedarë. Prandaj edhe programin nuk ështe nevoja ta ndryshosh e përpilosh nga fillimi por mjafton të ndash të dhënat në dy skedarë. 

Matrica vërtet ka kufizim përmasat, por siç tregohet dhe nga rezultatet, pema është më e ngadaltë, edhe pse punë sekondash. 


Në lidhje me leximin e rekordeve, ato lexohen dhe hidhen në pemë një nga e një. Funksioni lexo_databaze lexon rreshtin, formon nyjen, pastaj e hedh nyjen në pemë. Këtë gjë e përsërit deri sa gjen fundin e skedarit ose kompjuteri nuk ka më memorje (calloc = NULL). 

Nuk e kuptova sugjerimin tënd sepse unë atë që thua ti kam bërë. 

Suksese me provimet!

----------


## werewolf

> / Hap skedarin db dhe hidh rekordet ne matricen r
> // Kthen numrin e rekordeve ne skedar ose -1 nqs nuk hapet skedari
> //
> int lexo_databaze( const char db [], struct rekord * r);


per kete e kisha fjalen
Ti e merr nga skedari inputin (rekordet te pa renditur) apo jo?
po sikur ti merrje nga perdoruesi dhe ti mbaje te renditura ne peme ose matrice dhe ne fund ti shkruaje ne peme???
ushtrimi nuk thoshte te merrje skedarin dhe ta rendisje, por ta mbaje te renditur( rekordin e ri qe merje ta vije ne vendin e duhur), par do ishte me mire qe ne file ta shkruaje vetem ne fund, pasi te kishte mbaruar inputi nga perdoruesi, keshtu do evitoje te perdorje funksionin lexo database, por beje nje funksion tjeter qe ti merrte rekordet nga perdoruesi dhe ti vinte ne vendin e duhur

pse te perdoret nje matrice aq e madhe kur mund te duhen te futen vetem 2 rekorde psh?????
zgjidhja me matricen mund te jete(pak) eficent nga ana temporale(koha e ekzekutimitte programit) se ai me pemet, por per hapesire le shume per te deshiruar.... 



rofsh!

----------


## IlirDeda

Edi me pelqen shume analiza jote. Urime.
Werewolf, nuk arrij dot ta kuptoj se cfare do te thuash. A mund te shkruash pak kod qe te qartesohemi?

----------


## werewolf

kerkesa e ushtrimit ishte ti merrje rekordet dhe ti vije ne nje file te ordinuara, prandaj i thashe edit qe funksionin lexo_database ta shkruante ne menyre qe ta merte intputin nga perdoruesi, dhe jo nga skedari, jo se kishte ndo1 gje kjo, nuk ndryshon gje, por i pergjigjet me sakte kerkeses(qe thote ta lexoje rekordin dhe ta hedhi ne file te ordinuar).
dhe tjeter thashe qe 'me pelqen' me shume zgjidhja me peme, se ka komplesitet me te ulet ne lidhje me hapesiren(harxhon me pak memorje ne disa raste, dhe eshte e pershtatshme ne rastet kur nuk dime dimensionin e inputit)

Kodi eshte shume OK,  dhe analiza! Nejse..... 
bye

----------

