Ap/Cpp/VBE treniruotės

Iš wiki.angis.net.
Jump to navigation Jump to search

Aptariamos treniruotės, skirtos IT VBE egzamino programavimo dalies pasiruošimui. Naudojamos tik įprastinės C++ konstrukcijos, aprašytos vadovėlyje „Šiuolaikiškas žvilgsnis į programavimą C++, kursas 11–12 klasėms“, nenaudojama STL biblioteka. Tačiau medžiagoje atsisakoma kai kurių perteklinių elementų bei pateikiami patogesni algoritmai, kas leidžia gauti racionalius sprendimus per trumpesnį laiką.

Įžanga

Programavimo mokymąsi galima palyginti su treniruotėmis, kai pradedama nuo paprastų uždavinukų ir einama link sudėtingesnių. Egzamino užduotys nėra labai sudėtingos, bet turi tam tikrą specifiką, kuriai reikia geriau pasiruošti. Siekiant geresnių rezultatų, peržvelgsime jau įvykusių egazaminų užduotis ir susidėliosime savo sprendimo schemą. Analizuojant užduotis galima pastebėti, kad šiemet jau dešimtas sezonas, kai programavimo uždaviniai pateikiami tuo pačiu šablonu 🙂. Dar 2012 metais formatas buvo kitas, o nuo 2013 metų – programavimo užduočių šablonas nesikeičia. Todėl tikslinga taikyti galimai aiškesnę sprendimo schemą, kurią toliau aptarsime ir išbandysime spręsdami konkrečias VBE užduotis. Pateiktų programų tekstų rinkti klaviatūra iš naujo nereikia, jums pateikiami visi C++ tekstai aplinkoje https://onlineGDB.com, kurie paruošti vykdymui, pakanka paspausti mygtuką Run. Norėdami eksperimentuoti ir keisti programą, spauskite mygtuką Fork this arba persikelkite duomenis į savo naudojamą programavimo aplinką. VBE atveju bus galima naudoti tik Code::Blocks, todėl pasitreniruokite su šia aplinka, kad įgautumėte reikalingų įgūdžių.

Rekomenduojama sprendimo schema

Apžvelgus visas VBE užduotis C++ naudojimo laikotarpiu, aiškiai matyti tokia sprendimo schema:

  • aprašyti duomenų struktūras ir jų saugyklas,
  • skaityti duomenis,
  • pagal juos skaičiuoti ir spausdinti rezultatus.

Duomenys visada pateikiami viename faile, paprastai yra perteklinių duomenų (skaitikliai), nurodančių toliau pateikiamų atskirų elementų (duomenų) kiekį. Todėl ruošiantis egzaminui tikslinga laikytis šablono, sutrumpintai vadinamo VBE_DRCP (Data_Read_Calculate_Print), kurį paaiškinsime paprastos užduoties pavyzdžiu.

DUOTAS konkurse dalyvaujančių mokinių sąrašas, kuriame nurodytas vardas, klasės kodas ir surinktų taškų kiekis (0–100), mokinių skaičius n<=90.

6 
Simonas  12a 66 
Martina  10b 100 
Jonas    11c 75 
Marius   11c 68 
Stepas   12a 77 
Darius   12c 68

RASKITE: kiek klasių dalyvavo konkurse, kiek buvo klasės mokinių bei kiek jie surinko taškų, klases surikiuokite taškų mažėjimo tvarka bei pagal klasės kodą.

klasiu_sk= 4 
11c 2 143 
12a 2 143 
10b 1 100 
12c 1 68

Pradinai žingsniai: duomenų struktūros ir skaitymo funkcija

1. Perkelkite pradinių duomenų pavyzdžius į programos komentarų dalį, o po to į failą. Duomenys, esantys prieš akis programos tekste, padeda rašyti skaitymo funkciją!

2. Parašykite main() funkciją, kurioje nurodykite srautų stdin ir stdout priskyrimą failams.

   freopen ("U1.txt","r",stdin); 
   freopen ("U1rez.txt","w",stdout); // pradžioje paslėpkite  

3. Apibrėžkite struktūrą Mokinys ir rezervuokite vietą mokinių sąrašui. Naudokite vienaskaitą struktūrai ir daugiskaitą sąrašui. Rezervuokite tokio dydžio masyvą kaip nurodyta užduotyje. Masyvas ir mokinių skaitliukas rašomas globalių kintamųjų srityje.

