Usporiadaný lineárny zoznam (riešené príklady)

Z Kiwiki
Skočit na navigaci Skočit na vyhledávání
Imbox draft.png
Toto je projekt, na ktorom sa ešte stále pracuje!!

Aj keď sú v tomto dokumente použiteľné informácie, ešte nie je dokončený. Svoje návrhy môžete vyjadriť v diskusii o tejto stránke.

Algoritmy a programovanie - zbierka úloh


Štruktúry

Rekurzia

Dynamická alokácia pamäti

Vyhľadávanie

Triedenie

Lineárny zoznam

>Neusporiadaný lineárny zoznam
>Usporiadaný lineárny zoznam

Binárny strom

Numerické algoritmy

Zadanie

Vo vstupnom súbore máme zoznam študentov - v každom riadku sa nachádza meno, priezvisko, známka zo ZI, den, mesiac a rok narodenia. V poslednom riadku je 5 núl.

Zostavte program, ktorý zo súboru načíta všetkých študentov a vytvorí lineárny zreťazený zoznam, ktorého jednotlivé prvky budú obsahovať údaje jedného riadku. Prvky do zoznamu vkladajte tak, aby sa hneď pri vkladaní zotriedili. Triedenie bude podľa nasledujúcich požiadaviek.

  1. Zoznam bude utriedený podľa abecedy (od A po Z)
  2. Zoznam bude utriedený podľa priezviska
  3. ak je priezvisko rovnaké, tak budeme triediť podľa mena
  4. ak je meno rovnaké, tak budeme triediť podľa dátumu narodenia

Ďalej v programe budeme chcieť vyhľadať, či sa nejaký študent vyskytuje v zozname. Načítajte hľadaný reťazec a vyhľadajte daného študenta. Na toto vytvorte funkciu hladaj, ktorá bude zoznam prehľadávať a nájde všetky výskyty podľa zadaného kritéria.

Vzorový príklad

Vstup

Nasledujúce údaje sú načítané zo súboru

Jan Mrkvicka A 4 6 1985
Ferdinand Tell C 4 12 1986
Viliam Tell F 1 1 1987
johanka Z_arku C 5 4 1238
0 0 0 0 0 0

Nasledujúci údaj je načítaný z klávesnice

Tell

Výstup

Tell Ferdinand,C , 4.12.1986
Tell Viliam, F , 1.1.1987 

Analýza riešenia

Budeme pokračovať v predchádzajúcom príklade (Neusporiadaný lineárny zoznnam (riešené príklady)).

Pri vkladaní údajov si musíme naprogramovať porovnávaciu funkciu, pomocou ktorej budeme porovnávať záznamy (študentov) aby sme ich mohli vkladať na správne miesto. Vo funkcii PorovnajS(TStudent a, TStudent b) porovnávame dvoch študentov, podľa zadaných kritérií. Funkcia vráti 1 ak je študent a v abecednom poradí na vyššej pozícii ako b, v opačnom prípade vráti hodnotu -1. Ak sú údaje rovnaké vráti 0 .

Pri vkladaní údajov rozoznávame 3 prípady: údaje vkladáme na začiatok zoznamu, na koniec zoznamu, alebo niekde (na správne miesto) do stredu zoznamu. Pri všetkých prípadoch musíme upraviť štrukrúru TZoznam, aby ukazovatele prvy a posledny ukazovali na začiatok, resp. na koniec zoznamu. Taktiež treba správne nastaviť ukazovatele dalsi (štruktúry TPrvok) aby sa zoznam niekde neprerušil.

Pri vyhľadávaní študenta budeme zoznamom postupne prechádzať od prvého prvku až pokiaľ prvok nenájdeme. Pri úspechu vráti funkcia ukazovateľ na prvok, ktorý obsahuje hľadaného študenta: TPrvok* Najdi(TZoznam z, char *hladane,TPrvok *start=NULL,int podla_p=1). Parametrami funkcie sú: zoznam, v ktorom budeme hľadať, reťazec hladane - čo hľadáme. Podľa zadania máme vypísať všetky výskyty hľadaného reťazca. V prípade ak sú v zozname dvaja študenti s rovnakým priezviskom, funkcia nájde iba toho prvého. Aby funkcia pracovala univerzálnejšie, použijeme 3-ti parameter (Ukazovateľ na TPrvok), ktorý má význam: budeme hľadať od prvku start. Posledný argument má význam: ak bude podla_p=1 budeme hľadať priezvisko, ak bude podla_p=0, budeme vyhľadávať podľa mena. Pri ďalšom hľadaní získame prvok start jednoducho: použijeme posledne nájdený prvok.

Pre výpis prvku môžeme použiť funkciu VypisPrvok(TPrvok *p), ktorá bude vypisovať obsah prvku p (p obsahuje štrukúru TStudent, ktorá obsahuje položky meno, priezvisko, datum a znamka_ZI)

#include <iostream.h>
#include <fstream.h>
#include <string.h>
//-----------------datove struktury-------------------//
struct datum
    {    int d,m,y;
    };
struct TStudent
    {    char meno[32],priezvisko[32];
        datum datum_narodenia;
        char znamka_ZI;
    };
struct TPrvok
    {    TStudent student;
        TPrvok *dalsi;
    };     
struct TZoznam
{
  TPrvok *prvy, *posledny;
};

//-------------------funkcie-----------------------------//

int JePrazdny(TZoznam z)
{
  return z.prvy == NULL;
}