struct Mokinys { 
    string vardas; 
    string klase;   // klasės kodas 
    int taskai; 
}; 
Mokinys mokiniai[90];  // numatytosios reikšmės yra nuliai 
int msk = 0;           // mokinių skaičius sąraše

4. Parašykite skaitymo funkciją, kurioje įrašykite įvestų duomenų spausdinimą (nors to užduotis nereikalauja, bet tai pravers programos derinimo metu).

5. Išbandykite skaitymo funkcijos veikimą: pažymėkite funkciją freopen() kaip komentarą (dėl stdout – tada lieka konsolės režimas), o rezultatus stebėkite terminalo lange.

6. Jei duomenys perskaityti teisingai (sutampa su tais, kurie buvo pradinių duomenų faile) – tai esate teisingame kelyje, jau tam tikrą balų skaičių gausite 😊.

Naujausias pradinės programos variantas pateikiamas čia - [1]

Tolimesnė eiga: skaičiavimai ir rezultatai

Toliau tęsiame programos kūrimą – aprašysime rezultatų struktūrą ir masyvą pradinių duomenų globalioje srityje ir sukursime skaičiavimo funkciją. Tai yra esminė dalis, bet ir čia galima įžvelgti bendrų visoms užduotims požymių. Dažnai reikalaujama pradinius duomenis sugrupuoti pagal tam tikrą požymį. Nors C++ tam yra skirtos specialios priemonės (map struktūros), bet tai į mokyklos programą neįeina ir egzaminui, deja, tai nenaudotina. Todėl siūloma rašyti indekso paieškos funkciją, kuri rastų reikiamą vietą. Pradžioje ieškoma reikšmė įrašoma sąrašo pabaigoje – todėl ji visada bus randama. Jei ieškodami pasiekėme pabaigą, tai reiškia kad sąrašą reikia papildyti. Kadangi ieškoma reikšmė jau įrašyta, o struktūrų masyvo pradinės reikšmės yra nulinės, tai pakanka tik padidinti faktinių elementų skaitiklio reikšmę.

struct Klase {
    string vardas; // klasės kodas
    int mok_sk;    // klasės mokinių skaičius
    int taskai;    // klasės mokinių taškų suma
};
Klase klases[30];  // pagal nutylėjimą reikšmės nulinės
int ksk = 0;       // klasių sąraše kiekis

//==================================================
// taikysime paiešką su apsaugine reikšme pabaigoje !
// randa klasės indeksą pagal paieškos kodą
// o jei nėra, tai papildo klasių masyvą
int rastiKlase(string paieska) {
    klases[ksk].vardas = paieska; // visada rasime :)
    int i = 0;
    while (klases[i].vardas != paieska) i++;
    if(i == ksk) ksk++; // jei nebuvo - padidiname
    return i;
}
//------------------------------------------------
void skaiciuoti(){ // grupuojame pagal klases
    for (int i = 0; i < msk; i++){
        Mokinys m = mokiniai[i];
        int ki = rastiKlase(m.klase);
        klases[ki].mok_sk++;
        klases[ki].taskai += m.taskai;
    }
}

Spausdinimo funkcijoje tikslinga suformuoti tarpinį vienos raidės kintamąjį, kad atskirų struktūros elementų užrašai taptų lakoniškesni nei su indeksu.

Toliau deriname parašytas skaičiavimo funkcijas, stebime gaunamus rezultatus.

Baigiamoji dalis

Atskirai parašome rikiavimo kriterijui reikalingą funkciją arTvarka(). Tada ją galime išbandyti su standartine funkcija sort(). Tokiu būdu užduotis jau įvykdyta. Bet jei už rikiavimo funkciją skiriami balai, tai turėdami laiko galite ją parašyti, panaudodami tą pačią funkciją arTvarka().

NEPAMIRŠKITE: pašalinkite komentarą ties funkcija freopen(..., stdout), kad rezultatai pakliūtų į failą. Panaikinkite tarpinių rezultatų išvedimą skaitymo funkcijoje.

Aktyvus pilnos programos variantas yra pateikiamas čia

Kad programa būtų labiau individuali, parašykite savo nuožiūra komentarų, kuriuose nereikia tuščiažodžiauti. Galite iš anksto pasiruošti sinonimų funkcijų vardams:

  • skaityti() => formuoti(), skaityti_duomenis(), read(), ...
  • skaiciuoti() => formuoti(), grupuoti(), calculate(), ...
  • spausdinti() => isvesti(), rezultatai(), print(), write(), ...

Aišku, kad kiekvienais metais VBE metu būna tam tikrų „kabliukų“, todėl reikia atidžiai perskaityti užduočių sąlygas. Pradžioje pasirašykite vadinamuosius griaučius: duomenų struktūras, masyvus, main() ir kitas funkcijas, o tada spręskite ir tikrinkite savo sprendimus.

Siūlomų sprendimų apibendrinimas

A1. Darbą su failais geriausia organizuoti panaudojant funkciją reopen(). Tuomet cin visada bus įvedimo srautas, o cout – išvedimo. Pradžioje cout priskyrimą išjungiame naudodami //, nes žiūrėti rezultatus yra patogiau konsolės lange. Kadangi standartiniai srautai uždaromi automatiškai, todėl nereikia close(). Taip pat nereikia #include <fstream>. Kadangi main() funkcijos pradžia su freopen() tampa visada vienoda, tai į tą vietą ir keliame failų vardus, jų atskirai su raktažodiu const neaprašome.

A2. Programos pradinius duomenis ir rezultatus tikslinga formuoti kaip globalius, tai leidžia nekartoti jų funkcijų antraštėse. Tokiu būdu programa tampa aiškesnė! Struktūrų masyvai aprašomi kartu su elementų skaitikliais, kurie imituoja vector<T> tipą.

A3. Funkcijų antraščių rašyti nereikia, pakanka metodą main() nukelti į programos pabaigą. Kadangi duomenys ir rezultatai yra globalūs, daugelis funkcijų lieka be parametrų. Jos skirtos algoritmui suskaidyti į aiškiai apibėžtas dalis. Su parametrais rašomos rikiavimo ir paieškos funkcijos, kadangi tai yra universalios, nepriklausančios nuo konteksto funkcijos.

A4. Rikiavimo kriterijų visada tikslinga aprašyti kaip atskirą loginę funkciją. Tada jūsų rašomas rikiavimo algoritmas bus aiškesnis, be to galėsite patikrinimui naudoti standartinę funkciją sort().

A5. Užduotyje minima sąvoka „Prasmingai pavadinti kintamieji“ nereiškia kad reikia rašyti ilgus sudurtinius vardus – tai gali apsunkinti programos teksto skaitymą.

Konkrečių VBE 2022-2013 užduočių sprendimai

Jums pateikiami ketverių pastarųjų, 2016 bei 2013 metų užduočių sprendimai. Treniruotės metu patartina susipažinti su oficialiomis užduotimis, kadangi jų formuluotės pateikiamos naudojant tą patį šabloną. Visada būna dvi užduotys, viena lengvesnė, kita sudėtingesnė. Suprantama kad egzamino metu veikia stresas, nepavyksta iš karto rasti gero kelio, todėl ir siūloma mūsų VBE pritaikyta schema, leidžianti lengviau išspręsti užduotis. O mokytis geriau ne pagal egzamino metu gautus sprendimus, o pagal ramiai apibendrintus.

Visose programose duomenys yra pateikti programos priekyje, kas leidžia juos pastoviai stebėti ir geriau suprasti sąlygą. Perkėlimas į failą kopijavimo būdu yra greitas. Dar siūlome prasmingas skaičių grupes išryškinti skirtingų tarpų skaičiumi, kadangi skaičių įvedimui tas netrukdo, o uždavinys tampa aiškesnis.

2022 metų užduotys yra čia. U1 sprendimas yra čia. U2 sprendimas yra čia.
2022 metų užduotys pasižymėjo, jog nebuvo reikalaujama rašyti rikiavimo funkcijos, todėl laimėjo tie mokiniai, kurie lankė mūsų FB grupę IT VBE konsultacijos 🙂 kadangi rikiuoti reikėjo abiejose užduotyse ir buvo galima naudoti standartinę sort() funkciją. Taip pat užduočių autoriai mėgsta grupavimą pagal vardus antroje užduotyje, kas buvo detaliai išnagrinėta konsultacijose (garantuotas indekso radimas su reikšme pabaigoje).
U1 – Konkursas. Tai gana paprasta užduotis, buvo duotas konkretus konkurso dalyvių skaičius, todėl eilučių skaičius (masyvo dydis) buvo fiksuotas. Gal neįprasta buvo tai, jog pradinis skaičius rodė skaičiukų kiekį kitose eilutėse. Spausdinant rezultatus reikėjo atkreipti dėmesį, jog pateikiami ne visi dalyviai, o tik tie, kurie surinko daugiausiai taškų. Galima netgi naudoti supaprastintą ciklo variantą for, kuris vadinamas foreach.
U2 – Sportas. Teko pasikrapštyti, kad išpildyti visus U2 užduoties niuansus (palyginkite su 2016 metų U2) 🙂 Užduotis buvo kaip ir nesudėtinga - sukuriamas pratimų masyvas, kurio raktas yra pratimo vardas. Kabliukas buvo tame, kad kai kuriomis dienomis buvo kartojamas tas pats pratimas. Todėl pratimų elemento reikšmę sudarė: skaitliukai dienos dalims ir minutėms bei dienų masyvas, kurio elementas yra true, kai i-ąją dieną atliekamas pratimas. Tada skirtingų dienų skaičius bus paprasta požymių suma.