void VlozNaKoniec(TZoznam &z,TStudent s)
{
 TPrvok *novy = new TPrvok;
  novy->student = s;
  novy->dalsi = NULL;

  if (z.prvy == NULL)  // prazdny zoznam
    z.prvy = novy;
  else
    z.posledny->dalsi = novy;
  z.posledny = novy;
}
// nova funkcia !!!
int PorovnajS(TStudent a, TStudent b)
{  // podla priezviska, mena, datumu
 int porovanie;
 porovanie=strcmp(strlwr(a.priezvisko),strlwr(b.priezvisko));
 if(porovanie!=0) return porovanie;
 porovanie=strcmp(strlwr(a.meno),strlwr(b.meno));
 if(porovanie!=0) return porovanie;
 long da,db;
 da=a.datum_narodenia.d+a.datum_narodenia.m*100+a.datum_narodenia.y*10000;
 db=b.datum_narodenia.d+b.datum_narodenia.m*100+b.datum_narodenia.y*10000;
 if(da>db) return 1;
 if(da<db) return -1;
 return 0;
}

// nova funkcia !!!
void Vloz(TZoznam &z, TStudent x)  // vlozi prvok zotriedene
{
  TPrvok *novy = new TPrvok;
  novy->student=x;
  novy->dalsi = NULL;
  if (z.prvy == NULL)  // prazdny zoznam
    z.prvy = z.posledny = novy;
  else     
      if ( PorovnajS(x,z.prvy->student)==-1 )  // x < z.prvy->x / treba na zaciatok zoznamu
      {
        novy->dalsi = z.prvy;
        z.prvy = novy;
      }
      else
          if (PorovnajS(x,z.posledny->student)==1 )  // x > z.posledny->x / treba na koniec zoznamu
          {
            z.posledny->dalsi = novy;
            z.posledny = novy;
          }
          else
          {
                TPrvok *p1 = z.prvy, *p2 = z.prvy->dalsi;
                while (PorovnajS(p2->student,x)==-1)  //p2->x < x
                {
                  p1 = p2; p2 = p2->dalsi;
                }
                p1->dalsi = novy;
                novy->dalsi = p2;
          }
}
// nova funkcia !!!
TPrvok* Najdi(TZoznam z, char *hladane,TPrvok *start=NULL,int podla_p=1)
{ // ak je posledny parameter uvedeny, bude sa hladat od toho prvku dalej
  // inak sa hlada od zaciatku

  TPrvok *p;
  if(start==NULL)
    p = z.prvy;
  else
    p=start->dalsi;
  char hladane_pr[32];

  while (p != NULL)
  { if(podla_p)
       strcpy(hladane_pr,p->student.priezvisko);  // aby som si nezmenil povodne priezvisko
    else
       strcpy(hladane_pr,p->student.meno);  // aby som si nezmenil povodne priezvisko
    if (strcmp(strlwr(hladane_pr),strlwr(hladane))==0) return p;
    p = p->dalsi;
  }
  return NULL;
}

void VypisPrvok(TPrvok *p)
{
    cout << p->student.priezvisko <<" "<<p->student.meno<<" ("<<p->student.znamka_ZI<<") ";
    cout<<p->student.datum_narodenia.d<<". "<<p->student.datum_narodenia.m<<". ";
    cout<<p->student.datum_narodenia.y<<endl;    
}

void Vypis(TZoznam z)
{
  if (JePrazdny(z)) return;
  TPrvok *p = z.prvy;
  while (p->dalsi != NULL)
  {
    VypisPrvok(p);
    p = p->dalsi;
  }
  VypisPrvok(p);
}

void ZmazPosledny(TZoznam &z)
{
  if (z.prvy == NULL)  // prazdny zoznam
    return;

  TPrvok *p = z.prvy;
  if (p->dalsi == NULL)  // je len jeden prvok
  {
    delete p;
    z.prvy = z.posledny = NULL;
    return;
  }

  // najdeme predposledny prvok
  while (p->dalsi->dalsi != NULL)
    p = p->dalsi;
  delete p->dalsi;
  p->dalsi = NULL;
  z.posledny = p;
}

void Zmaz(TZoznam &z)
{
  while (!JePrazdny(z))
    ZmazPosledny(z);
}

void Nacitaj(TStudent &s,istream &vstup)
{
 vstup>>s.meno>>s.priezvisko>>s.znamka_ZI;    
 vstup>>s.datum_narodenia.d>>s.datum_narodenia.m>>s.datum_narodenia.y;
}
int main()
{
  TZoznam zoznam;
  zoznam.prvy = zoznam.posledny = NULL;
  TStudent s;
  int n=0;

  ifstream vstup;
  vstup.open("prvaci.txt");
 
  Nacitaj(s,vstup);
  Vloz(zoznam,s);
  while(s.datum_narodenia.d)
  {
          Nacitaj(s,vstup);
          if(s.datum_narodenia.d)
             Vloz(zoznam,s);
          n++;
  }
  vstup.close();
  cout<<"--------vypis zoznamu--------------"<<endl;
  cout<<"Pocet studentov: "<<n<<endl;;
  //  Vypis(zoznam);
  int kriterium;
  cout<<"Podla coho chces vyhladavat? meno(0)/priezvisko(1)";
  cin>>kriterium;
  cout<<endl<<"Zadaj retazec, ktory chces vyhladat: ";
  char przv[32];
  cin>>przv;
 
  cout<<"-----------------------------"<<endl;
  TPrvok *ja=Najdi(zoznam,przv,NULL,kriterium);  // hladame prvy vyskyt
  int pocet=0;
  while(ja)
  {   pocet++;
      if(ja)
            VypisPrvok(ja);
      ja=Najdi(zoznam,przv,ja,kriterium);  // hladame dalsie vyskyty od podledneho najdeneho studenta
  }
  cout<<"-----------------------------"<<endl;
  cout<<"Pocet najdenych studentov: "<<pocet<<endl;
  Zmaz(zoznam);
  system("pause");
}