2021 metų užduotys yra čia. U1 sprendimas yra čia. U2 sprendimas yra čia.
U1 – Bėgimas. Šioje užduotyje duomenis sudaro tik skaičiukai. Todėl funkcija trukmė() atlieka laiko skaičiavimą, naudodama 4 nuoseklius skaičius iš srauto cin. Mažiausią laiką randame tiesiog įvedimo metu.
U2 – Apklausa. Gana normali sąlyga, nėra pozicinio vardų įvedimo. Algoritmo pagrindą sudaro grupavimo pagal pamokos vardą metodas, kuriame taikome paiešką su ieškomo elemento įrašymu į pamokų sąrašo pabaigą.

2020 metų užduotys yra čia. U1 sprendimas yra čia. U2 sprendimas yra čia.
U1 – Gėlės. Sprendžiant reikia transformuoti mėnesį ir dieną į vasaros dienų masyvo indeksą ir tam naudojamas mėnesio pradžios indeksų masyvas const int mi[] = {0, 30, 61};
U2 – Žvejų varžybos. Tai gana paini sąlyga. Kad su ta pačia funkcija būtų galima rikiuoti žvejų ir žuvų masyvus, yra naudojama struct Duomuo - universali struktūra - tinka žvejui ir žuvims.

2019 metų užduotys yra čia. U1 sprendimas yra čia. U2 sprendimas yra čia.
U1 – Aliejus. Gana keista užduotis – daug pradinių duomenų (atskirų kintamųjų), o sprendžiant nereikalingi nei sąlygos, nei ciklo sakiniai😊. Gali išmokyti šabloninio vardų sudarymo.
U2 – Biatlonas. Vidutinio sunkumo užduotis, reikia suformuoti laiką iš atskirų dalių.

2016 metų užduotys yra čia. U1 sprendimas yra čia. U2 sprendimas yra čia.
U1 – Kuprinės ir U2 – Makšta yra pačios lengviausios šios serijos užduotys 😊 U1 reikalavimas nenaudoti masyvų, o pakartotinai skaityti failą, priminė 50 metų senumo faktus, kai dėl atminties trūkumo buvo naudojamas tarpinių duomenų kaupimas 🙁 Tuo tarpu U2 įdomi dėl to, kad ji tapo prototipu 2022 metų užduočiai.

2013 metų užduotys yra čia. U1 sprendimas yra čia. U2 sprendimas yra čia.
U1 – Siuntos ir U2 – Apskritys yra nesudėtingos užduotys 😊

Aptartą programavimą pagal šabloną galima palyginti su krepšinio deriniais - juos žinantys pasiekia geresnių rezultatų nei besiblaškantys. Kadangi visos VBE užduotys yra panašaus pobūdžio, tai siūlomas būdas leidžia pasiekti geresnį rezultatą aiškesnėmis priemonėmis. 😊

Apskritai kodo peržiūra ir pertvarkymas yra gera mokymosi priemonė! Ją naudoja ir profesionalai, tai vadinamasis refaktoringas https://en.wikipedia.org/wiki/Code_refactoring. Tikimės kad pavyks rasti ir daugiau racionalių sprendimų.

Savo pastebėjimus apie galimus pagerinimus, netikslumus bei neaiškumus rašykite tiesiog autoriui el. paštu arba komentuokite FB grupės https://www.facebook.com/groups/itvbekonsultacijos/ diskusijose. Radusieji programose klaidų bus apdovanojami: mokytojai – skanėstais, o mokiniai – papildomais balais KTU duomenų struktūrų kurse 😊.

Turinys