Está en la página 1de 169

KAUNO TECHNOLOGIJOS UNIVERSITETAS Praktins informatikos katedra

J.Blonskis, V.Buknaitis J.Konien, D.Rubliauskas

C++ PRAKTIKUMAS

Kaunas 2001

Turinys
1 skyrius. C++ elementai..........................................................................5 2 skyrius. Masyvai, failai, eiluts ...........................................................26 3 skyrius. Struktros...............................................................................55 4 skyrius. Klass apibrimas. Objektas ................................................62 5 skyrius. vedimo, ivedimo srautai......................................................67 6 skyrius. Klasi savybs. Objektikai orientuotas programavimas ......77 7 skyrius. Tiesiniai vienkrypiai sraai...............................................103 8 skyrius. Dvikrypiai tiesiniai sraai.................................................136 9 skyrius. Tiesini sra rinkiniai.......................................................147 10 skyrius. Netiesiniai sraai ..............................................................152 11 skyrius. Savarankikas darbas .........................................................158

vadas
C kalba ir jos modifikacija C++ pasiymi labai dideliu lakonikumu, sintaksini struktr lankstumu ir universalumu, todl i kalb daniausiai pradedama mokytis jau turint programavimo kitomis kalbomis patyrim. i knyga skirta skaitytojui, kuriam inomos pagrindins programavimo kalbose vartojamos svokos, program struktrizavimo priemons, kuris sugeba naudoti standartines duomen struktras, valdanias struktras, programavimo aplinkas. Knygelje glaustai pateikiamos C++ pagrindins preimons (sakini konstrukcijos, duomen tipai, funkcijos). Gausiai pavyzdiais iliustruojamos pagrindins C++ priemons, kurios, autori nuomone, btinos pradinei painiai su ia kalba. Pagrindinis dmesys skirtas klasms ir j savybms. Programavime plaiai vartojamas dinaminis atminties skirstymas. Tai leidia kurti efektyvesnes programas. Dinamins duomen struktros leidia kurti programuotojui norimos konfigracijos ir sudtingumo duomen tipus. Tai labai lanksti ir efektyvi priemon, naudojama duomenims saugoti bei apdoroti. iame leidinyje pristatomos pagrindins klasikins dinamins duomen struktros: tiesiniai vienkrypiai sraai ir j modifikacijos (stekas, dekas, eil, iedas), dvikrypiai tiesiniai sraai, tiesini sra rinkiniai, medio tipo sraas. Nagrinjamos pagrindins operacijos su sraais: formavimas, perira, paieka, rikiavimas, alinimas, terpimas, naikinimas. Visi veiksmai iliustruojami realiomis programomis, paraytomis ir patikrintomis su C++4.5. Knyga skirta studentams, studijuojantiems duomen struktras, taiau stengtasi pristatyti dinamines duomen struktras detaliai su kuo daugiau pavyzdi, kad bt suprantama ir ingeidiam moksleiviui ar programavimo mgjui. i knyga skirta praktinei painiai su C++, todl isamesnms kalbos studijoms reikalinga specialiai tam skirta literatra. C++ kalbai skirt knyg daug, taiau jos silomos usienio kalbomis. Lietuvikai parayt knyg labai maai. Autoriai tikisi, kad i knyga palengvins pradedaniam programuotojui pasirinkti jam tinkam literatr.

1 skyrius. C++ elementai


1.1. Programos struktra
Pradedant programuoti su C++ kalba, siloma atkreipti dmes tokias ios kalbos ypatybes: yra tik viena programos struktrizavimo priemon funkcija; programos svok atitinka pagrindin funkcija, kuri ymima vardu main; identifikatoriuose didiosios ir maosios raids nesutapatinamos; programos objekt (struktr, kintamj, funkcij) apraai gali bti bet kurioje programos vietoje svarbu tik tai, kad objektas bt apibrtas prie j naudojant; aprauose plaiai vartojami funkcij prototipai; C++ kalboje nedidelis standartizuot operatori skaiius, todl naudojamos vairios bibliotek sistemos; kreipiantis kintamuosius ir struktras, plaiai vartojamos rodykls; daugel duomen tip galima interpretuoti keliais vairiais bdais.

Tipin programos C++ kalba (programos failo) struktra:


/* Instrukcijos pirminiam procesoriui /* Globaliniai apraai /* Funkcij prototipai main() { /* Pagrindins funkcijos tekstas } /* Funkcij apraai */ */ */ */ */

Apraant programos struktr, panaudotos tokios C++ kalbos sintaksins konstrukcijos: komentarai paaikinimams skirtas simboli rinkinys, kurio ribos ymimos simboli poromis /* ir */; paraius eilutje du simbolius be 5

tarpo // toliau esantis tekstas iki eiluts pabaigos suprantamas kaip komentarai; main() pagrindins programos funkcijos antrat; sudtinis sakinys tarp skliaust {} raytas sakini rinkinys, su kuriais programoje elgiamasi taip kaip su vienu sakiniu;

Programos struktros aprayme komentarais parodyta, kokia tvarka joje turi bti surayti struktriniai elementai: Programos pradioje suraomos instrukcijos pirminiam procesoriui (preprocessor), kuriose nurodoma, kokius programos teksto pertvarkymus reikia atlikti prie jos kompiliavim. Globaliniais apraais apibriami tie programos objektai, kurie gali bti vartojami visame rengiamos programos faile (tiek pagrindinje, tiek vartotojo funkcijose). Vartotojo funkcijos gali bti apraomos ne tik programos gale, bet ir globalini apra dalyje. Suraius pagalbines funkcijas programos gale, jos tekst lengviau skaityti ir analizuoti; tada nesilaikoma reikalavimo, kad funkcijas reikia pirma aprayti, o tik po to vartoti. io prietaravimo ivengiama globalini apra dalyje pateikiant programos gale surayt funkcij prototipus. Funkcij prototipais vadinami j antrai sakiniai. Programai tikslinga suteikti vard, uraom teksto pirmoje eilutje kaip komentar. ia naudinga parayti daugiau paaikinim apie program. Visa tai leis lengviau ir greiiau atpainti reikaling program.

1.1 pratimas. Programa klausia vartotojo, ar giedras dangus. Kaip atsakym


vartotojas paspaudia klavi 1, jeigu giedras dangus, ir 0 prieingu atveju. Programa atspausdina ekrane vest reikm ir j perduoda funkcijai, kuri analizuoja atsakym ir iveda ekrane piln praneim.
#include <iostream.h> #include <conio.h> // vedimo/ivedimo srautai // Tekstinio ekrano tvarkykl Funkcijos prototipas Pagrindin funkcija Kintamojo apraas Kintamojo apraas Ivedimas ekrane

void Atsakymas(int); // // Pagrindin programa void main() { // char simbolis; // int Dangus; // cout << "Ar saule sviecia?\n"; //

} // void Atsakymas(int Ats) if (Ats == 1) cout << else cout << "danguje }

cout << " Taip 1 Ne 0 \n"; cin >> Dangus; // vedimas klaviatra cout << "Atsakymas:" << Dangus << "\n"; cout << "Dabar "; Atsakymas(Dangus); // Kreipinys funkcij cout << endl << "Paspauskite bet kok simbolini klavi << " ir ENTER" << endl; // endl eiluts pabaiga cin >> simbolis; Funkcija { "giedras dangus!!!\n"; labai daug debesu\n";

Programos pradioje suraytos instrukcijos pirminiam procesoriui, kurios ymimos simboliu #. terpimo instrukcijomis include nurodoma, koki fail tekstai turi bti terpti instrukcij paymtose vietose pirminio apdorojimo metu. terpiam fail vardai raomi tarp simboli < > arba tarp kabui (""), jeigu failas yra sukurtas vartotojo. Jeigu programoje vartojamos asmenins pagalbins bibliotekos, instrukcijomis include turi bti nurodomi iose bibliotekose esani priemoni prototip failai, kuri vardai turi pltinius .h (header).

1.2. Kintamj tipai ir apraymas. Pradini reikmi priskyrimas


Kintamj apra sintaks:
tipas kintamj sraas [= pradin reikm ]

Kaip ir kitose kalbose, duomen tipai nurodomi baziniais odiais. C++ kalboje yra vartojami ie baziniai elementars duomen tipai:
1.1 lentel. Pagrindiniai tipai

Tipas
char int long short unsigned float double

Galimos reikms
128..127 32768..32768 2147483648..2147483647 32768..32768 0..65535 3.41038..3.41038 1.710308..1.710308

Tokio aprao pavyzdys programoje Pratimas1 yra pagrindinje funkcijoje:


int Dangus;

Programoje visi kintamieji kiekvienu momentu privalo bti apibrti, t.y. turti konkrei reikm. Kalbos kompiliatorius kintamiesiems skiria atmint, taiau nepasirpina, kas ten yra. Programuotojas privalo tai numatyti. Rekomenduojama programos kintamj apra dalyje nurodyti pradines j reikmes. Programos pavyzdyje galima buvo parayti: int Dangus = 0; arba atskiru priskyrimo sakiniu: Dangus = 0; Aprauose vienodo tipo kintamuosius galima grupuoti, pavyzdiui:
int Dangus = 0, Medis = 0, Katinas = 0;

Tai galima aprayti ir taip:


int Dangus, Medis, Katinas; Dangus = Medis = Katinas = 0;

Nors abu bdai duoda t pat rezultat, taiau pirmasis tinkamesnis. Jis vaizdesnis ir suprantamesnis, nes vienoje vietoje viskas pasakyta apie kintamj. J naudojant bus maiau klystama, nes nereiks dukart kartoti kintamojo vardo. Jis leidia lengviau suprasti ir modifikuoti program, nes kintamj reikms pasakomos j aprao vietoje ir kiekviena inicializuojama atskirai, taigi, ir pakeitimus darant, pradines reikmes galima skirti skirtingas. Sveikojo tipo kintamj aprayme galima taikyti nuorod unsigned. Taip sukuriami kintamieji, galintys turti tik teigiamas sveiko tipo reikmes, pavyzdiui: unsigned int X; // reikmi intervalas: 0..65535 Programose labai naudingos konstantos. Jos apraomos panaudojant kalbos rezervuot od const, pavyzdiui: const const 8 int float A = 125; B = 13.5;

1.2 pratimas. Programa parodo, kad C++ kalboje leidiama maiyti skirting tip kintamuosius. Maiant tipus char ir int, naudojamas simbolio ASCII lentels skaitmenis atitikmuo, o maiant tipus int ir float, paprasiausiai pridedama arba atmetama trupmenin skaiiaus dalis.
void main() { int a, b, c; char x, y; float num, toy; a = b = c = 27; x = y = 'A'; num = toy = 3.6792; a = x = num c = } y; b; = b; toy; // // // // a bus lygus 65 (simbolis A) x bus lygus 27 (simbolis ) num bus lygus 27.00 c bus lygus 3

Kintamasis galioja nuo jo paskelbimo vietos. Kintamuosius galima aprayti bet kurioje vietoje. Tikslinga prisiminti, kad: programos teksto pradioje prie main funkcij surayti kintamieji yra globals ir galioja visame tolesniame tekste; kintamieji, kuri apraas yra funkcijoje, vadinami lokaliais ir galioja tik joje; esant vienodam globalaus ir lokalaus kintamojo pavadinimams, pirmenyb suteikiama lokaliam, t.y. toje funkcijoje globalus negalioja; kintamieji gali bti apraomi j panaudojimo vietoje, taiau tai nerekomenduojama.

1.3 pratimas. i programa iliustruoja, kaip galima aprayti kintamuosius, ir kuriose programos vietose jie galios.
#include <stdio.h> void head1(void); void head2(void); void head3(void); int count; // Globalus kintamasis

// main() { int index; head1(); head2(); head3();

Pagrindin programa // index galioja tik funkcijoje main

for (index = 8; index > 0; index) { int stuff; // stuff galioja tik i skliausteli ribose for (stuff = 0; stuff < 7; stuff++) printf("%d ", stuff); printf (" indeksas = %d\n", index); } } int counter; // counter galioja tik nuo ios vietos // Pirmoji antrat void head1(void) { int index; // index galioja tik funkcijoje head1 index = 23; printf("Pirmoji antraste: %d\n", index); } // Antroji antrat void head2(void) { int count; // count galioja tik funkcijoje head2 // ir panaikina globalaus kintamojo galiojim count = 53; printf("Antroji antraste: %d\n", count); counter = 77; } // Treioji antrat void head3(void) { printf("Trecioji antraste: %d\n", counter); }

vykdius program ekrane matysime tokius rezultatus:


Pirmoji antraste: 23 Antroji antraste: 53 Trecioji antraste: 77 0 1 2 3 4 5 6 indeksas 0 1 2 3 4 5 6 indeksas 0 1 2 3 4 5 6 indeksas 0 1 2 3 4 5 6 indeksas

= = = =

8 7 6 5

10

0 0 0 0

1 1 1 1

2 2 2 2

3 3 3 3

4 4 4 4

5 5 5 5

6 6 6 6

indeksas indeksas indeksas indeksas

= = = =

4 3 2 1

Priskyrimo sakinyje panaudojome operatori = (lygybs enklas). Kiti daniausiai vartojami operatoriai parodyti 1.2 lentelje. Operacijoms ymti naudojami enklai surayti 1.3 lentelje.
1.2 lentel. Daniausiai naudojami operatoriai

Operatorius
++ += = k++ ++k k k s += k; s = k;

Pavyzdiai ir paaikinimai k reikm panaudojama, po to didinama vienetu. k reikm didinama vienetu, po to panaudojama. k reikm panaudojama, po to mainama vienetu. k reikm mainama vienetu, po to panaudojama.
s = s + k; s = s k;
1.3 lentel. Operacij enklai

Aritmetins operacijos
+ % sudtis atimtis dalybos modulis * / daugyba dalyba

== != >
&& !

Sulyginimo operacijos ar lygios dvi reikms? ar pirma maesn u antr? < ar nelygios dvi reikms? >= ar pirma nemaesn antr? ar pirma didesn u antr? <= ar pirma nedidesn u antr? Logins operacijos
login daugyba ir (and) loginis neigimas ne (not) login sudtis arba (or)

Raant aritmetines iraikas naudojami paprasti skliaustai. Standartins matematins funkcijos yra suraytos bibliotekoje math.h. 1.4 pratimas. Programoje naudojamos vairios palyginimo operacijos.
void main() { int x, y, z; char a, b, c; float r, s, t;

11

x = y = z = 11; a = b = c = 40; r = s = t = 12.987; if if if if if (x == y) z = -13; (x > y) a = 'A'; (!(x > y)) a = 'B'; (b <= c) r = 0.0; (r != s) t = c/2; printf("1. printf("2. printf("3. printf("4. printf("5. z a a r t = = = = = %d\n", %d\n", %d\n", %f\n", %f\n", z); a); a); r); t);

if (x = (r != s)) z = printf("6. x = %d z = if (x = y) z = 222; printf("7. x = %d z = if (x != 0) z = 333; printf("8. z = %d\n", if (x) z = 444; printf("9. z = %d\n",

1000; %d\n", x, z); %d\n", x, z); z); z);

x = y = z = 77; if ((x == y) && (x == 77)) z = 33; printf("10. z = %d\n", z); if ((x > y) || (z > 12)) z = 22; printf("11. z = %d\n", z); if (x && y && z) z = 11; printf("12. z = %d\n", z); if ((x = 1) && (y = 2) && (z = 3)) r = 12.00; printf("13. x = %d y = %d z = %d r = %f\n", x, y, z, r); if ((x == 2) && (y = 3) && (z = 4)) r = 14.56; printf("14. x = %d y = %d z = %d r = %f\n", x, y, z, r); if (x == x) printf("15. if (x != x) printf("16. } z z z z = = = = 1.234; %d\n", z); 5.678; %d\n", z); // visada vykdoma slyga // niekada nevykdoma slyga

Programos rezultatai:
1. 2. 3. 4. 5. 6. z a a r t x = = = = = = -13 40 66 0.000000 20.000000 1 z = 1000

12

7. x = 11 z = 222 8. z = 333 9. z = 444 10. z = 33 11. z = 22 12. z = 11 13. x = 1 y = 2 z = 3 r = 12.000000 14. x = 1 y = 2 z = 3 r = 12.000000 15. z = 1 16. z = 1

1.3. Funkcijos
Programos Pratimas1 pabaigoje parayta funkcija Atsakymas, kurios prototipas uraytas prie pagrindin funkcij main. Funkcijos prototipo uraas baigiamas simboliu ; (kabliatakis). Funkcijos aprao sintaks:
[reikms tipas] vardas ([formali parametr sraas]) { funkcijos tekstas }

Jeigu funkcijos vardui yra suteikiama reikm, jos tekste privalo bti sakinys
return reikm;

Jeigu tokio sakinio nra, funkcijai reikm nesuteikiama. Funkcijos reikms tipas yra nurodomas odiu void (tuias), jeigu funkcija negrina reikms. Reikmi neturinios C++ kalbos funkcijos atitinka kitose kalbose (pavyzdiui Paskalio) procedras. Kreipiniai tokias funkcijas programose sudaro atskirus sakinius. Jeigu funkcija neturi argument, argument sraas gali bti paliekamas tuias arba ymimas odiu void. Pavyzdiui, void Atsakymas(void); Funkcijos prototipe nra tikslo vardinti parametrus: kompiliatoriui pakanka inoti, kiek yra parametr ir kokie j tipai, todl aprae vardai gali bti praleidiami. Pagrindin funkcija main(), kuri programoje gali bti tik viena, nurodo kompiliatoriui, kur prasideda programoje vykdom veiksm apraymai. 13

Pagrindins funkcijos ir pagalbini funkcij tekstai yra sudaromi pagal tas paias taisykles. Tekst sudaro funkcijoje vartojam objekt apraai, programos vykdom skaiiavim ir valdymo sakiniai, komentarai. Funkcija skaiiavim rezultatus gali perduoti jos vartotojui dviem bdais: per parametr sra; per funkcijos vard. Norint gauti funkcijos skaiiavim rezultatus per parametr sra, reikia perduoti kreipinio metu adres vietos, kur turi bti patalpinti grinami duomenys. Adresus gali saugoti rodykls tipo parametrai (r. 26 psl.). Funkcijos prototipe nurodomi rodykls tipo parametrai, pavyzdiui: void Keisti(int *, int); ia pirmasis parametras rodo, kad kreipinio metu reikia perduoti funkcijai int tipo kintamojo adres, kai tuo tarpu antrasis parametras reikalauja reikms, kuri gali bti nurodoma kreipinio metu kaip konstanta, kintamasis ar rodykl reikm. Pavyzdiui: Keisti(&a, 5); Keisti(&a, x); Keisti(&a,*p); formas. 1.5 pratimas. Funkcija Keisti demonstruoja abi parametr Pagrindin funkcija parodo ekrane gaunamus rezultatus.
#include <iostream.h> #include <conio.h> void Keisti(int *, int); // Pagrindin programa void main() { int a = 20, b = 10, *c = &a; cout << " a b cout << "Pradines reiksmes : " << a << " " << b << " " << *c Keisti(&a, b); cout << "Po pirmo keitimo : " << a << " " << b << " " << *c Keisti(&b, 20); cout << "Po antro keitimo : " << a << " " << b << " " << *c Keisti(c, b); cout << "Po trecio keitimo : " << a << " " << b << " " << *c Keisti(&b, *c);

*c \n"; << "\n"; << "\n"; << "\n"; << "\n";

14

} // Funkcija Keisti void Keisti(int *p1, int p2) { *p1 = *p1 + 10; p2 = p2 + 10;

cout << "Po ketvirto keitimo: " << a << " " << b << " " << *c << "\n";

vykdius program ekrane matomi rezultatai:


Pradines reiksmes : Po pirmo keitimo : Po antro keitimo : Po trecio keitimo : Po ketvirto keitimo: a 20 30 30 40 40 b 10 10 20 20 30 *c 20 30 30 40 40

1.4. Duomen vedimas/ivedimas


Apraant programos ir vartotojo dialog, duomen vedimui bei ivedimui panaudojama iorini sraut bibliotekos iostream.h nukreipimo operatoriai << ir >>. Praneim ivedimui ekran yra vartojama struktra:
cout << simboli eilut

Vardas cout ymi standartin ivedimo sraut (ekran). C++ kalbos simboli eiluts yra tarp dvigub kabui (") rayti kompiuterio alfabeto ir valdani simboli rinkiniai. Valdantys simboliai gali bti terpiami bet kurioje eiluts vietoje (1.4 lentel). J sintaks: \simbolis
1.4 lentel. Valdantys simboliai

Pavadinimas Skambutis Eiluts pabaiga kit eilut kitos eiluts pradi Horizontali tabuliacija Vertikali tabuliacija Nulinis simbolis

C kalboje
\a \r \f \n \t \v \0

ASCII kodas 7 13 12 10 9 11 0

Daniausiai vartojamas valdantis simbolis \n, kuris perkelia ekrano ymekl naujos eiluts pradi. ymeklio perklimui naujos eiluts 15

pradi rekomenduojama naudoti operatori endl. Jeigu norime, kad simboli eilutje bt terptas simbolis " arba \, vartojami atitinkamai \" arba \\. Rezultat formatavimui bibliotekoje iomanip.h saugomi manipuliatoriai, kurie gali bti terpiami ivedimo srautus:
setw (n) setprecision (n)

n lauko plotis simboliais, n skaitmen skaiius.

Jei setw nurodyto lauko dydio skaiiui nepakanka, manipuliatorius ignoruojamas. Nuoroda setw galioja artimiausiai ivedamai reikmei, o setprecission iki naujo nurodymo. 1.6 pratimas. Programa demonstruoja, kaip veikia manipuliatoriai setw ir setprecission.
#include <iostream.h> #include <iomanip.h> main() { float A = 18.236; cout << "1. A=" << setw(9) << A << endl; cout << "2. A=" << setprecision(3) << A << endl; cout << "3. A=" << setw(10) << setprecision(5) << A <<endl; A = 123.45678; cout << "4. A=" << A << endl; }

Programos darbo rezultatas bus toks: 1. 2. 3. 4.


cin >> Kintamasis

A= 18.236 A=18.2 A= 18.236 A=123.46

Skaitymas i standartinio vedimo srauto (klaviatros): Klaviatroje renkami duomenys sudaro ASCII kodo simboli sraut, kurio interpretavimo bd nurodo kintamojo, kuriam nukreipiami duomenys, tipas.

16

Keli kintamj reikmes galima vesti taip:


cin >> a >> b >> c;

Be i sraut klasi, C++ kalboje yra vartojamos ir klasikins vedimo/ivedimo bibliotekos. Tokios bibliotekos yra trys: stdio.h (klasikinis buferizuotas I/O input/output), io.h (emo lygio nebuferizuotas UNIX standarto I/O), conio.h (specialios I/O funkcijos). Pratimuose analizuojamos tik bibliotekos stdio.h funkcijos. Apraant I/O operacijas, vartojama srauto svoka. Srautas tai abstrakcija, leidianti atsiriboti nuo konkretaus I/O renginio (disko, juostos, terminalo). Srautai bna dviej tip: Tekstinis srautas eilutes, atskiriamas specialiais simboliais (CR carriage return, LF line feed), suskaidyta simboli seka. Tekstinio srauto informacija nebtinai yra identika duomenims matomiems konkreiame atvaizdavimo renginyje (spausdintuve, displjuje), nes dalis simboli (CR, LF) yra skirta ne vaizdavimui, o srauto perdavimo valdymui; Dvejetainis srautas bit seka, tiksliai atitinkanti informacij konkreiame renginyje.

Kiekviena programa automatikai atidaro 5 standartinius tekstinius srautus: stdin (vedimas), stdout (ivedimas), stderr (praneimai apie klaidas), stdaux (papildomas), stdprn (spausdintuvas). Jie susiejami su standartiniais sisteminiais I/O renginiais. Daniausiai srautai stdin, stdout, stderr yra susiejami su konsole (klaviatra ir ekranas). Standartin I/O rengin galima pakeisti (perskirti) DOS priemonmis. Standartini sraut (klaviatros ir ekrano) valdymui vartojamos funkcijos printf ir scanf. J prototipai:
int printf (const char *ablonas, [<Kintamj sraas>]); int scanf(const char *ablonas, <Atminties lauk sraas>);

17

ablonas tai simboli eilut su terptais raom arba skaitom duomen formatais, kurie aprao duomenims skiriamo lauko struktr arba j interpretavimo bd. Funkcijoje scanf skaitomiems duomenims skiriami atminties laukai yra nurodomi adresais. Tipin formato struktra yra tokia: %[<Poymis>][<Lauko dydis>] [.<Tikslumas>]<Duomen tipas> Poymiai daniausiai naudojami tokie: sulygiuoti pagal kairj krat; + ivedant skaii, nurodyti jo enkl (+ ar ); Duomen tipai ymimi raidmis. Pagrindiniai tipai yra tokie: d arba i sveikasis, o atuntainis sveikasis, u sveikasis, be enklo, x eioliktainis sveikasis, c simbolinis tipas, f slankaus kablelio, s simboli eilut, e rodiklin forma, p rodykl. 1.7 pratimas. Programa iliustruoja komandos printf veikim.
void main() { int a; long int b; short int c; unsigned int d; char e; float f; double g; a b c d e f g = = = = = = = 1023; 2222; 123; 1234; 'X'; 3.14159; 3.1415926535898; a a a b = = = = %d\n", a); %o\n", a); %x\n", a); %ld\n", b); // // // // deimtainis skaiius atuntainis skaiius eioliktainis skaiius deimtainis ilgas skaiius

printf("1. printf("2. printf("3. printf("4.

18

printf("5. c = %d\n", c); printf("6. d = %u\n", d); printf("7. e = %c\n", e); printf("8. f = %f\n", f); printf("9. g = %f\n", g); printf("\n"); printf("10. a = %d\n", a); printf("11. a = %7d\n", a); printf("12. a = %7d\n", a); c = 5; d = 8; printf("13. a = %*d\n", c, a); printf("14. a = %*d\n", d, a); printf("\n"); printf("15. f = %f\n", f); printf("16. f = %12f\n", f); printf("17. f = %12.3f\n", f); printf("18. f = %12.5f\n", f); printf("19. f = %12.5f\n", f); }

// // // // //

deimtainis trumpas be enklo simbolis realus skaiius dvigubo tikslumo realus sk.

// paprastas sveikas skaiius // lauko plotis 7 simboliai // lygiuojama pagal kair krat // lauko plotis 5 simboliai // lauko plotis 8 simboliai // // // // // paprastas realus skaiius lauko plotis 12 simboli realiai daliai 3 simboliai realiai daliai 5 simboliai lygiuojama pagal kair krat

vykdius program ekrane matysime:


1. 2. 3. 4. 5. 6. 7. 8. 9. a a a b c d e f g = = = = = = = = = 1023 1777 3ff 2222 123 1234 X 3.141590 3.141593

10. 11. 12. 13. 14. 15. 16. 17. 18. 19.

a a a a a f f f f f

= 1023 = 1023 = 1023 = 1023 = 1023 = 3.141590 = 3.141590 = 3.142 = 3.14159 = 3.14159

19

1.5. Ciklai ir slygins iraikos


Ciklo while sintaks yra tokia:
while (kartojimo slyga) kartojamas sakinys;

Kartojamas sakinys yra vykdomas tol, kol kartojimo slyga yra tenkinama (true). Jei ciklo viduje kintamasis, nuo kurio priklauso kartojimo slygos nutraukimas, nra keiiamas, ciklas taps aminu. Ciklas nei karto nebus vykdomas, jeigu kartojimo slyga jau pradioje bus netenkinama (false). Jeigu cikl sudaro keletas sakini, tuomet jie skliaudiami skliaustais {}. Taip gaunamas sudtinis sakinys. 1.8 pratimas. Programa iliustruoja ciklo while veikim.
void main() { int count = 0; while(count < 6) { printf("count = %d\n", count); count++; } }

vykdius program ekrane matysime:


count count count count count count = = = = = = 0 1 2 3 4 5

Panaus yra ciklas dowhile. Jo aprao sintaks:


do kartojamas sakinys while (kartojimo slyga);

Nuo ciklo while is ciklas skiriasi tuo, kad jis visuomet bus vykdomas bent vien kart, nes kartojimo slyga tikrinama jau vykdius kartojam sakin. 1.9 pratimas. Programa iliustruoja ciklo dowhile veikim.
void main() { int i = 0; do { printf("i = %d\n", i); i++; } while(i < 5);

20

vykdius program ekrane matysime:


i i i i i = = = = = 0 1 2 3 4

Ciklo for sintaksin struktra:


for (i1; i2; i3) kartojamas sakinys;

Sakinyje nurodyta iraika i1 skaiiuojama tik vien kart, prie pradedant cikl, kuomet tikrinama, ar tenkinama i2 iraika. Jei taip vykdomas kartojimo sakinys. Iraikos i3 reikm perskaiiuojama po kartojimo sakinio vykdymo, ir grtama prie iraikos i2 tikrinimo. Taigi, galime apibendrinti, kad i1 apibria ciklo parametro pradin reikm, i2 nurodo sustojimo slyg, o i3 kitimo dsn. 1.10 pratimas. Programa iliustruoja ciklo for veikim.
void main() { int i; for(i=0; i<6; i++) printf("i = %d\n", i); }

vykdius program ekrane matysime:


i i i i i i = = = = = = 0 1 2 3 4 5

Valdymo struktros. Pradsime nuo vienos i populiariausi struktros ifelse. Jos sintaks yra tokia:
if (slyga) <aka TAIP>; else <aka NE>;

C++ kalboje nra loginio duomen tipo, todl santykiams suteikiama skaitmenin reikm, kuri yra 1, kai santykio operacija tenkinama, ir 0, 21

kai santykio operacija netenkinama. C++ kalboje slygas galima aprayti ne tik santykiais, bet ir bet kokiomis kitomis skaitmeninmis iraikomis. Jei tokios iraikos reikm yra 0, laikoma, kad slyga netenkinama, o jei reikm kitokia, laikoma, kad slyga tenkinama. Dar viena domi C++ kalbos savyb kalboje nra loginio tipo, bet logines iraikas vartoti galima. Logini iraik skaitmeniniai argumentai, kuri reikms nenulins (0), interpretuojami kaip logins reikms TRUE, o nulins (=0) laikomos reikmmis FALSE. Logini iraik reikms taip pat bna skaitmenins 0 (FALSE) ir 1 (TRUE). Programuojantiems Paskalio kalba, siloma atkreipti dmes tai, kad: C++ kalbos sakinyje if prie ak else yra raomas ; (kabliatakis). vertinant tai, kad logins reikms C++ kalboje nra, teisingas bus uraas:

if (Ats) cout << "giedras dangus!!!\n"; else cout << "danguje labai daug debesu\n";

ia else aka bus vykdoma tik esant atsakymo nulinei reikmei, kitais atvejais bus vykdoma aka TRUE. Jeigu programos vartotojas netiksliai atsakys programos klausim, tuomet is sakinys ir programos pavyzdyje esantis sakinys dirbs skirtingai. Aukiau pateiktoje programoje 1.1 pratimas else aka bus vykdoma visais atvejais, iskyrus atsakym lyg 1. 1.11 pratimas. Programa iliustruoja valdymo struktros ifelse veikim.
void main() { int data; for (data=0; data<10; data++) { if (data == 2) printf("data = %d\n", data); if (data < 5) printf("data = %d, t.y. maziau uz 5\n", data); else printf("data = %d, t.y. daugiau uz 4\n", data); } }

vykdius program ekrane matysime:


data = 0, t.y. maziau uz 5 data = 1, t.y. maziau uz 5 data = 2

22

data data data data data data data data

= = = = = = = =

2, 3, 4, 5, 6, 7, 8, 9,

t.y. t.y. t.y. t.y. t.y. t.y. t.y. t.y.

maziau uz 5 maziau uz 5 maziau uz 5 daugiau uz 4 daugiau uz 4 daugiau uz 4 daugiau uz 4 daugiau uz 4

Dar du nauji valdymo sakiniai, tai break ir continue. ie sakiniai neturi joki parametr ir daniausiai yra naudojami cikluose; break nutraukia ciklo vykdym ir veiksmai tsiami nuo pirmo sakinio, esanio u ciklo, o continue nutraukia tik vienos iteracijos vykdym ir sugrina kartojimo slygos tikrinim. 1.12 pratimas. Programa iliustruoja sakini break ir continue veikim.
void main() { int xx; for (xx=5; xx<15; xx++) { if (xx == 8) break; printf("Break ciklas; xx = %d\n", xx); } for (xx=5; xx<15; xx++) { if (xx == 8) continue; printf("Continue ciklas; xx = %d\n", xx); } }

vykdius program ekrane matysime:


Break ciklas; xx Break ciklas; xx Break ciklas; xx Continue ciklas; Continue ciklas; Continue ciklas; Continue ciklas; Continue ciklas; Continue ciklas; Continue ciklas; Continue ciklas; = 5 = 6 = 7 xx = xx = xx = xx = xx = xx = xx = xx =

5 6 7 9 10 11 12 13

23

Continue ciklas; xx = 14

switch-case struktra yra tokia:


switch (iraika) { case ym1: sakinys1; case ym2: sakinys2; default : sakinys3;

Jei iraika yra lygi ym1, bus vykdomi sakinys1, sakinys2 ir sakinys3; jei lygi ym2 sakinys2 ir sakinys3, o visais likusiais atvejais tik sakinys3. Taiau daniau i struktra yra naudojama kartu su operatoriumi break:
switch (iraika) { case ym1: sakinys1; break; case ym2: sakinys2; break; default : sakinys3; break;

iuo atveju, jei iraika lygi ym1, vykdomas tik sakinys1; jei lygi ym2 tik sakinys2, o likusiais atvejais sakinys3. 1.13 pratimas. Programa iliustruoja struktros switch-case veikim.
void main() { int i; for(i=3; i<13; i++) { switch (i) { case 3 : printf("Trys\n"); break; case 4 : printf("Keturi\n"); break; case 5 : case 6 : case 7 : case 8 : printf("Penki - astuoni\n"); break; case 11 : printf("Vienuolika\n"); break; default : printf("Neaprasyta reiksme\n"); break; } } }

24

vykdius program ekrane matysime:


Trys Keturi Penki - astuoni Penki - astuoni Penki - astuoni Penki - astuoni Neaprasyta reiksme Neaprasyta reiksme Vienuolika Neaprasyta reiksme

25

2 skyrius. Masyvai, failai, eiluts


2.1. Rodykl, adresas
Kiekvienam programoje apraytam kintamajam kompiliatorius skiria atminties lauk, kur apibdina visa grup parametr: adresas, lauko dydis, saugom duomen tipas ir reikm. Programos tekste panaudotas kintamojo vardas nurodo, kad turi bti manipuliuojama su jo reikme. Apsiriboti manipuliavimu vien tik kintamj reikmmis galima tik paprastus skaiiavimo algoritmus apraaniose programose. Sudtingesnse taikomosiose ir sisteminse programose, kuriose yra aktuals racionalaus dinaminio atminties paskirstymo, dinamini struktr sudarymo ir kompiuterio rangos valdymo fiziniame lygyje klausimai, tenka manipuliuoti ne tik atmintyje saugomomis kintamj reikmmis, bet ir j adresais. Adres reikmi saugojimui yra skirtos rodykls, kuri apra sintaks:
lauko tipas *rodykls vardas

Programos tekste struktra *rodykls vardas reikia, kad turi bti vartojama rodykls rodomo lauko reikm. Paioms rodyklms gali bti suteikiamos tik to paties tipo objekt, kuriems buvo apibrtos rodykls, adres reikms. Pavyzdys: int x, *px;
px = &x;

Priskyrimo operatorius px = &x rodyklei px suteikia kintamojo x adreso reikm, todl x reikm dabar galima kreiptis tiek vardu x, tiek struktra *px. Rodykls tipo kintamiesiems btina nurodyti pradin reikm, kuri daniausiai bna tuias adresas: px = NULL. 2.1 pratimas. Programa iliustruoja, kaip naudojamos rodykls. Kintamieji pt1 ir pt2 yra rodykls (tai rodo vaigduts prie juos). Ura &index galime skaityti kaip kintamojo index adresas. O realiai ioje programoje yra tik vienas kintamasis, kurio reikm keiiame. 26

main() { int index, *pt1, *pt2; index = 39; pt1 = &index; pt2 = pt1; printf("index *pt1 *pt2"); printf("%4d %4d %4d\n", index, *pt1, *pt2); *pt1 = 13; printf("%4d %4d %4d\n", index, *pt1, *pt2); }

vykdius program ekrane matysime:


index *pt1 *pt2 39 39 39 13 13 13

2.2. Vienmatis masyvas


Labai glaudiai su rodyklmis yra susijs masyvo tipas, kuris yra skirtas vienodo tipo duomen (element) rinkiniams saugoti. Masyv apra sintaks:
element tipas masyvo vardas [element skaiius]

iame aprayme skliaustai [ ] yra btini struktros elementai. Masyvo narius ymi kintamieji su indeksais, kuri vard sintaks:
masyvo vardas[indeksas]

Pavyzdiui, masyvo apraas: int A[10]; masyvo elementas: A[5]. Indeksais gali bti tik intervalo [0, n-1] sveikosios reikms (n masyvo element skaiius). Pastaba: Masyvo vardas be indekso reikia jo nulinio elemento adres. 2.2 pratimas. Programa demonstruoja situacij, kai gretimuose atminties laukuose surayti vienodo tipo duomenys (a, b, c, d) panaudoti masyvo formavimui. Pradi nurodo pirmojo kintamojo adresas: pi = &a;
#include <iostream.h> int a=1, b=2, c=3, d=4, *pi;

27

main() { int i = 0, mas[4]; pi = &a; // Kintamojo a adresas while(i<4) mas[i++] = *(pi++); // Masyvo formavimas // Masyvo ivedimas ekran atvirkia tvarka while(i) cout << mas[--i] << "\t"; cout << endl; }

Kai reikmi didinimo ar mainimo operacijos yra taikomos rodyklms, j reikms yra keiiamos ne vienetu, o su rodykle susieto lauko dydiu. i rodykli savyb pavyzdio programoje yra panaudota kintamj grups a, b, c, d reikmi perrinkimui. Papildykite program taip, kad ji parodyt ekrane vis joje vartojam kintamj ir masyvo mas element adresus. Apraant adres ivedim, naudokite rodykli ablon %p. Adresai bus ivedami eioliktainje skaiiavimo sistemoje. 2.3 pratimas. Reikia surasti masyvo element sum. Duomenys vedami klaviatra. Reikmms sumuoti padaroma funkcija, kuri rezultat grina funkcijos vardu. Funkcijai perduodamas masyvo pirmojo elemento adresas: A (galima rayti &A[0]).
#include <iostream.h> int Suma(int *, int); // Pagrindin programa void main() { int A[10], i, n; // A[0], A[1], ... , A[9] cout << "Iveskite n reiksme: "; cin >> n; for (i=0; i<n; i++) { cout << "A[ " << i << " ]= "; cin >> A[i]; } cout << " Suma = " << Suma(A, n) << endl; } // Funkcija Suma int Suma(int *pr, int k) { int S = 0, i = 0; while(i<k) { S += *(pr+i); i++; } return S; }

28

2.3. Dinaminis atminties iskyrimas


Dirbant su masyvais btina sitikinti, kad norimas duomen skaiius tilps kompiuterio atmintyje. Galimi keli bdai iskirti atminiai. Vienas paprasiausi yra funkcija:
void *malloc(Kiekis);

ia nurodomas praomos atminties Kiekis baitais. Jeigu atmintis buvo skirta, tai grinama rodykl pirmj tos atminties bait, kitaip funkcijos reikm yra NULL. Kreipinio metu atminties kiek patogu nurodyti kaip duomen element skaiiaus ir vieno elemento uimamos vietos baitais sandaug, pavyzdiui: n * sizeof(float) kur n reali skaii kiekis, o funkcija sizeof grina nurodyto duomen tipo (ia realaus) apimt baitais. Funkcija malloc grina rodykl nurodyto tipo atmint: kreipinio metu nurodomas rodykls tipas. 2.4 pratimas. Klaviatra vedamas duomen skaiius. Jeigu duomenims saugoti yra vietos atmintyje, tai duomenys vedami klaviatra masyv, kurio rodykl yra saugoma kintamuojame A. Toliau duomenys surikiuojami majimo tvarka.
#include <iostream.h> #include <alloc.h> // Atminties skyrimas ir duomen vedimas int *Duomenys(int); void Tvarka (int *, int); // Rikiavimas void Sp (int *, int); // Ivedimas ekrane // Pagrindin programa void main() { int n, *A; cout << "Iveskite n reiksme: "; cin >> n; A = Duomenys(n); if (A != NULL) { cout << " n= " << n << endl; cout << " Ivestas masyvas:\n"; Sp(A, n); Tvarka(A, n); cout << " Sutvarkytas masyvas:\n";

29

Sp(A, n); free(A); } // Masyvo uimama atmintis atlaisvinama cout << endl; } // Duomen vedimas int *Duomenys(int n) { int *x, i; x = (int *) malloc(n * sizeof(int)); if (x == NULL) cout << "Truksta atminties" << endl; else { for(i=0; i<n; i++) { cout << "Iveskite " << (i+1) << "-a elementa "; cin >> *(x+i); } cout << endl; } return x; } // Rikiavimas void Tvarka(int *x, int n) { int i, j, c; for(i=0; i<n-1; i++) for(j=i+1; j<n; j++) if (*(x+j) > *(x+i) ) { c = *(x+i); *(x+i) = *(x+j); *(x+j) = c; } } // Ivedimas ekrane void Sp(int *x, int n) { int i = 0; while(i < n) { cout << (i+1) << "-elementas: " << *(x+i) << endl; i++; } }

Atminties iskyrimui patogu naudoti operatori new. Pakeiskite 2.3 pratimo funkcijos Duomenys eilut:
x = (int *) malloc(n * sizeof(int));

nauja eilute:
x = new int[n];

Ibandykite program. dvimaiams masyvams. 30

Isiaikinkite

new

galimybes,

taikym

2.4. Dvimatis masyvas


Dvimaio masyvo (matricos) apraas:
duomen tipas masyvo vardas [eilui skaiius] [stulpeli skaiius];

Pavyzdiui, uraas int A[10][8] rodo, kad bus 10 eilui (0, 1, 2, , 9) ir kiekviena j turs po 8 elementus (stulpeliai 0, 1, 2, , 7). Matricos elementas veiksmuose nurodomas dviem indeksais, kurie raomi atskiruose lautiniuose skliaustuose: A[2][3]. Sudtingesniuose udaviniuose tikslinga sukurti savo duomen tipus. Masyvo tipas sukuriamas taip: typedef vardas Pavyzdiui:
typedef int Masyvas [55]; typedef float Matrica [10][15]; const Kiek = 15 typedef double Lentele [Kiek][Kiek];

masyvo

element

tipas

masyvo

tipo

indeks apraas;

ia buvo sukurti fiksuotos apimties masyv tipai. Dabar galima aprayti kelet to paties tipo masyv: Masyvas A, B, C;
Matrica P, D, R; Lentele Pirma, Antra;

2.5 pratimas. Klaviatra vedami duomenys, kurie saugomi matricoje. Suskaiiuojama matricos kiekvienos eiluts element suma. Rezultatai suraomi vienmat masyv.
#include <iostream.h> #include <alloc.h> typedef int mas [10]; typedef int matr[10][15]; int Duomenys(matr, int *, int *); void Sp (mas, int); int Suma (mas, int); // Duomen vedimas // Spausdinimas // Masyvo element suma

31

// Pagrindin programa void main() { matr A; mas S; int n, m, i, j; Duomenys(A, &n, &m); // Duomen vedimas klaviatra if (A != NULL) { cout << "----------------------\n"; for (i=0; i<n; i++) // Matricos spausdinimas for (j=0; j<m; j++) cout << A[i][j] << endl; cout << "----------------------\n"; for (i=0; i<n; i++) { // Matricos spausdinimas cout << "Eilute Nr " << (i+1) <<": "; Sp(A[i], m); } // Vienos eiluts spausdinimas cout << "----------------------\n"; // Skaiiavimai for (i=0; i<n; i++) S[i] = Suma(A[i], m); Sp (S, n); } // Suformuoto masyvo spausdinimas cout << endl;

} // Duomen vedimas int Duomenys(matr D, int *n, int *m) { int i, j; cout << "Iveskite n reiksme: "; cin >> *n; cout << "Iveskite m reiksme: "; cin >> *m; for (i=0; i<*n; i++) { cout << "Eilute Nr:" << (i+1) << endl; for (j=0; j<*m; j++) { cout << "Iveskite " << (j+1) << "-a elementa "; cin >> D[i][j]; } } cout << endl; return 1; } } // Spausdinimas void Sp(mas x, int n) { int i = 0; while (i<n) cout << x[i++] << " " << endl; } // Masyvo element sumos skaiiavimas int Suma(mas D, int k) { int i, Sk=0; for (i=0; i<k; i++) Sk += D[i]; return Sk; }

32

Galima turti funkcij, Ibandykite i funkcij:

kuri

suformuot

rezultat

masyv.

// funkcijos prototipas void Suma (mas, matr, int, int);

i funkcija, vis matricos eilui element sumas surao vienmat masyv, kurio vardas nurodomas kreipinio metu pirmuoju parametru.
void Suma(mas R, matr D, int eil, int st ) { int i, j; for (i=0; i<eil; i++) { *(R+i) = 0; for(j=0; j<st; j++) *(R+i) += D[i][j]; } }

2.5. Duomen failai


Apdorojant didesns apimties duomen srautus, patogu duomenis saugoti failuose. Failo kintamieji apraomi tipo FILE rodykle:
FILE *F;

Failai paruoiami darbui funkcija, kurios prototipas toks:


#include <stdio.h> FILE *fopen(const char *FailoVardas, const char *M);

ia FailoVardas nurodomas kaip simboli eilut: konstanta tarp kabui, arba konstantos vardu, arba kintamuoju, turiniu t reikm. Failo paruoimo darbui bvis nurodomas antruoju parametru M (simbolin eilut: konstanta, jos vardas arba kintamasis). Galimos bvio reikms suraytos 2.1 lentelje.
2.1 lentel. Failo paruoimo darbui bsenos

r w a

tik skaitymui; tik raymui; jeigu failas egzistavo, tai naikinamas ir sukuriamas naujai; papildymui gale; jeigu failo nebuvo, tai sukuriamas;

Bvio reikm papildius raide t (rt, wt, at), failas bus paruoiamas darbui kaip tekstinis. Bvio reikm papildius raide b (rb, wb, ab), failas bus paruoiamas darbui kaip binarinis. Jeigu nebus panaudota nei t, nei b raids, tai failas bus atidaromas darbui priklausomai nuo globalinio kintamojo fmode reikms (r. fcntl.h). Kiekvienas bvio variantas 33

gali bti papildytas enklu + (plius) (pvz.: r+, w+, wt+). Tai reikia, kad failai paruoiami atnaujinimui (leidiama skaityti ir rayti). Toliau pristatome pagrindini buferizuot I/O funkcij prototipus.
int fclose(FILE *rod); int putc(int simbolis, FILE *rod); int getc(FILE *rod); int putw(int sk, FILE *rod); int getw(FILE *rod); // //

failo udarymas simbolio raymas skaiiaus raymas

// simbolio skaitymas //

// skaiiaus skaitymas

char *fgets(char *s, int n, FILE *rod); // skaito eilut s i n simboli int fputs(const char *s, FILE *rod); //

eiluts s raymas

int fread(void *buf, int t, int n, FILE *rod); // siunia n po t bait turini blok i failo rod bufer buf;

// funkcijos reikm rodo perskaityt blok skaii


int fwrite(void *buf, int t, int n, FILE *rod); // Siunia n po t bait turini blok i buferio buf fail rod;

// funkcijos reikm rodo perskaityt blok skaii


int fprintf(FILE *rod, const *char f [,<sraas>]); // fail rod, naudojant ablon f, raomi srao elementai;

// ablonas ir argument sraas sudaromi taip, kaip ir funkcijai // printf


int fscanf(FILE *rod, const *char f [,<sraas>]);

// skaitymas pagal ablon. Funkcijos reikm // skmingai perskaityt element skaiius


int feof(FILE *rod); // failo pabaiga nenulin funkcijos reikm int ferror(FILE *rod); //

klaida nenulin funkcijos reikm


//

int remove(const *char vardas);

alinamas failas

Fail apdorojimo programoms apdorojam fail vardai gali bti perduodami pagrindins funkcijos parametrais. Funkcijos prototipas:
int main(int n, char *argv[ ]);

34

ia n argument skaiius, o argv argumentams skirto eilui masyvo rodykl. Argument reikms yra nurodomos programos ikvietimo komandoje ir yra atskiriamos tarpais. Nulin argument masyvo eilut tai paios programos pavadinimas. 2.6 pratimas. Duomen faile duom6.dat surayti skaiiai. Reikia duomenis i failo surayti masyv ir atspausdinti ekrane. Suskaiiuoti masyvo element sum ir atspausdinti ekrane.
#include #include #include #include <io.h> <stdio.h> <iostream.h> <conio.h>

const Kiek = 15; typedef int mas [Kiek]; FILE *F; void Sp (mas, int); // Spausdina masyv int Suma (mas, int); // Sumuoja masyvo elementus // Pagrindin programa void main() { mas A; int n = 0; F = fopen("duom6.dat", "r"); if (F == NULL) printf("Failas neatidarytas"); else { while (!feof(F) && ( n < Kiek)) { fscanf(F, "%d", &A[n]); n ++; } Sp(A, n); printf("Suma=%5d\nPabaiga", Suma(A, n)); }

} // Spausdina masyv void Sp(mas X, int n) { int i = 0; while (i<n) cout << X[i++] << " " << endl; } // Sumuoja masyvo elementus int Suma(mas R, int k) { int i = 0, S = 0; while (i<k) S += R[i++]; return S; }

35

2.7 pratimas. Duomen faile duom7.dat surayti skaiiai. Reikia duomenis i failo surayti masyv. Masyvo element reikms atspausdinamos kitame faile.
#include #include #include #include #include <iostream.h> <stdio.h> <alloc.h> <conio.h> <stdlib.h>

const Kiek = 10; typedef int mas [Kiek]; void SpF(mas, int, char); // Masyvo element ivedimas fail int Ivesti(mas, int *); // Skaitymas i failo // Pagrindin programa void main() { mas A; int n = 0; if (Ivesti(A, &n)) { cout << "\nDuomen failo nra\n"; getch(); exit(1); } SpF(A, n, 'A'); } // Skaitymas i failo int Ivesti(mas A, int *n) { FILE *F; F = fopen("duom7.dat", "r"); if (F == NULL) { printf( "Failas neatidarytas"); return 1; } else { while(!feof(F) && (*n < Kiek)) { fscanf(F, "%d", &A[*n]); n++; } // Borland C++4.5 realizacijoje raoma (*n)++ fclose(F); return 0; } } // Masyvo element ivedimas fail void SpF(mas X, int n, char R) { FILE *F; int i = 0; F = fopen("duom7.rez", "w");

36

if (F == NULL) printf("Failas neatidarytas spausdinimui"); else { while (i<n) fprintf(F, "%c[%2d]=%4d\n", R, i, X[i++]); fclose(F); } }

Duomen failas: Duom7.dat 5 6 98 -5 12 3 4 5 21 -3 4 5 23 1 23 34 45 5 6 -123

Rezultat failas: Duom7.rez


A[ 1]= A[ 2]= A[ 3]= A[ 4]= A[ 5]= A[ 6]= A[ 7]= A[ 8]= A[ 9]= A[10]= 5 6 98 -5 12 3 4 5 21 -3

Duomen vedimo funkcijoje Ivesti skaitymo cikl pakeiskite tokiu:


while((fscanf(F, "%d", &A[*n]) != EOF ) && (*n < Kiek)) *n++;

Dabar duomen vedimo funkcijoje skaitymo cikl pakeiskite tokiu:


while((fscanf(F, "%d", &A[*n]) != EOF ) && (*n++ < Kiek));

Palyginkite visus tris variantus ir pasirinkite, kuris Jums suprantamiausias. Silome programas rayti paprastesnes ir aikesnes, nes jas lengviau ir greiiau suvokti ne tik Jums, po kurio laiko modifikuojant, bet ir kitiems, turintiems maiau praktinio programavimo gdi. 2.8 pratimas. Duomen faile suraytos tak, esani koordinai ploktumoje, koordinats (x, y). Reikia duomenis surayti matric, kur pirmame stulpelyje bt tak x koordinats, antrame stulpelyje y koordinats. Parayti funkcij, kuri matricos treiame stulpelyje surayt tak atstumus iki koordinai pradios tako. Ketvirtame stulpelyje paymti, kokiam ketviriui takas priklauso. Nuliuku ymti takus, esanius ant ai. Rezultat faile atspausdinti 37

matricos duomenis, uraant kiekvieno stulpelio prasm nusakanius pavadinimus ir numeruojant eilutes. Gale parayti, kiek kuriame ketvirtyje yra tak, ir kiek yra tak ant ai.
#include #include #include #include #include #include #include <iostream.h> <stdio.h> <alloc.h> <conio.h> <stdlib.h> <math.h> <time.h>

typedef float mas[][4]; const char *Duomenys = "Duom8.dat"; const char *Rezultatai = "Duom8.rez"; void RezFailas(); // int Failas(); // mas *Ivesti(int); // void Spausdinti(mas *, int, int); // void Atstumai(mas *, int); // void Vieta(mas *, int); // // Pagrindin programa void main() { mas *A; int n; RezFailas(); if((n = Failas()) == 0) { cout<<" Duomenu nerasta\n"; getch(); exit(0); } A = Ivesti(n); if (A == NULL) { cout<<"NERA NERA \n"; getch(); exit(1); } cout << "Masyvas ivestas n = "<< n Spausdinti(A, n, 0); Atstumai(A, n); Spausdinti(A, n, 1); Vieta(A, n); Spausdinti(A, n, 2); } Rezultat failo paruoimas Randa kiek yra duomen Duomen vedimas Rezultat spausdinimas Tak atstumai
Tak padtis ploktumoje

<< endl;

38

// Paruoia rezultat fail. Urao dat ir laik void RezFailas() { FILE *F; char Data[9], Laikas[9]; if(F = fopen(Rezultatai, "w")) { _strdate(Data); _strtime(Laikas); fprintf(F, "%s %s\n", Data, Laikas); fclose(F); } } // Patikrina, ar yra duomen failas ir kiek jame tak int Failas() { FILE *F; int n = 0, k; if ((F = fopen(Duomenys, "r")) == NULL ) { cout << "Duomenu failo nera\n"; return 0; } while(!feof(F)) { n++; fscanf(F, "%d%d\n", &k, &k); } fclose(F); return n; } // Skaito duomenis i failo masyv mas *Ivesti(int n) { FILE *F; mas *A; if ((F = fopen(Duomenys, "r")) == NULL) { cout << "Duomenu failas neatidarytas\n"; getch(); return NULL; } A = (mas *) malloc(n*4*sizeof(float)); if(A == NULL) { cout << "Truksta masyvui atminties\n"; getch(); return NULL; } n = 0; while(!feof(F)) { fscanf(F, "%f%f\n", &(*A)[n][0], &(*A)[n][1]); n++; } fclose(F); return A; }

39

// Spausdina duomenis ir rezultatus /* Raktas k valdo: kai 0, spausdina tik tak koordinates (duomenis); kai 1, spausdina duomenis ir tak atstumus iki koordinai pradios tako; kai 2, spausdina duomenis, atstumus ir tak vietas koordinai ploktumoje.*/ void Spausdinti(mas *C, int n, int k) { FILE *F; int i; if ((F = fopen(Rezultatai, "a")) == NULL) { cout << "Rezultatu failas neatidarytas\n"; getch(); return; } switch(k) { case 0: fprintf(F, "Duomenys\n"); fprintf(F, "*********************\n"); fprintf(F, " Nr. x y \n"); break; case 1: fprintf(F, "\nDuomenys ir atstumai iki koord. pradzios\n"); fprintf(F, "******************************\n"); fprintf(F, " Nr. x y Atstumas \n"); break; case 2: fprintf(F, "\nDuomenys, atstumai ir tasko vieta koord. plokstumoje\n");
fprintf(F, "**************************************\n"); fprintf(F, " Nr. x y Atstumas Vieta \n");

break; } for(i=0; i<n; i++) { switch(k){ case 0: fprintf(F," %3i %7.2f %7.2f \n", i+1, (*C)[i][0],(*C)[i][1]); break; case 1: fprintf(F, "%3i %7.2f %7.2f %7.2f \n", i+1, (*C)[i][0],(*C)[i][1],(*C)[i][2]); break; case 2: fprintf(F, "%3i %7.2f %7.2f %7.2f %7.2f \n", i+1, (*C)[i][0],(*C)[i][1],(*C)[i][2],(*C)[i][3]); break; }} switch(k) {

40

} // Skaiiuojami tak atstumai iki koordinai pradios tako void Atstumai(mas *D, int n) { float x, y; for (int i = 0; i<n; i++) { x = (*D)[i][0]; y = (*D)[i][1]; (*D)[i][2] = sqrt(x*x + y*y); } } // Nustatoma tako padtis koordinai ploktumoje /* 14 nurodo ketvirio numer, o 0 kad takas yra ant vienos i ai. */ void Vieta(mas *D, int n) { float x, y; for (int i=0; i<n; i++) { x = (*D)[i][0]; y = (*D)[i][1]; if ((x>0) && (y>0)) (*D)[i][3] = 1; else if ((x>0) && (y<0)) (*D)[i][3] = 4; else if ((x<0) && (y>0)) (*D)[i][3] = 2; else if ((x<0) && (y<0)) (*D)[i][3] = 3; else (*D)[i][3] = 0; } }

} fclose(F);

case 0: fprintf(F, "*********************\n"); break; case 1: fprintf(F, "******************************\n"); break; case 2: fprintf(F, "**************************************\n"); break;

Duomen failo pavyzdys:


15 13 -15 -22 0 5 -5 0 -1 12 -5 -45 22 5 0 0 -5 -1

41

Rezultat failo pavyzdys:


06/08/99 21:48:34 Duomenys ********************* Nr. x y 1 15.00 12.00 2 13.00 -5.00 3 -15.00 -45.00 4 -22.00 22.00 5 0.00 5.00 6 5.00 0.00 7 -5.00 0.00 8 0.00 -5.00 9 -1.00 -1.00 ********************* Duomenys ir atstumai iki koord. pradzios ****************************** Nr. x y Atstumas 1 15.00 12.00 19.21 2 13.00 -5.00 13.93 3 -15.00 -45.00 47.43 4 -22.00 22.00 31.11 5 0.00 5.00 5.00 6 5.00 0.00 5.00 7 -5.00 0.00 5.00 8 0.00 -5.00 5.00 9 -1.00 -1.00 1.41 ****************************** Duomenys, atstumai ir tasko vieta koord. plokstumoje ************************************** Nr. x y Atstumas Vieta 1 15.00 12.00 19.21 1.00 2 13.00 -5.00 13.93 4.00 3 -15.00 -45.00 47.43 3.00 4 -22.00 22.00 31.11 2.00 5 0.00 5.00 5.00 0.00 6 5.00 0.00 5.00 0.00 7 -5.00 0.00 5.00 0.00 8 0.00 -5.00 5.00 0.00 9 -1.00 -1.00 1.41 3.00 **************************************

42

2.9 pratimas. Naudodamiesi C++ aplinkos pagalbine informacija (Ctrl+F1) isiaikinkite, kaip sudaryta struktrizuoto tekstinio failo Duom9.txt papildymo programa. Failo eilutse yra saugomi duomenys apie vairiems asmenims priklausanius telefonus. Duomen elementams yra skiriamos tokios eilui atkarpos: pavard [1, 20], vardas [21, 40], telefono numeris [41,50]. Sukurkite tokios struktros fail ir patikrinkite program. Programos vykdymo pabaigos slyg isiaikinkite nagrindami jos tekst.
#include #include #include #include <string.h> <stdio.h> <stdlib.h> <conio.h>

FILE *failas; char buf[50], e1[20], e2[20], e3[10]; const char vardas[] = "Duom9.txt"; int Init (const char *, char *); void Duomenys(FILE *); void Rodyti (FILE *); // Pagrindin programa void main() { buf[0] = '\0'; if (!Init(vardas, "a")) exit(1); // Failo paruoimas darbui Duomenys(failas); // Duomenys vedami klaviatra fail fclose(failas); if (!Init(vardas,"r")) exit(1); //Failo paruoimas skaitymui Rodyti(failas); // Duomenys siuniami ekran fclose(failas);

} // Naujo failo atidarymas skaitymui/raymui arba seno papildymui int Init (const char *v, char *mode) { if ((failas = fopen(v, mode)) == NULL) { // Failo nebuvo // Naujo sukurti nepavyko if ((failas = fopen(v, "w+")) == NULL) { fprintf(stderr, "Atidaryti fail raymui/skaitymui nepavyko.\n"); return 0; } // Klaidos poymis else return 1; } // Naujai sukurtas failas else return 2; // Surastas failas ir atidarytas }

43

// Duomenys vedami klaviatra fail void Duomenys(FILE *failas) { int i; while(buf[0] != 'q') { buf[0]= '\0';
// vedimo pabaiga nurodoma eilute, kurios pirmas simbolis yra 'q' // Struktrizuotos eiluts sudarymo ir raymo ciklai

} // Duomenys siuniami ekran void Rodyti(FILE *) { while(fgets(buf, strlen(buf)+1, failas)) printf("%s",buf); }

printf("Nurodykite pavarde, varda ir telefono numeri:\n"); scanf("%s %s %s", e1, e2, e3); strcat(buf, e1); for(i=strlen(buf); i<20; i++) strcat(buf, " "); strcat(buf, e2); for(i=strlen(buf); i<40; i++) strcat(buf, " "); strcat(buf, e3); strcat(buf, "\n"); if (buf[0] != 'q') fwrite(buf, strlen(buf), 1, failas); }

Sudarykite pagalbin funkcij buferinio kintamojo buf papildymui formatuotais laukais. Pakeiskite programoje blok raymo komand fwrite eilui raymo komanda fputs. Pakeiskite program taip, kad jos darb bt galima nutraukti vedus vieno simbolio eilut: "Q" arba "q". Norint tai padaryti, reikia i klaviatros perskaityti i karto vis eilut ir tik po to j skanuoti su funkcija sscanf. 2.10 pratimas. Panaudodami duomen sraut apdorojimo klas ofstream vedame duomenis matric ir atlik veiksmus (sukeiiami vietomis stulpeliai su didiausia ir maiausia matricos reikme) ivedame rezultatus.
#include #include #include #include <fstream.h> <stdio.h> <stdlib.h> <iomanip.h>

44

const num = 15; typedef int matr[num][num]; void read(char *, matr, int *); // Duomen skaitymas void print(char *, matr, int, char *); // Spausdinimas int max(matr, int); // Didiausio paieka int min(matr, int); // Maiausio paieka void swap(matr, int, int, int); // Stulpeli sukeitimas int test(char *, char *); // Fail paruoimas // Pagrindin programa void main(void) { int n; matr a; char inbuff[12], outbuff[12]; // Fail vardams saugoti // Rodykls fail vardus *duom ir *rezult cout << "Koks duomenu failo vardas?\n"; char *duom = gets(inbuff); cout << "Koks rezultatu failo vardas?\n"; char *rezult = gets(outbuff); if (test(duom, rezult)) { cout << "Klaida atidarant failus"; exit(0); } read(duom, a, &n); // Duomen skaitymas matric // Duomen spausdinimas fail print(rezult, a, n, "Pradiniai duomenys"); swap(a, n, min(a, n), max(a, n)); print(rezult, a, n, "Rezultatai"); // Rezultat spausdinimas cout << "Pabaiga\n\a"; } // Duomen skaitymas void read(char *is, matr a, int *n) { ifstream infile(is); // Duomen failo atidarymas infile >> *n; // vedama n reikm (*n)--; // Matricos vedimas for(int i=0; i<=*n; i++) for(int j=0; j<=*n; j++) infile >> a[i][j]; infile.close(); // Failo udarymas } // Spausdinimas void print(char *os, matr a, int n, char *text) { // Rezultat failas paruoiamas papildymui ofstream offile(os, ios::app);

45

} // Randamas stulpelis su didiausia reikme int max (matr a, int n) { int m = -1000, p = -1; // p - stulpelio numeris for(int i=0; i<=n; i++) for(int j=0; j<=n; j++) if (a[i][j] > m) { m = a[i][j]; p = j; } return p; } // Randama maiausia reikm int min(matr a, int n) { int m = 1000, p = -1; // p - stulpelio numeris for(int i=0; i<=n; i++) for(int j=0; j<=n; j++) if (a[i][j] < m) { m = a[i][j]; p = j; } return p; } // Sukeiiami du stulpeliai vietomis void swap(matr a, int n, int mine, int maxe) { int p; for(int i=0; i<=n; i++) { p = a[i][mine]; a[i][mine] = a[i][maxe]; a[i][maxe] = p; } } // Pagrindin programa int test(char *is, char *os) { ifstream duomenys(is); // Patikrinamas duomen failas if (!duomenys) return 1; duomenys.close(); ofstream rezultatai(os); // Patikrinamas rezultat failas if (!rezultatai) return 1; // rezultat fail ivedamas praneimas rezultatai << "Matrica \n"; rezultatai.close(); return 0;

offile << '\n' << text << '\n' << " "; for(int j=1; j<=n+1; j++) offile << setw(5) << j; offile << " \n |"; for(j=0; j<=n; j++) offile << "-----"; offile << " \n"; for(int i=0; i<=n; i++) { offile << setw(3) << (i+1) << " |"; for(int j=0; j<=n; j++) offile << setw(5) << a[i][j]; offile << " \n"; }

46

} Duomen failas 4 15 1 5 6 2 25 6 7 5 -5 5 -45 1 2 3 4 Rezultat failas Matrica Pradiniai duomenys 1 2 3 4 |-------------------1 | 15 1 5 6 2 | 2 25 6 7 3 | 5 -5 5 -45 4 | 1 2 3 4 Rezultatai 1 2 3 4 |-------------------1 | 15 6 5 1 2 | 2 7 6 25 3 | 5 -45 5 -5 4 | 1 4 3 2

2.6. Simboli eiluts


Simboli masyvai gali bti vartojami simboli eilutms apdoroti. Naudojant masyvus simboliams saugoti, reikia atsiminti, kad C++ kalboje eilui reikmi pabaigas priimta ymti nulinio ASCII kodo simboliu, kuris ymimas '\0'. Simbolinio tipo konstantos taip pat yra raomos tarp apostrof, pavyzdiui 'a', 'D'. Eiluts tipo konstantos raomos tarp kabui, pavyzdiui, "Katinas". 2.11 pratimas. Klaviatra vedamas odis (simboli eilut be tarp). Programa vestoje simboli eilutje visas masias raides keiia didiosiomis.
#include <iostream.h> #include <conio.h> void main() { char Eil[80]; int i, c; c = 'a' - 'A'; // Atstumas tarp raidi kod lentelje cout << "veskite eilut maosiomis raidmis ir be tarp\n"; cin >> Eil; for(i=0; Eil[i] != '\0'; i++)

47

if (Eil[i] >= 'a') cout << Eil << endl;

Eil[i] -= c; }

Sudarykite program, kuri skaiiuot ir parodyt ekrane vis klaviatra vestos eiluts lotynik raidi pasikartojimo danius. Didiosios ir maosios raids turi bti interpretuojamos vienodai. Neumirkite, kad C kalboje char ir int tipai yra suderinami Prie nagrindami tolesnius pavyzdius, apvelgsime kelias funkcijas, palengvinanias darb su eilutmis.
char *strcpy(char *dest, const char *src); Eilut src kopijuoja dest iki nulinio simbolio. Grina rodykl dest. char *stpcpy(char *dest, const char *src); Eilut src kopijuoja eilut dest iki nulinio simbolio. Grina dest + strlen(src). char *strcat(char *dest, const char *src); Eiluts src kopij prijungia prie eiluts dest galo. Grina rodykl sujungtas eilutes (dest). Grinamos eiluts ilgis yra: strlen(dest) + strlen(src). const char *strchr(const char *s, int c); char *strchr( char *s, int c); Eilutje s ieko simbolio c. Paieka pradedama nuo eiluts pradios ir

baigiama suradus pirmj simbol, lyg nurodytam. Nulinis simbolis laikomas eiluts dalimi, todl jo paieka taip pat galima. Pavyzdiui, strchr(strs,0) grina rodykl nulin simbol. Funkcija grina rodykl surast simbol eilutje, arba NULL neradus. 2.12 pratimas. Programa iliustruoja funkcijos strchr veikim.
#include <string.h> #include <stdio.h> int main(void) { char string[20]; char *ptr, c = 'r'; strcpy(string, "Nagrinelama eilute"); ptr = strchr(string, c); if (ptr) printf("Simbolis %c yra: %d-as\n", c, ptr-string); else printf("Tokio simbolio eiluteje nera\n");

48

return 0; }

vykd program, ekrane matysime eilut:


Simbolis r yra: 3-as

Pertvarkykite program taip, kad ji ivardyt ekrane visas dialogo su vartotoju metu nurodytos raids pozicijas klaviatra vestoje eilutje.
int strcmp(const char *s1, const char *s2);

Palygina eilutes. Lygina eilutes, pradedant pirmaisiais simboliais iki tol, kol bus surasti nesutampantys simboliai arba bus surasta vienos i eilui pabaiga. Jeigu s1 yra... maesn u eilut s2 lygi eilutei s2 didesn u eilut s2 strcmp grina reikm, kuri yra...
< 0 == 0 > 0

int strcmpi(const char *s1, const char *s2);

Palygina eilutes, kaip ir ankstesn, tik masias ir didisias raides laiko vienodomis.
size_t strlen(const char *s);

Grina simboli skaii eilutje. Nulinis simbolis neskaiiuojamas.


char *strncpy(char *dest, const char *src, size_t maxlen);

Kopijuoja i eiluts src eilut dest nurodyt simboli skaii maxlen. Jeigu eilutje src simboli maiau, negu nurodytas kiekis maxlen, tuomet rezultate bus tiek, kiek surasta; jeigu daugiau negu reikia, tai tiek kiek nurodyta. Grinama rodykl dest eilut. 2.13 pratimas. Programa iliustruoja funkcijos strncpy veikim.
#include <stdio.h> #include <string.h> int main(void) { char string[10]; char *str1 = "abcdefghi"; strncpy(string, str1, 3); string[3] = '\0'; printf("%s\n", string);

49

return 0; }

vykd program, ekrane matysime eilut:


abc

char *strtok(char *s1, const char *s2); Funkcija grina rodykl s1 fragment (od) i simboli, kuri nra eilutje s2, o u fragmento terpia nulinio kodo simbol. Kartojant kreipin su NULL vietoje pirmo argumento, grinama rodykl kit od. Kai nauj odi nebra, grinama rodykl NULL. 2.14 pratimas. Programa iliustruoja funkcijos strtok veikim.
#include <string.h> #include <iostream.h> #include <conio.h> void main() { char Eil[30] = "Joju, dairausi ir dainuoju"; char *p, sep[5]= ", "; cout << Eil << endl; // Visa tiriama eilut // strtok terpia ribotuv NULL u surasto odio p = strtok(Eil, sep); if (p) cout << p << endl; // Pirmasis odis // Antras kreipinys su argumentu NULL grina antro odio adres p = strtok(NULL, sep); if (p) cout << p << endl; // Antrasis odis cout << Eil << endl; // Tik pirmasis odis }

vykd program, ekrane matysime eilut:


Joju, dairausi ir dainuoju Joju dairausi Joju

Pertvarkykite pavyzdio program su ciklo operatoriumi taip, kad ji parodyt ekrane visus tiriamos eiluts odius. Analizs ciklo pabaigos poymiu vartokite grinamos rodykls reikm NULL. Atskiriamus i 50

eiluts odius i pradi suraykite odi masyv ir tik po to parodykite ekrane.


char *_strtime(char *buf);

Kompiuterio laik urao eilutje buf, kurios ilgis privalo bti 9 Eiluts forma HH:MM:SS, kur HH valandos, MM minuts ir SS sekunds. Grina eiluts buf adres. Eilut baigiama nuliniu simboliu.
char *_strdate(char *buf);

Kompiuterio dat urao eilutje buf, kurios ilgis privalo bti 9 Eiluts forma MM/DD/YY, kur MM mnuo, DD mnesio diena ir YY met paskutiniai du skaiiai. Grina eiluts buf adres. Eilut baigiama nuliniu simboliu. 2.15 pratimas. Programa iliustruoja funkcij _strdate veikim.
#include <time.h> #include <stdio.h> void main(void) { char data[9]; char laikas[9]; _strdate(data); _strtime(laikas); printf("Data: %s Laikas: %s\n", data, laikas); }

ir _strtime

vykd program, ekrane matysime vykdymo dienos dat ir laik, pavyzdiui:


Data: 10/22/00 Laikas: 11:13:16

2.16 pratimas. Klaviatra vedama simboli eilut, kur odiai skiriami bent vienu tarpu. Reikia atspausdinti eiluts odius po vien ekrane, nurodant odio pradios ir pabaigos indeksus. Ankstesniame pratime eiluts vedimo pabaiga buvo pirmas sutiktas tarpas arba eiluts pabaiga, todl paraius kelis odius, buvo vedamas tik pirmasis. Visos eiluts vedimui galima naudoti funkcij: #include <stdio.h> char *gets(char *s);

51

Skaitomos eiluts pabaigos simbolis '\n' automatikai pakeiiamas simboliu '\0'. Sudarant program, tikslinga vis eilut perskaityti jai skiriam simboli masyv ir po to analizuoti po vien simbol.
#include #include #include #include <iostream.h> <conio.h> <stdio.h> <string.h>

typedef char Mas[80]; void zodis(Mas, Mas, int *); // odio atskyrimas // Pagrindin programa void main() { Mas Eil, Z; int i, c; cout << "veskite eilut maosiomis raidmis\n"; cout << " odius atskirkite tarpais\n"; gets(Eil); // Simboli eilut cout << Eil << endl; // Eilut spausdinama ekrane strcat(Eil, " "); // Po paskutinio odio bus tarpas i = 0; while(Eil[i] != '\0') { // odi atskyrimas: c = i; // odio pradia; zodis(Eil, Z, &i); // surastas odis pradedant i vieta; if (Z[0] != '\0') // jeigu buvo odis, tai spausdinamas cout << "Pradia: " << c << " Pabaiga: " << (i-1) << " *" << Z << "*" << endl; i++; } // Praleidiamas tarpas } // odio atskyrimas /* I eiluts A, pradedant simboliu, numeris n, iskiriamas odis. Surasto odio simboliai suraomi eilut B. Gale nulinis simbolis */ void zodis(Mas A, Mas B, int *n) { int i = 0; while((A[*n] != '\0') && (A[*n] != ' ')) B[i++] = A[(*n)++]; B[i] = '\0'; }

Ibandykite skaitymo po vien simbol funkcij:


int getc(FILE *stream);

52

Skaitant i klaviatros, turi bti vartojamas failo vardas stdin. Eiluts skaitymo bufer apraymo pavyzdys:
// Tuias ciklas! while((Eil[i++] = getc(stdin)) != '\n'); str[--i]='\0'; // Eiluts pabaigos ym

Pertvarkykite odi atskyrimo program taip, kad ji ekrane parodyt tik ilgiausi od. odio ilgio skaiiavimui siloma vartoti toki funkcij:
int length(char* x) { int i = 0; while(x[i++]); return --i; }

Atskiro simboli eilui tipo C++ kalboje nra. Eiluts yra saugomos simboli masyvuose, kur j pabaigos yra ymimos nulinio kodo simboliais '\0'. Daugumoje C++ kalbos realizacij yra toki masyv apdorojimo bibliotekos, kuriose yra vairios eilui struktros analizs ir j tvarkymo funkcijos. Borland C++ realizacijoje ios priemons yra paskirstytos dviejose bibliotekose: string.h (struktros analiz ir tvarkymas) ir stdlib.h (tip keitimas). 2.17 pratimas. Savarankikai isiaikinkite pavyzdio programlje vartojam eilui tvarkymo funkcij paskirtis ir kreipimosi jas bdus.
#include <iostream.h> #include <string.h> #include <conio.h> typedef char zodis[15]; typedef char string[80]; int main() { zodis x; string z, t; cout << "Iveskite savo varda ir cin >> z >> x; strcat(z, " "); strcat(z, x); strcpy(t, z); strlwr(t); cout << "Mazosiomis raidemis: " strupr(t);

pavarde\n";
// Eilui sujungimas

// Maosios raids << t << endl; // Didiosios raids

53

cout << "Didziosiomis raidemis: " << t << endl; cout << "Buvo ivesta: " << z << endl; cout << "Buvo raidziu: " << (strlen(z)-1) << endl; }

Pertvarkykite program taip, kad ji i klaviatra vestos eiluts atskirt odius ir paskirstyt du masyvus: skaii ir kitoki odi. Abiej masyv elementai ir skaii masyvo suma turi bti parodomi ekrane. Eilui pertvarkymui skaiius vartokite bibliotekos stdlib.h funkcijas, kuri prototipai: double atof(const char *s); int atoi(const char *s); Jos grina skaii reikmes arba 0, jeigu argumento eiluts negalima pertvarkyti skaii.

54

3 skyrius. Struktros
Struktr apra sintaks:
struct <struktrinio tipo vardas> { <lauk apra sraas> } [<kintamj sraas>];

Lauk apra sra elementai atskiriami kabliatakiais, o kintamj srao elementai kableliais. Jei aprae nra kintamj srao, jis apibria tik nauj struktrini duomen tip, taiau jo realizacijoms atmintyje vietos neskiria. Atskiro struktros tipo apibrimo ir realizavimo pavyzdys:
// Apibrimas struct telefonas { char vardas[30]; unsigned longint tel; // Realizavimas struct telefonas Tel, *P, TelMas[100]; <struktros vardas>.<lauko vardas>

Kreipiantis struktr elementus vartojami sudtiniai vardai: Galimos rodykls sruktr tipo reikmes:
P = &Tel; // struct telefonas *P;

Lauk vard uraymo, panaudojant rodykles, pavyzdiai:


(*P)->Tel, P->Tel, P->Tel.vardas

3.1 pratimas. Klaviatra vedamas moni sraas spausdinamas lentele faile.


#include #include #include #include <stdio.h> <stdlib.h> <iomanip.h> <conio.h> vardas [10]; pavarde[10]; gim_met; ugis; };

struct zmogus { char char int float

55

FILE *F; const char Duomenys[]="Prat31.rez"; int Atidaro(const char *, char *); void Lentele(); // Pagrindin programa void main(void ) { if (Atidaro(Duomenys, "w")) exit(0); Lentele(); fclose(F); cout << "Pabaiga\n\a"; } // Failo atidarymas int Atidaro( const char *Vardas, char *Forma){ if (( F = fopen( Vardas, Forma )) == NULL ) { cout<< "Failas neatidarytas"; return 1;} else return 0; } // Duomenys vedami klaviatra ir spausdinami faile void Lentele() { struct zmogus A; int n; cout << "Kiek zmoniu bus ?\n"; cin >> n;
fprintf(F,"..........................................\n"); fprintf(F,": Vardas : Pavarde : gim. m. : ugis :\n"); fprintf(F,"..........................................\n");

while(n--) { cout << "Iveskite varda \n"; cin >> A.vardas ; cout << "Iveskite pavarde \n"; cin >> A.pavarde; cout << "Iveskite gimimo metus \n"; cin >> A.gim_met; cout << "Iveskite ugi \n"; cin >> A.ugis; fprintf(F, ":%10s :%10s : %4d : %3.2f :\n", A.vardas, A.pavarde, A.gim_met, A.ugis); }
fprintf(F,"..........................................\n");

fclose(F);

} .......................................... : Vardas : Pavarde : gim. m. : ugis : .......................................... : Petras : Petraitis : 1933 : 2.15 : : Jurgis : Jurgelis : 1582 : 1.58 : : Kazys : Kazelis : 1258 : 1.25 : ..........................................

Programos darbo rezultatai faile Prat31.rez:

56

Struktr masyvai sudaromi taip pat, kaip ir paprast duomen tip. Rekomenduojama sukurti duomen tip, po to j naudoti. 3.2 pratimas. Klaviatra vedami duomenys suraomi struktr masyve. Po to jie spausdinami lentele.
#include #include #include #include <stdio.h> <stdlib.h> <iomanip.h> <conio.h>

struct zmogus { char vardas [10]; char pavarde[10]; int gim_met; float ugis; }; FILE *F; const char Duomenys[]="Prat32.rez"; int Atidaro(const char *, char *); void Ivesti(zmogus *, int *); void Lentele(zmogus *, int); // Pagrindin programa void main(void ) { zmogus A[10]; int n = 0; Ivesti(A, &n); if (Atidaro(Duomenys, "w")) exit(0); Lentele(A, n); fclose(F); cout<<"Pabaiga\n\a"; } // vedimas klaviatra void Ivesti(zmogus *B, int *n) { int i = 0; cout << "Kiek zmoniu bus ?\n"; cin >> *n; while(i < *n) { cout << "*********************\n"; cout << (i+1) << "-ojo zmogaus duomenys:\n"; cout << "Iveskite varda \n"; cin >> B[i].vardas; cout << "Iveskite pavarde \n"; cin >> B[i].pavarde; cout << "Iveskite gim. metus\n"; cin >> B[i].gim_met; cout << "Iveskite ugi \n"; cin >> B[i].ugis; cout << "Aciu \n"; i++; } }

57

// Failo atidarymas int Atidaro(const char *Vardas, char *Forma) { if ((F = fopen(Vardas, Forma)) == NULL ) { cout << "Failas neatidarytas"; return 1; } else return 0; } // Ivedimas lentele void Lentele(zmogus *C, int n) { int i = 0;
fprintf(F,"..........................................\n"); fprintf(F,": Vardas : Pavarde : gim. m. : ugis :\n"); fprintf(F,"..........................................\n");

while(i < n) { fprintf(F, ":%10s :%10s : %4d : %3.2f :\n", C[i].vardas, C[i].pavarde, C[i].gim_met, C[i].ugis); i++; }
fprintf(F,"..........................................\n");

fclose(F); }

3.3 pratimas. Klaviatra vedami duomenys suraomi tipizuot fail. Po to jie skaitomi i to failo ir parodomi ekrane.
#include #include #include #include <stdio.h> <stdlib.h> <iomanip.h> <conio.h>

FILE *failas; const char Rezultatai[]="Prat33.rez"; struct telefonas { char vardas [10]; char pavarde[10]; long tel; } T; int Atidaro ( const char *, char *); void Raso(); void Skaito(); // Pagrindin programa void main(void ) { if (Atidaro(Rezultatai, "w")) exit(0); Raso(); fclose(failas); if (Atidaro(Rezultatai, "r")) exit (0); Skaito();

58

} // vedamus duomenis surao fail void Raso() { char buf[50] = ""; printf("Programos nutraukimas - eilute 'q'\n"); while(buf[0] != 'q') { printf("Nurodykite varda, pavarde ir telefono numeri:\n"); gets(buf); if (buf[0] != 'q') { sscanf(buf, "%s%s%ld", T.vardas, T.pavarde, &T.tel); fwrite(&T, sizeof(struct telefonas), 1, failas); } } } // Failo atidarymas int Atidaro(const char *Vardas, char *Forma) { if ((failas = fopen(Vardas, Forma)) == NULL) { cout << "Failas neatidarytas"; return 1; } else return 0; } // Skaito i failo void Skaito() { printf(".......................................\n"); printf(": Vardas : Pavarde : telefonas :\n"); printf(".......................................\n"); while(fread(&T, sizeof(struct telefonas), 1, failas)) printf( ":%10s :%10s : %10ld :\n", T.vardas, T.pavarde, T.tel); printf(".......................................\n"); }

fclose(failas); cout << "Pabaiga\n\a";

Pertvarkykite program, kad pagrindinje funkcijoje pagal vartotojo pageidavimus bt galima pasirinkti tokius veiksmus: duomen failo turinio ivedimas ekrane, naujo failo formavimas arba esanio failo papildymas. Programos akojimui vartokite operatori case. Papildykite program failo rikiavimo pagal pavardes alfabeto tvarka funkcija. Rikiuojamo failo duomenys i pradi turi bti perraomi ra masyv ir tik po to rikiuojami. Lyginant eilutes turi bti vartojamos ne santykio operacijos, bet bibliotekos string.h funkcijos arba makrokomandos: stricmp, strnicmp, strncmpi, strcmpi.

59

Kuriant sudtingesnes programas tikslinga inoti kelet domesni funkcij savybi. Kalboje C++ realizuota labai efektyvi funkcij savyb polimorfizmas, kuri dar vadinama daugiavariantikumu arba funkcij persidengimu (overloading). Senose C++ kalbos versijose polimorfini funkcij apraai turi bti paymimi baziniu odiu overload. Kalbos realizacijose Borland C++ tai daryti nebtina. 3.4 pratimas. Demonstruojama ivedimo ekrane polimorfin funkcija print, kurios darbas priklauso nuo kreipinyje urayto duomen tipo.
#include <stdio.h> #include <conio.h> // overload inline void inline void inline void print; // Bordland C galima praleisti. print(int x) {printf("%d\n" , x); } print(double x) {printf("%5.2f\n", x); } print(char *x) {printf("%s\n", x); } // Slankaus kablelio skaiius // Sveikas skaiius // Simboli seka

void main(void ) { print(3.14); print(15); print("Simboliu eilute"); }

ia baziniu odiu inline paymtos terpiamos funkcijos. terpiamos funkcijos yra makrokomand analogai pirminis procesorius rao funkcijos tekst kiekvieno kreipinio j vietoje. Jei funkcij tekstai trumpi, toks funkcij tekst terpimas padidina program darbo greit. 3.5 pratimas. Dar viena labai naudinga funkcij savyb argument parinkimas pagal nutyljim.
#include <stdio.h> #include <conio.h> struct upe { char *vardas; char *salis; } x, y, z, k; // Funkcija Rodo void Rodo(struct upe *d, char *a = NULL, char *b = NULL) { d->vardas = a; d->salis = b; } // Pagrindin programa void main(void) { Rodo(&x);

60

Rodo(&y, "Nemunas"); Rodo(&z, "Merkys", "Lietuva"); Rodo(&k, "Nilas"); printf("%10s %10s \n", x.vardas, printf("%10s %10s \n", y.vardas, printf("%10s %10s \n", z.vardas, printf("%10s %10s \n", k.vardas, }

x.salis); y.salis); z.salis); k.salis);

vykdius program ekrane matysime:


(null) Nemunas Merkys Nilas (null) (null) Lietuva (null)

61

4 skyrius. Klass apibrimas. Objektas


C++ kalboje struktra, jungianti savyje kintamuosius, skirtus duomenims saugoti, ir funkcijas, kurios naudoja tik tuos kintamuosius, vadinama klase. Kintamieji vadinami duomenimis, o funkcijos metodais. Objektiniame programavime priimta, kad duomenimis tiesiogiai gali naudotis tik tos klass metodai. Klass aprao struktra:
class <Klass Vardas> { <Duomen elementai> public: <Metodai> };

Klasje duomenys ir metodai gali bti raomi bet kokia seka. Klass elementai (duomenys ir metodai) gali turti poymius. Poymis klasje galioja tol, kol bus sutiktas kito poymio uraas. Jeigu poymio urao nra, tuomet pagal nutyljim bus priimtas private visiems elementams iki pirmojo poymio urao, jeigu jis bus. Yra tokie poymiai: private (lokalusis). Elementai prieinami tik klass viduje. public (globalusis). Klass elementai prieinami jos iorje. protected (apsaugotasis). Klass elementai prienami klasje, kuri paveldi duotj klas. ia jie galioja private teismis.

Programavimo technologijos poiriu reikt laikytis tam tikros tvarkos. Rekomenduojama pradioje surayti duomenis, po to metodus. Metod srae taip pat reikalinga tvarka. Pirmuoju srae turt bti klass konstruktorius. Tai metodas, skirtas klass objekto pradini duomen reikmms nurodyti. Jo vardas privalo sutapti su klass pavadinimu. Konstruktorius neturi grinamos reikms. Toliau metod srae turi bti darbo su duomenimis metodai. Gale raomas destruktorius, jeigu toks yra. Tai metodas, naikinantis objekt. Destruktoriaus vardas turi sutapti su klass vardu, kurio pradioje paraomas simbolis ~. Pavyzdiui: 62

class Katinas { public Katinas() { } ~Katinas() { }

// Konstruktorius // Destruktorius

Konstruktorius ir destruktorius privalo bti public. Konstruktorius, kuris neturi parametr, ikvieiamas darbui pagal nutyljim. Galima parayti:
Katinas A; // vietoje Katinas A();

Destruktorius skirtas tos klass objektui naikinti kompiuterio atmintyje. Jeigu jo nra, objektas naikinamas baigus vykdyti program. Programos darbo eigoje kreipinys destruktori naikina objekt. Jeigu objekto duomen laukai gauna atmint dinamikai, tuomet btina destruktoriuje parayti veiksmus, kuriais atsisakoma atminties, skirtos duomen laukams. Destruktoriai, kaip ir konstruktoriai, negrina jokios reikms. Jeigu klas turi destruktori, bet nra kreipinio j, tuomet, pagrindinei funkcijai baigus darb, jis yra vykdomas pagal nutyljim. Metodai klasje gali bti pilnai aprayti. Tokius metod apraus tikslinga turti, jeigu j tekstas yra trumpas. Kit metod apraai ikeliami u klass rib. Tuomet klasje raomas tik metodo prototipas. Metodo aprao klass iorje struktra:
<Grinamos reikms tipas> <Klass Vardas>:: <Metodo vardas> (<Parametr sraas>) { <Programos tekstas> }

Klass tipo kintamieji vadinami objektais. J apraymas analogikas kit tip kintamj apraams. Sukuriami objektai gali bti statiniai, dinaminiai. Galima turti objekt masyvus. Objektai gali bti dinamini sra elementais. 4.1 pratimas. Sukuriama klas, apraanti vieno studento savyb svor. Klasje yra du metodai: duomen skaitymo klaviatra ir duomen rodymo ekrane. Pagrindinje funkcijoje sukuriami du objektai. Duomenys vedami panaudojant metod Skaito, o parodomi ekrane panaudojant metod Rodo. Metodai klasje apraomi kaip public, nes juos naudojame klass iorje.
#include <iostream.h> #include <conio.h> // vedimo/ivedimo priemons // Ryio su ekranu priemons

63

// Klass apraymas class Studentas { char *pav; float svoris; public: void Skaito() { // Metodas cout << "Iveskite pavarde: \n"; cin >> pav; cout << "Iveskite svori:\n"; cin >> svoris; }; void Rodo() { // Metodas cout << pav << " " << svoris << endl; }; }; // Pagrindin programa void main() { Studentas A, B; // Sukuriami objektai A.Skaito(); B.Skaito(); B.Rodo(); A.Rodo(); }

4.2 pratimas. Sukuriama klas studentas, kuri turi du duomen laukus, skirtus saugoti pavardei ir svoriui. Konstruktorius studentas suteikia pradines reikmes duomen laukams. Reikms nurodomos objekto sukrimo metu. Konstruktoriaus ir metodo Rodo apraai ikelti u klass rib. Metodas Rodo iveda ekrane studento pavard ir svor. terpiami metodai RodoVarda ir RodoSvori skirti gauti informacij apie duomen laukuose saugom pavard ir svor. Metodas Duomenys skirtas nauj duomen perdavimui objekt. Vidini metod informacijai apdoroti klasje nra. Klass objektai skiriami tik duomen registracijai.
#include <stdio.h> #include <stdlib.h> #include <iostream.h> #include <conio.h> // Klass apraymas class student { char *vardas; float svoris; public:

64

}; // Pagrindin programa void main() { clrscr(); student X("Petraitis", 13.5); // Objektas X student Y(" ", 0); // Objektas Y X.Rodo(); // Objekto X duomenys cout << "Objekto student X duomenys \n"; cout << X.RodoVarda() << " : "<< X.RodoSvori(); cout << endl; // Duomen persiuntimas kitam objektui, t.y. Y = X Y.Duomenys(X.RodoVarda(), X.RodoSvori()); Y.Rodo(); // Objekto Y duomenys

student(char *, float); void Rodo(); char *RodoVarda() { return vardas; } float RodoSvori() { return svoris; } void Duomenys(char *a, float b) { vardas = a; svoris = b; }

// // // // //

Konstruktorius Metodas Metodas Metodas Metodas

} // Metod apraai student::student(char *a, float b) { vardas = a; svoris = b; } void student::Rodo() { cout << vardas << " : " << svoris << endl; }

vykdius program ekrane matysime:


Petraitis : 13.5 Objekto student X duomenys Petraitis : 13.5 Petraitis : 13.5

4.3 pratimas. Sukuriama klas darbui su skaiiais masyve. Numatyti veiksmai: papildyti sra nauja reikme, paalinti nurodyt reikm ir perirti ekrane turimus srao skaiius. Klas nagrinti ir panaudoti paprasiau, kai metod apraai pateikiami atskirai. Metod apraus siloma rayti tuoj po klasi (arba kiekvienos klass) apra.
#include <iostream.h> #include <conio.h> const dydis = 50;

65

// Klass apraymas class sar { int A[dydis]; int ilg; public: void sar(); // Konstruktorius void add(int); // Srao papildymo metodas void del(int); // Reikms alinimo metodas void get(); // Srao rodymo ekrane metodas }; // Metod apraai void sar::sar() { ilg = 0; } // Konstruktorius void sar::add(int naujas) { // Papildymo metodas if (ilg == dydis) { // Sraas papildomas, jeigu srae dar nebuvo cout << "sarasas pilnas"; return; } for(int i=0; i<ilg; i++) if (A[i] == naujas) return; A[ilg++] = naujas; } void sar::del(int elem) { // alinimo metodas for(int i=0; i<ilg; i++) if (A[i] == elem) { for(int j=i; j<ilg-1; j++) A[j] = A[j+1]; ilg--; } } void sar::get() { // Ivedimo ekrane metodas for(int i=0; i<ilg; i++) cout << A[i] << " "; cout << endl; } // Pagrindin programa void main() { clrscr(); sar Rasa; // Objekto apraas Rasa.sar(); // Objektas paruoiamas Rasa.add(10); // Srao papildymai Rasa.add(20); Rasa.add(30); Rasa.get(); // Ekrane matome: 10 20 30 Rasa.del(20); // aliname Rasa.get(); // Ekrane matome: 10 30 }

66

5 skyrius. vedimo, ivedimo srautai


5.1. Ivedimas ekrane ir vedimas klaviatra
vedimo sraut klas istream ir ivedimo sraut klas ostream apraytos faile iostream.h. J objektai cin ir cout palaiko klasse numatytus veiksmus. Anksiau buvo nagrinjami operatoriai >> ir <<. Ivedam skaii formatui valdyti buvo panaudotos faile iomanip.h esanios priemons setw(int) ir setprecission(int). Klass ostream metodas width(int) skirtas nurodyti ivedamo sraute duomen laukams. Galioja artimiausiam dydiui. Tai setw analogas. 5.1 pratimas. Parodomas duomen lauko valdymo metodas.
#include <iostream.h> #include <conio.h> main() { for(int i=2; i<6; i++) { cout.width(3); cout << "i="; cout.width(i); cout << i << endl; } }

vykdius program ekrane matysime:


i= 2 i= 3 i= 4 i= 5

Ivedant duomenis nurodytu formatu nepanaudotos pozicijos upildomos tarpo simboliais. Metodas fill(int) leidia pakeisti upildymo simbol norimu. Pakeitimas galioja iki naujo nurodymo. 67

5.2 pratimas. Demonstruojamas duomen lauk upildymas simboliais.


#include <iostream.h> #include <iomanip.h> #include <conio.h> main() { cout.fill('.'); for(int i=2; i<6; i++) { cout << "i="; cout.width(i); cout << i << endl; } }

vykdius program ekrane matysime:


i=.2 i=..3 i=...4 i=....5

5.3 pratimas. Metodas put skirtas vienam simboliui ivesti ekrane.


#include <iostream.h> #include <conio.h> main() { char zodis[] = "Katinas"; for(int i=0; zodis[i]; i++) cout.put(zodis[i]); cout << endl; }

vykdius program ekrane matysime:


Katinas

5.4 pratimas. Metodas put programose danai vartojamas kartu su funkcija int toupper(int), kuri maj raid keiia didija. Kiti simboliai nekinta.
#include <iostream.h> #include <conio.h> #include <ctype.h>

68

main() { char sim; char zodis[] = "Katinas ir Pele"; for(int i=0; zodis[i]; i++) { sim = toupper(zodis[i]); cout.put(sim); } cout << endl << zodis << endl; }

vykdius program ekrane matysime:


KATINAS IR PELE Katinas ir Pele

5.5 pratimas. vedimo klasje metodas get skirtas vieno simbolio vedimui klaviatra.
#include <iostream.h> #include <conio.h> #include <ctype.h> main() { char sim; cout << "Ar dar dirbsite?( T/N ): "; do { sim = cin.get(); sim = toupper(sim); } while((sim != 'T') && (sim != 'N')); cout << "Jus pasirinkote : " << sim << endl; }

vykdius program ekrane matysime:


Ar dar dirbsite?( T/N ): t Jus pasirinkote : T

5.6 pratimas. vedimo klasje metodas getline skirtas vienos eiluts vedimui klaviatra. Matome, kad paprastai vedama eilut iki pirmojo tarpo simbolio arba iki galo, jeigu tarpo simbolio nebuvo. Panaudoj getline metod galima vesti norim simboli skaii: nurodomas skaiius. Jeigu tiek simboli nebuvo, vedami visi simboliai iki eiluts galo. vedama eilut visuomet papildoma nuliniu simboliu (eiluts galas). 69

#include <iostream.h> #include <conio.h> #include <ctype.h> main() { char A[30]; int n; cout << "Iveskite eilute:\n"; cin >> A; // Pirmasis eiluts odis cout << "Eilute: *" << A << "*\n"; cin.getline(A, 12); //Vienuolika simboli ir '\0' cout << "Eilute: *" << A << "*\n"; cin.getline(A, sizeof(A)); // Iki galo arba tiek, kiek telpa cout << "Eilute: *" << A << "*\n"; n = cin.gcount(); // Eiluts ilgis su nuliniu simboliu cout << "n= " << n << endl; }

vykdius program ekrane matysime:


Iveskite eilute: Rainas Katinas ir Pilka Pele Eilute: *Rainas* Eilute: * Katinas ir* Eilute: * Pilka Pele* n=12

5.7 pratimas. vedimo klasje metodas getline gali turti trei parametr, nurodant simbol, kuriuo baigiamas vedimas. Pavyzdyje parayta raid Z. Jeigu vedamoje eilutje jos nebus, tuomet bus vedami visi eiluts simboliai arba tik tiek, kiek nurodyta, jeigu eilutje j yra daugiau.
#include <iostream.h> #include <conio.h> #include <ctype.h> main() { char A[30]; cout << "Iveskite eilute:\n"; cin.getline(A, sizeof(A), 'Z'); cout << "Eilute: *" << A << "*\n"; }

70

5.2. vedimas i failo ir ivedimas fail


vedimo srautu i failo klas ifstream ir ivedimo srautu fail klas ofstream apraytos faile fstream.h. Galima sukurti objektus, kurie nukreipia vedimo\ivedimo srautus i\ failus. Jiems atitinkamai galioja operatoriai >> ir <<. Konstruktoriaus parametru yra failo vardas. ia yra metodai, kuriuos turi jau nagrintos sraut klass. Failo udarymui yra metodas close(). 5.8 pratimas. Duomen faile Duom58.txt yra skaiius 15. Rezultat faile Rez58.txt rasime skaii 15.
#include <iostream.h> #include <fstream.h> #include <conio.h> main() { ofstream R("Rez58.txt"); ifstream D("Duom58.txt"); int A; D >> A; cout << " A= " << A << endl; R << A; }

vykdius program ekrane matysime:


A= 15

Rezultat faile bus:


15

5.9 pratimas. Duomen failo Duom59.txt perraymas eilutmis nauj fail Rez59.txt.Taip programikai gaunama failo kopija. Metodas eof skirtas failo pabaigai nustatyti: grina reikm 0, kai failo pabaiga dar nepasiekta, ir 1, kai jau turime failo pabaig.
#include <iostream.h> #include <fstream.h> #include <conio.h> main() { ofstream R("Rez59.txt");

71

ifstream D("Duom59.txt"); char A[80]; while(!D.eof()) { D.getline(A, sizeof(A)); cout << A << endl; R << A << endl; } }

vykdius program duomen ir rezultat failuose matysime:


Batuotas Katinas pagavo gauruota peliuka. Tupi sarka kamine.

5.10 pratimas. Duomen failo Duom510.txt perraymas odiais nauj fail Rez510.txt. Ankstesnje programoje pakeitus skaitymo i failo metod operatoriumi >>, gausime rezultat faile atskirus duoto teksto odius.
#include <iostream.h> #include <fstream.h> #include <conio.h> main() { ofstream R("Rez510.txt"); ifstream D("Duom510.txt"); char A[80]; while(!D.eof()) { D >> A; cout << A << endl; R << A << endl; } }

vykdius program duomen faile, rezultat faile ir ekrane matysime:


Batuotas Katinas pagavo gauruota peliuka. Tupi sarka kamine.

72

5.11 pratimas. Duomen failo perraymas simboliais nauj fail Rez511.txt ir ekran. Ankstesnje 5.9 pratimo programoje pakeitus skaitymo i failo metod get, gausime rezultat faile ir ekrane duomen failo kopij.
#include <iostream.h> #include <fstream.h> #include <conio.h> main() { ofstream R("Rez511.txt"); ifstream D("Duom511.txt"); char sim; while(!D.eof()) { sim = D.get(); cout << sim; R << sim; } D.close(); R.close(); }

Dirbant su duomen failais reikia patikrinti ar failas buvo surastas ir skmingai atidarytas. Kiekvienu skaitymo i failo ingsniu btina patikrinti, ar veiksmas buvo skmingai atliktas. Tam skirtas metodas fail(), kurio rezultatas yra 0, kai klaid nebuvo, ir 1, kuomet vyko trikis. Klaid praneimams ekrane skirtas ivedimo srautu objektas cerr. Metodas fail() naudojamas ivedime, norint sitikinti, ar veiksmas buvo skmingas (buvo vietos naujam raui). 5.12 pratimas. Duomen failo Duom512.txt.skaiiai perraomi nauj fail Rez512.txt.
#include <iostream.h> #include <fstream.h> #include <conio.h> main(){ ofstream R("Rez512.txt"); ifstream D("Duom512.txt"); int a; if (D.fail()) cerr << "Neatidarytas duomenu failas"; else { while((!D.eof()) && (!D.fail())) {

73

D >> a; if(!D.fail()) { R << a << endl; cout << a << endl; } } } D.close(); R.close(); } "Duom.dat" 15 12 45 -56 15 89 "Rez13.rez" 3 15 12 45 -56 3 15 89

5.13 pratimas. iose klasse yra write ir read metodai, skirti duomen mainams su failais bait lygyje. Programa urao faile duot struktr, o po to perskaito ir parodo ekrane. Metoduose uraas (char *) nusako kompiliatoriui, kad bus naudojama rodykl skirtingus tipus.
#include <iostream.h> #include <fstream.h> #include <conio.h> struct Studentas{ char pav[20]; int metai; float ugis; }; main() { Studentas A; Studentas S = {"Petriukas ", 21, 187.5}; ofstream R("Rez513.txt"); R.write((char *) &S, sizeof(Studentas)); R.close(); ifstream D("Rez513.txt"); D.read((char *) &A, sizeof(Studentas)); cout << A.pav << A.metai << " " << A.ugis << endl; D.close(); }

74

5.14 pratimas. Analogikai galima sukurti baitin fail struktriniams duomenims i tekstinio failo saugoti. Programa demonstruoja duomen failo Duom514.txt perraym fail Rez514.txt ir po to skaitym i jo ir duomen raym ekrane.
#include <iostream.h> #include <fstream.h> #include <conio.h> struct Studentas{ char pav[20]; int metai; float ugis; }; main() { char sim; Studentas A; ofstream R("Rez514.txt"); ifstream D("Duom514.txt"); while(!D.eof()) { // Skaitomi duomenys D.getline(A.pav, sizeof(A.pav)); D >> A.metai >> A.ugis; sim = ' '; // Eiluts pabaiga while((!D.eof()) && (sim != '\n')) { sim = D.get(); cout << sim; } // Duomenys ekrane cout << A.pav << " " << A.metai << " " << A.ugis; cout << endl; // Duomenys faile R.write((char *) &A, sizeof(Studentas)); } D.close(); R.close(); // Skaitomi failo duomenys ir parodomi ekrane ifstream C("Rez15.txt"); while(!C.eof()) { C.read((char *) &A, sizeof(Studentas)); if (!C.fail()) cout << A.pav << A.metai << " " << A.ugis; cout << endl; } C.close(); }

75

Duomen failas:
Katinas Batuotas Rapolas Didysis Barbora Bulvyte 45 15 25 12.5 159.98 199.45

76

6 skyrius. Klasi savybs. Objektikai orientuotas programavimas


6.1. Paveldjimas
Objektiniame programavime viena svarbiausi savybi, apibriani objekt sveik, yra paveldjimas.
class A class B

Klas B, kuri paveldi klas A, vadinama protviu (bazin klas). Klas A, kuri alia savo duomen ir metod paveldi kit klas B, vadinama palikuonimi (ivestin klas). Protvio duomenys ir metodai paveldimi kaip private, t.y. juos gali naudoti tik palikuonio metodai. Jeigu norima tiesiogiai kreiptis i iors protvio metodus, reikia nurodyti paveldjimo atribut public. 6.1 pratimas. Sukuriama klas Langas, skirta tekstinio ekraninio lango parametrams saugoti ir langui ekrane formuoti. Sukuriama klas Trys, skirta duomenims saugoti, keisti ir demonstruoti ekraniniame lange. i klas paveldi klas Langas. Jos metodai naudojami tik savo klass viduje.
#include <iostream.h> #include <conio.h> #include <stdio.h> // Klas Langas class Langas { int x1, y1, x2, y2; // Lango koordinats int fonas; // ir fono spalva public: Langas(int, int, int, int, int); void Ekranas(); };

77

// Klass Langas metodai Langas::Langas(int xv, int yv, int xa, int ya, int spalva) { x1 = xv; y1 = yv; x2 = xa; y2 = ya; fonas = spalva;} void Langas::Ekranas() { window(x1, y1, x2, y2); textbackground(fonas); clrscr(); } // Klas Trys class Trys: Langas { int a; float b; char c; public: trys(int, float, char, int, int, int, int, int); void add (int k) { a += k; } // Didina a void addf(float k) { b += k; } // Didina b void addc(char k) { c += k; } // Didina c void Rodo(); // Rodo ekrane }; // Klass Trys metodai Trys::trys(int r1, float r2, char r3, int xv, int yv, int xa, int ya, int spalva): Langas(xv, yv, xa, ya, spalva) { a = r1; b = r2; c = r3; Ekranas(); } void Trys::Rodo() { cprintf("Grazu:"); cprintf(" %5i %5.2f %3c \r\n", a, b, c); } // Pagrindin programa main() { int Spalva = 2; window(1, 1, 80, 25); textbackground(BLACK); clrscr(); Trys A(5, 2.5, 'b', 10, 10, 50, 15, BROWN); textcolor(Spalva++); textcolor(Spalva++); A.Rodo(); A.Rodo(); A.add (10 ); A.addf(25.3);

78

textcolor(Spalva++); textcolor(Spalva++); getch(); }

A.Rodo(); A.Rodo();

A.addc(3

);

vykdius program ekrane rudo fono lange matysime:


Grazu: Grazu: Grazu: Grazu: 5 15 15 15 2.50 2.50 27.80 27.80 b b b e

alia spalva ydra spalva Raudona spalva Violetine spalva

6.2 pratimas. Sukuriama klas Pirmas, kuri paveldi antroji klas Antras. Pagrindinje funkcijoje sukuriami kiekvienos klass objektai. Demonstruojamas kreipinys protvio klass metod. Kad galima bt taip kreiptis, btina nurodyti paveldjimo atribut public. Konstruktoriuje Antras kreipinys konstruktori Pirmas raomas tuoj po antrats. Jis paveldimam laukui x suteikia reikm 5.
#include <iostream.h> // Paveldimo metodo panaudojimas #include <conio.h> // pagrindinje funkcijoje // Klas Pirmas class Pirmas { int x; public: Pirmas(int a) { x = a; } void Rodo() { cprintf("Pirmas::rodo() %5d \n\r", x); } }; // Klas Antras class Antras: public Pirmas { int y; public: Antras(int b):Pirmas(5) { y = b; } void Rodo(){ cprintf("Antras::rodo() %5d \n\r", y); } }; // Pagrindin programa void main() { window(1, 1, 80, 25); textbackground(BLACK); clrscr(); window(10, 10, 40, 18); textbackground(GREEN); clrscr();

79

window(13, 12, 37, 16); textcolor( BLACK ); Pirmas A(10); A.Rodo(); Antras B(25); B.Rodo(); B.Pirmas::Rodo(); getch(); }

vykdius program ekrane alios spalvos lange matysime:


Pirmas::rodo() Antras::rodo() Pirmas::rodo() 10 25 5

6.3 pratimas. Demonstruojamas hierarchinis klasi paveldjimas. Sukuriamos trys klass: ymeklio valdymo Vieta, raids raymo ekrane nurodytoje vietoje nurodyta spalva Raide ir odio raymo ekrane po vien raid Zodis. Klas Vieta ymeklio nevaldo. Ji skirta ymeklio koordinatms saugoti ir keisti.
#include <iostream.h> #include <conio.h> #include <stdio.h> #include <string.h> // Klas Vieta class Vieta { int x, y; public: Vieta(int Xs, int Ys) { x = Xs; y = Ys; } int KoksX() { return x; } int KoksY() { return y; } void Kitas(int Xs, int Ys) { x = Xs; y = Ys; } }; // Klas Raid class Raide: Vieta { int spalva; char sim; public: Raide(int Xp, int Yp,int Sp, char Simb): Vieta(Xp, Yp) { spalva = Sp; sim = Simb; } void Kita(int a, int b, int c, char s) { Kitas(KoksX()+a, KoksY()+b); spalva +=c ;

80

sim =s; } void Rodo() { textcolor(spalva); gotoxy(KoksX(), KoksY()); cprintf("%c", sim ); } }; // Klas Zodis class Zodis: Raide { char Zd[]; public: Zodis(char A[]):Raide(1, 1, 1, 'A') { strcpy (Zd, A); } void Spausd(); }; void Zodis::Spausd() { int i = 0; while(Zd[i] != '\0') { Kita(1, 1, 1, Zd[i]); Rodo(); i++; } } // Pagrindin programa void main(){ window(1, 1, 80, 25); textbackground(BLACK); clrscr(); Raide A(10, 2, RED, 'G'); A.Rodo(); A.Kita(2, 1, 1, 'R'); A.Rodo(); Zodis B("Kaunas\0"); B.Spausd(); getch(); }

vykdius program ekrane skirtingomis spalvomis matysime:


K a u n a s G R

81

6.4 pratimas. Demonstruojamas paveldimo metodo panaudojimas. Klas Zodis turi metod Rodo. Klas Raide taip pat turi metod Rodo, kuri paveldi Zodis. Sukurtas objektas Zodis B; B.Rodo(); kreipinys savo klass objekt, o B.Raide::Rodo(); kreipinys paveldtos klass objekt. Klas Zodis turi paveldti klas Raide su nuoroda public.
#include <iostream.h> #include <conio.h> #include <stdio.h> #include <string.h> // Klas Vieta class Vieta { int x, y; public: Vieta(int Xs, int Ys) { x = Xs; y = Ys; } int KoksX() { return x; } int KoksY() { return y; } void Kitas(int Xs, int Ys) { x = Xs; y = Ys; } }; // Klas Raide class Raide: Vieta { int spalva; char sim; public: Raide(int Xp, int Yp, int Sp, char Simb): Vieta(Xp, Yp) { spalva = Sp; sim = Simb; } void Kita(int a, int b, int c, char s) { Kitas(KoksX()+a, KoksY()+b); spalva +=c ; sim =s; } void Rodo() { textcolor(spalva); gotoxy(KoksX(), KoksY()); cprintf("%c", sim); } }; // Klas Zodis class Zodis: public Raide { char *Zd; public: Zodis(char *A):Raide(1, 1, 1, 'A') { Zd = A ; } void Rodo(); };

82

// Zodis metodai void Zodis::Rodo() { // Metodo apraymas int i =0; while(*(Zd+i) != '\0') { Kita(1, 1, 1, *(Zd+i)); Raide::Rodo(); i++; } } // Pagrindin programa void main() { char *Vardas ="Lapas"; window(1, 1, 80, 25); textbackground(BLACK); clrscr(); Raide A(10, 3, RED, 'G'); A.Rodo(); // Ekrane raid G A.Kita(2, 2, 1, 'R' ); A.Rodo(); // Ekrane raid R Zodis B(Vardas); B.Raide::Rodo(); // Ekrane raid A B.Rodo(); // Ekrane odio Lapas raids getch(); }

vykdius program raides ekrane matysime skirtingomis spalvomis:


A L a p a s

G R

6.2. Operatori perdengimas


Programavimo kalbose naudojami operatoriai pasiymi polimorfizmu (daugiavariantikumu). Kaip pavyzdys gali bti operatorius +, kuris taikomas tiek int, tiek float tipo kintamiesiems, nors sudties veiksmai atliekami nevienodai. Klasse galima naujai apibrti operatorius, t.y. pakeisti j veikim. Toks naujas operatori perorientavimas yra vadinamas perdengimu

83

(overloading). Operatori apraai nuo funkcij skiriasi vartojamu odiu operator: operator <Operatoriaus simbolis>; Perdengimas draudiamas operatoriams: . .* :: ?: 6.5 pratimas. Demonstruojamas dviej operatori + ir perkrovimas klass Katinas objektams. Operatoriumi + bus sudedamos dvi eiluts, kuri viena yra objekte, o kita nurodoma parametru. Rezultate objekto eilut pailgja. Kitas operatorius skiriamas nurodyto simbolio vis pakartojim objekto eilutje alinimui.
#include <iostream.h> // Operatori perkrovimas #include <conio.h> #include <string.h> const N = 40; // Klas Katinas class Katinas { public: Katinas(char *); // Konstruktorius void operator + (char *); void operator - (char ); void Rodo(); ~Katinas(); // Destruktorius private: char *Vardas; }; // Katinas metodai Katinas::Katinas(char *Vardas) { Katinas::Vardas = new char[N]; strcpy(Katinas::Vardas, Vardas); } void Katinas::Rodo() { cout << Vardas << endl; } void Katinas::operator + (char * A) { strcat(Vardas, A); } void Katinas::operator - (char C) { for(int i=0; *(Vardas+i) != '\0'; ) { if(*(Vardas + i) == C) for(int j=i; j<(strlen(Vardas)-1); j++) *(Vardas + j) = *(Vardas + j+1);

84

} }

i++;

Katinas::~Katinas() { delete Vardas; } // Pagrindin programa void main(void) { Katinas A ("Batuotas ir piktas"); A.Rodo(); A + " Rudas! "; A.Rodo(); A - 'a'; A.Rodo(); getch(); }

vykdius program ekrane matysime:


Batuotas ir piktas Batuotas ir piktas Rudas! Btuots ir pikts Ruds!

6.3. Persidengiantys metodai


Patogi programavimo priemon yra persidengiantys metodai. Gali bti persidengiantys konstruktoriai. Persidengianios funkcijos turi t pat vard, taiau gali turti skirtingus parametr sraus. vartojama funkcija atpastama pagal kreipinyje surayt argument skaii ir j tip. 6.6 pratimas. Demonstruojama klasje Lapas persidengiantys konstruktoriai, kuri vienas duomen laukams suteikia pradines reikmes, fiksuotas klass aprayme, o kitas vartotojo nurodytas objekto sukrimo metu. Yra keturi metodai vardu Suma. Pagal kreipinio argumentus yra atrenkamas, kur reikia vykdyti. Kreipinyje A.Suma((float)35.25); nurodomas argumento tipas. To nereikt daryti, jeigu ia bt raomas kintamojo vardas.
#include #include #include #include <iostream.h> <conio.h> <string.h> <stdio.h> // Metod perdengimas

85

// Klas Lapas class Lapas { int x; float y; char z; public: Lapas(int, float, char ); // Konstruktorius Lapas() { x = 0; y = 0; z = 'z'; } // Konstruktorius void Rodo(char *); void Suma(int Sk) { x = x + Sk; } void Suma(float Sk) { y = y + Sk; } void Suma(char Sk) { z = Sk; } void Suma(int A, char B) { x = x + 2.0 * A; z = B + 4; } }; // Lapas metodai Lapas::Lapas(int A, float B, char C) { x = A; y = B; z = C; } void Lapas::Rodo(char *Eilute) { cout << Eilute << " : "; cout << " x= " << x << " y= " << y << " cout << endl; } // Pagrindin programa void main(void) { Lapas A; Lapas B(5, 3.4, 'C'); A.Rodo("Objektas A-1"); B.Rodo("Objektas B-1"); A.Suma(5); B.Suma('K'); A.Rodo("Objektas A-2"); B.Rodo("Objektas B-2"); A.Suma((float)35.25); B.Suma(5, 'A'); A.Rodo("Objektas A-3"); B.Rodo("Objektas B-3"); getch(); }

z= " << z;

86

vykdius program ekrane matysime:


Pradinis A Pradinis B A pakeistas x B pakeistas z A pakeistas y B pakeistas x ir z Objektas Objektas Objektas Objektas Objektas Objektas A-1 B-1 A-2 B-2 A-3 B-3 : : : : : : x= x= x= x= x= x= 0 5 5 5 5 15 y= 0 z= z y= 3.4 z= C y= 0 z= z y= 3.4 z= K y= 35.25 z= z y= 3.4 z= E

6.4. Virtualios funkcijos


Tegul duota protvio klas Lapas ir jos palikuonio klas KnygaPirma. Paskelbsime Lapas *p rodykl klass Lapas objekt. Lapas L1 klass Lapas objektas. KnygaPirma Kn1 klass KnygaPirma objektas. C++ egzistuoja taisykl: bet kuris kintamasis, apraytas kaip rodykl protvio klass objekt, gali bti naudojamas kaip rodykl palikuonio klas. Ms atveju teisinga p = &L1; p = &Kn1; Su rodykle p galima pasiekti visus objekto Kn1 elementus, kuriuos jis paveldjo i klass Lapas. Taiau negalima paimti nuosav (private) klass KnygaPirma element. Jeigu duota rodykl palikuonio klass objekt, tai jos pagalba negalima pasinaudoti protvio klass elementais. Be to, reikia vertinti, kad naudojant protvio klass tipo rodykl palikuonio klass objektui adresuoti, j didinant ar mainant, adresas keisis protvio klass objekto dydiu. Virtualios funkcijos leidia atlikti funkcij perkrovim (polimorfizmo savyb) programos vykdymo metu. Tai protvio klasje su specifikatoriumi virtual apraytos funkcijos, kurios i naujo apraytos vienoje (ar keliose) i palikuoni klasi. Funkcij vardai, grinamos reikms tipai ir argumentai nesikeiia. Tegul duota iraika p = &L1 ir virtuali funkcija Rodo. Tegul i funkcija aprayta su specifikatoriumi virtual protvio klasje Lapas ir be specifikatoriaus virtual palikuonio klasje KnygaPirma. 87

p->Rodo() irinks protvio klass funkcij. Jei p = &Kn1, tai p->Rodo() irinks sukurtos klass KnygaPirma funkcij. Reikalavimai virtualioms funkcijoms: Virtuali funkcij prototipai protvio ir palikuonio klasse turi sutapti. Prieingu atveju funkcija bus laikoma perkraunama, o ne virtualia. Virtuali funkcija turi bti klass komponente (negali turti specifikatoriaus friend). Destruktorius gali turti specifikatori virtual, konstruktoriui tas draudiama. Jei funkcija paskelbta virtualia, tai i savyb ji isaugo visoms j paveldjusioms klasms. Jei kurioje nors sukurtoje klasje virtuali funkcija neaprayta (praleista), tai naudojama protvio klass versija. Jeigu praleidus virtuali funkcij, sukurtoje klasje negalima naudoti protvio klass funkcijos, tai ji paskelbiama pure virtual function. virtual Funkcijos_tipas Funkcijos_vardas (parametrai)=0; tada visose j paveldjusiose klasse turs bti sava virtualios funkcijos versija. Jei kuri nors klas turi nors vien pure funkcij, tai ji vadinama abstrakia. J galima naudoti tik kaip protvio.

6.7 pratimas. Sukuriama klas Lapas, kurioje metodas Rodo paymimas virtualiu. Turime dvi palikuonio klases KnygaPirma ir KnygaAntra. ia taip pat yra tokios funkcijos. Sukuriami objektai ir parodomas virtuali funkcij vartojimas.
#include <iostream.h> // Virtuals metodai #include <conio.h> // Klas Lapas class Lapas { public: virtual void Rodo( void ) { cout << " Klases Lapas versija \n"; } }; // Klas KnygaPirma class KnygaPirma: public Lapas { public: virtual void Rodo(void) { cout << " Klases KnygaPirma versija \n"; } };

88

// Klas KnygaAntra class KnygaAntra: public Lapas { public: virtual void Rodo(void) { cout << " Klases KnygaAntra versija \n"; } }; // Pagrindin programa void main(void) { Lapas *p, L1; KnygaPirma Kn1; KnygaAntra Kn2; p = &L1; p->Rodo(); // Vykdomas klass Lapas metodas p = &Kn1; p->Rodo(); // Vykdomas klass KnygaPirma metodas p = &Kn2; p->Rodo(); // Vykdomas klass KnygaAntra metodas getch(); }

vykdius program ekrane matysime:


Klases Lapas versija Klases KnygaPirma versija Klases KnygaAntra versija

6.8 pratimas. Modifikuotas 6.7 pratimas. Klasje KnygaAntra nra virtualaus metodo. Sukuriama nauja klas Katinas, kuri yra klass KnygaPirma palikuonis. ioje klasje yra metodas Rodo, kuris nra virtualus.
#include <iostream.h> // Virtuals metodai #include <conio.h> // Klas Lapas class Lapas { public : virtual void Rodo(void) { cout << "Klases Lapas versija \n"; } }; // Klas KnygaPirma class KnygaPirma: public Lapas { public: virtual void Rodo(void) { cout << "Klases KnygaPirma versija \n"; };

89

// Klas KnygaAntra class KnygaAntra: public Lapas { public: void Matau(void) { cout << "Klases KnygaAntra Matau \n"; } }; // Klas Katinas class Katinas: public KnygaPirma { public: void Rodo() { cout << "Klases Katinas versija \n"; } }; // Pagrindin programa void main(void) { Lapas *p, L1; KnygaPirma Kn1; KnygaAntra Kn2; Katinas Cat; p = &L1; p->Rodo(); // Vykdomas klass Lapas metodas cout << "\n"; p = &Kn1; p->Rodo(); // Vykdomas klass KnygaPirma metodas p->Lapas::Rodo(); // Vykdomas klass Lapas metodas Kn1.Rodo(); // Vykdomas klass KnygaPirma metodas Kn1.Lapas::Rodo(); // Vykdomas klass Lapas metodas cout << "\n"; p = &Kn2; p->Rodo(); // Vykdomas klass Lapas metodas Kn2.Matau(); // p->Matau(); Kreipinys negalimas cout << "\n"; p = &Cat; p->Rodo(); // Vykdomas klass Katinas metodas Cat.Rodo(); // Vykdomas klass Katinas metodas p->Lapas::Rodo(); // Vykdomas klass Lapas metodas // p->KnygaPirma::Rodo(); Kreipinys negalimas Cat.Lapas::Rodo(); // Vykdomas klass Lapas metodas Cat.KnygaPirma::Rodo(); // Klass KnygaPirma metodas getch(); }

90

vykdius program ekrane matysime:


Klases Lapas versija Klases Klases Klases Klases KnygaPirma versija Lapas versija KnygaPirma versija Lapas versija

Klases Lapas versija Klases KnygaAntra Matau Klases Klases Klases Klases Klases Katinas versija Katinas versija Lapas versija Lapas versija KnygaPirma versija

6.9 pratimas. Klasje Lapas apraomas metodas Rodo abstraktus. ios klass palikuonyse yra savos funkcijos, kurios atliekamos vykdymo metu.
#include <iostream.h> // Virtuals metodai #include <conio.h> // Klas Lapas class Lapas { public: virtual void Rodo(void) = 0; }; // Klas KnygaPirma class KnygaPirma: public Lapas { public: void Rodo(void) { cout << "Klass KnygaPirma versija \n"; }; // Klas KnygaAntra class KnygaAntra: public Lapas { public: void Rodo(void) { cout << "Klass KnygaAntra versija \n"; }; // Klas Katinas class Katinas:public KnygaPirma { public: void Rodo()

91

{ cout << "Klass Katinas versija \n"; }; // Pagrindin programa void main(void) { Lapas *p; KnygaPirma Kn1; KnygaAntra Kn2; Katinas Cat; p = &Kn1; p->Rodo(); p = &Kn2; p->Rodo(); p = &Cat; p->Rodo(); getch(); }

// Vykdomas klass KnygaPirma metodas //Vykdomas klass Lapas KnygaAntra metodas // Vykdomas klass Katinas metodas

vykdius program ekrane matysime:


Klass KnygaPirma versija Klass KnygaAntra versija Klass Katinas versija

6.5. Draugikos (friend) klass, funkcijos


Yra galimyb klasms tarpusavyje draugauti, t.y.klas A gali leisti kitai klasei B naudotis jos priemonmis. Tokiu atveju klasje A yra skelbiama klas B draugika apraoma su atributu friend. Klasje B raomi metodai, kurie naudojasi klass A priemonmis kaip savomis. Draugika klas skelbiama public dalyje. 6.10 pratimas. Klas Knyga skelbia draugika klas Lentyna. Kadangi tos klass apraas yra toliau, tai jos antrat-prototipas raoma prie klass Knyga apra. Klasje Lentyna esanios priemons naudoja Knyga duomenis.
#include <iostream.h> #include <string.h> #include <conio.h> class Lentyna; // Klass antrat

92

// Klas Knyga class Knyga { public: Knyga(char *, char *, char *); // Konstruktorius void Rodo(void); // Ivedimas ekrane friend Lentyna; // Draugika klas private: char pav[64]; char autorius[64]; char leidykla[64]; }; // Knyga metodai Knyga::Knyga(char *pav, char *autorius, char *leidykla) { strcpy(Knyga::pav, pav); strcpy(Knyga::autorius, autorius); strcpy(Knyga::leidykla, leidykla); } void Knyga::Rodo(void) { cout << "Pavadinimas: " << pav << endl; cout << "Autorius: " << autorius << endl; cout << "Leidykla: " << leidykla << endl; } // Klas Lentyna class Lentyna { public: void Keisti(Knyga *, char *); char *Rasti(Knyga); }; // Lentyna metodai // Klass Knyga tipo objekte pakeiia leidyklos pavadinim void Lentyna::Keisti(Knyga * Kn, char * Leid) { strcpy(Kn->leidykla, Leid ); } // Praneamas klass Knyga tipo objekto leidyklos pavadinimas char *Lentyna::Rasti(Knyga Kn) { static char vardas[64]; strcpy(vardas, Kn.leidykla); return(vardas); } // Pagrindin programa void main(void) { Knyga K("Informatika I dalis",

93

" J.Adomavicius ir kt.", "KTU"); Lentyna L; K.Rodo(); L.Keisti(&K, "Technologija"); K.Rodo(); getch(); }

vykdius program ekrane matysime:


Pavadinimas: Informatika I Autorius: J.Adomavicius ir Leidykla: KTU Pavadinimas: Informatika I Autorius: J.Adomavicius ir Leidykla: Technologija dalis kt. dalis kt.

Funkcijai, nepriklausaniai jokiai klasei, gali bti suteiktas draugikos titulas. Ta funkcija gyja teis naudotis klass duomenimis ir metodais. Tose klasse, kurios t funkcij kvieia bti draugika, raomas funkcijos prototipas su atributu friend. 6.11 pratimas. Funkcija Lygu skelbiama draugika dviejose klasse: Point ir Circle. Funkcija palygina skirting klasi objekt naudojamas spalvas ir pranea ekrane, ar jos lygios, ar nelygios. Klas Vieta skirta saugoti ymeklio vietos ekrane koordinatms. Konstruktorius Vieta apibria sukurto objekto pradin pozicij. Metodas set skirtas keisti koordinatms, o getX ir getY koordinatms spausdinti ekrane. Klas Point paveldi klas Vieta ir turi duomen lauk spalvos kodui saugoti. Konstruktorius formuoja tako vietos ekrane koordinates ir spalv. Metodas PutPoint padeda tak grafiniame ekrane. Klasje skelbiama funkcija Lygu. Klas Circle paveldi klas Vieta ir turi duomen laukus apskritimo spalvos kodui bei spinduliui saugoti ir papildom darbui. Konstruktorius formuoja apskritimo centro koordinai, spindulio ir spalvos pradines reikmes. Metodas PutCircle bria apskritim grafiniame ekrane. Klasje skelbiama funkcija Lygu.
#include <iostream.h> #include <graphics.h> #include <conio.h>

94

#include <stdio.h> #include <stdlib.h> class Circle; // Klas Vieta class Vieta { protected: int x, y; public: Vieta(int Xp, int Yp) { x = Xp; y = Yp; } void set(int a, int b) { x = a; y = b; } int getX() { cout << "x= " << x << endl; return x; } int getY() { cout << "y= " << y << endl; return y; } }; // Klas Point class Point: public Vieta { int Spalva; public: Point(int Xp, int Yp, int Cp); void PutPoint() { putpixel(x, y, Spalva); } friend void Lygu(Point p, Circle c); }; // Klas Circle class Circle: public Vieta{ int Spalva, T, R; public: Circle(int Xp, int Yp, int Cp, int Rp); void PutCircle() { T = getcolor(); setcolor(Spalva); circle(x, y, R); setcolor(T); } friend void Lygu(Point p, Circle c); }; // Metodai Point::Point(int Xp, int Yp, int Cp): Vieta( Xp, Yp ) { Spalva = Cp; } Circle::Circle(int Xp, int Yp, int Cp, int Rp): Vieta(Xp, Yp) { Spalva = Cp; R = Rp; } void Lygu(Point p, Circle c) { if (p.Spalva == c.Spalva) cout << "Spalvos sutampa\n"; else cout << " Skirtingos spalvos \n"; }

95

// void Grafika(); void main(){ Grafika();

Pagrindin programa

// Ekranas paruoiamas darbui grafiniame rime

Point Taskas(200, 100, 3); Circle C1 (400, 200, 3, 100); Circle C2 (200, 200, 1, 50 ); Taskas.PutPoint(); C1.PutCircle(); C2.PutCircle(); Lygu(Taskas, C1); Lygu(Taskas, C2); getch(); closegraph(); // Ekrane padedamas takas // Ekrane briamas apskritimas // Ekrane briamas apskritimas
// Praneama, kad spalvos lygios // Praneama, kad spalvos skirtingos

} // Grafinio ekrano paruoimas void Grafika() { int A = DETECT, B; initgraph(&A, &B, "c:\\"); if (graphresult() != grOk) { printf("Klaida: %i %i\n ", A, B); exit(1);} }

Galima kitos klass metodus skelbti draugikais savo klasje ir leisti jiems naudotis duomen laukais. Tam reikia klasje A parayti su atributu friend klass B metod (funkcij) prototipus. 6.12 pratimas. Turime klas Kitoks, kurioje yra trys metodai, skirti darbui su kitos klass duomen laukais: keisti apskritimo vietai ekrane, spindulio reikmei ir spalvai. Klasje Circle tie metodai skelbiami draugikais. Pagrindinje funkcijoje sukuriami du klass Circle objektai C1 ir C2. Nubriamas ydras apskritimas C1 duomenimis. Sukurtas klass Kitoks objektas CC pakeiia objekto C1 visus duomenis. Nubriamas raudonas apskritimas. Pakeiiamas C1 spindulys ir nubriamas raudonas maesnio spindulio apskritimas

96

(gauname du raudonus koncentrikus apskritimus). Toliau tas pat padaroma su C2 apskritimu: du koncentriki violetiniai apskritimai.
#include #include #include #include #include <iostream.h> <graphics.h> <conio.h> <stdio.h> <stdlib.h>

class Circle; // Klas Kitoks class Kitoks { public: void Dydis(Circle *, int); void Vieta(Circle *, int, int); void Spalva(Circle *, int); }; // Klas Circle class Circle { int Spalva, T, R, x, y; public: Circle(int Xp, int Yp, int Cp, int Rp); void PutCircle() { T = getcolor(); setcolor(Spalva); circle(x, y, R); setcolor(T); } friend void Kitoks::Dydis(Circle *, int); friend void Kitoks::Vieta(Circle *, int, int); friend void Kitoks::Spalva(Circle *, int); }; // Metodai Circle::Circle(int Xp, int Yp, int Cp, int Rp) { Spalva = Cp; R = Rp; x = Xp; y = Yp; } void Kitoks::Dydis(Circle *CC, int D) { CC->R = D; } void Kitoks::Vieta(Circle *CC, int Nx, int Ny) { CC->x = Nx; CC->y = Ny; } void Kitoks::Spalva(Circle *CC, int S) { CC->Spalva = S; }; // Pagrindin programa void Grafika();

97

void main(){ Grafika();

// Grafinio ekrano paruoimas // Objektas C1 // Objektas C2

Circle C1(400, 200, 3, 100); Circle C2(300, 300, 5, 50 ); C1.PutCircle(); Kitoks CC;

// Briamas C1 ydras apskritimas


// Objektas CC darbui su Circle tipo objektas

CC.Vieta(&C1, 100, 100);// Keiiama C1 vieta CC.Spalva(&C1, RED); // Keiiama C1 spalva C1.PutCircle(); // Briamas C1 raudonas apskritimas CC.Dydis(&C1, 25); C1.PutCircle(); C2.PutCircle(); CC.Dydis(&CC, 30); C2.PutCircle(); getch(); closegraph(); // Keiiamas C1 spindulys // Briamas C1 raudonas apskritimas // Briamas C2 violetinis apskritimas // Keiiamas spindulys // Briamas C2 violetinis apskritimas

} // Grafinio ekrano paruoimas void Grafika() { int A = DETECT, B; initgraph(&A, &B, "c:\\"); if(graphresult() != grOk) { printf("Klaida: %i %i\n ", A, B); exit(1); } }

6.6. Dinaminiai objektai


Galima turti rodykles objektus, objekt sraus: masyvus, rodykli, masyvus, sraines struktras. Atminties skyrimui patogu naudoti operatori new: <rodykl> = new <tipas>;

98

Dinamikai skirtos atminties atsisakoma operatoriumi delete arba funkcija free: delete <rodykl>; void free (<rodykl>); 6.13 pratimas. Turime klas Lapas. Sukuriama rodykl p klas Lapas. Sukuriamas dinaminis objektas, kurio adresas saugomas rodyklje p.
#include <iostream.h> #include <string.h> #include <stdlib.h> // Klas Lapas class Lapas { char *L; public : Lapas(char * T) { L = T;} void Kitas(char *K) { strcpy(L, K); } void Rodo(void) { if (L) cout << L << " lapas \n"; else cout << "Neturiu lapo\n"; } }; // Pagrindin programa void main(void) { Lapas *p; p = new Lapas("Klevo "); if (!p) { cout << "Truksta atminties\n"; exit( 0 ); } p->Rodo(); p->Kitas("Liepa"); p->Rodo(); free(p); }

vykdius program ekrane matysime:


Klevo lapas Liepa lapas

6.14 pratimas. Turime klas Lapas. Sukuriame rodykli masyv p, kuriame saugosime rodykles tris objektus klass tipo Lapas. Suformuojamas rodykli objektus masyvas. Objektai saugo tuias eilutes. Po to klaviatra suvedami odiai ir patalpinami objekt duomen laukus L. Programos pabaigoje atspausdinami objekt saugomi odiai ir objektai paalinami i atminties.

99

#include <iostream.h> #include <string.h> #include <stdlib.h> // Klas Lapas class Lapas { char *L; public : Lapas() { L = NULL; } void Kitas(char *K) { L = new char[10]; strcpy(L, K); } void Rodo(void) { if (L) cout << L << " lapas \n"; else cout << "Neturiu lapo\n"; } }; // Pagrindin programa void main(void) { int i; Lapas *p[3]; char T[10]; for (i=0; i<3; i++) { // p[i] = new Lapas(); cout << "*** "; p[i]->Rodo(); } cout << "--------------\n"; for (i=0; i<3; i++) { // cout << "Iveskite: "; cin >> T; cout << endl; p[i]->Kitas(T); } // for (i=0; i<3; i++) p[i]->Rodo(); for (i=0; i<3; i++) free(p[i]); // cout << "Pabaiga\n"; }

Masyvo sudarymas

Duomen vedimas

Spausdinimas Naikinimas

vykdius program ekrane matysime:


*** Neturiu lapo *** Neturiu lapo *** Neturiu lapo -------------Iveskite: Liepa Iveskite: Klevas Iveskite: Maumedis

100

Liepa lapas Klevas lapas Maumedis lapas Pabaiga

6.15 pratimas. Turime klas kurio elementais yra objekt upildymas seka, nes sraas sunaikinimas.

Lapas. Sukuriamas tiesinis dinaminis sraas, klass Lapas tipo objektai. Parodomas srao duomenimis, srao spausdinimas (atvirktin buvo formuojamas pradi) ir srao

#include <iostream.h> #include <string.h> #include <stdlib.h> // Klas Lapas class Lapas { char *L; public : Lapas() { L = NULL; } void Kitas(char *K) { L = new char[10]; strcpy(L, K); } void Rodo(void) { if (L) cout << L << " lapas \n"; else cout << "Neturiu lapo\n"; } ~Lapas() { free(L); } }; // Sraas struct sar { Lapas *Medis; sar *sek;}; // Pagrindin programa sar *Naikinti(sar *); void main(void) { sar *P = NULL, *R; int i; char T[10]; for(i=1; i<=3; i++) { cout << "\nIveskite: "; cin>>T; R = new sar; R->sek = P; P = R; P->Medis = new Lapas();

// Srao formavimas

101

} // Srao naikinimas sar *Naikinti(sar *P) { sar *R; while(P) { R = P; P = P->sek; R->Medis->~Lapas(); free( R ); } return P; }

P->Medis->Kitas(T); } R = P; // Srao spausdinimas while(R) { R->Medis->Rodo(); R = R->sek; } P = Naikinti(P); // Srao naikinimas if (!P) cout << "Sarasas tuscias\n"; cout << "Pabaiga\n";

vykdius program ekrane matysime:


Iveskite: Liepa Iveskite: Klevas Iveskite: Slyva Slyva lapas Klevas lapas Liepa lapas Sarasas tuscias Pabaiga

102

7 skyrius. Tiesiniai vienkrypiai sraai


7.1. Srao struktra
Sraais vadinami tokie duomen rinkiniai, kuri elementus apibdina ne tik j reikms, bet ir tvarkymo taisykls, ryiai tarp element. Keiiant element tipus, ryi tarp element bdus ir tvarkymo taisykles, galima sudaryti daugyb vairi tip sra (eiles, stekus, dekus, medius), todl universalios srao tipo struktros sudarymas yra problematikas. Paprasiausi sraai gali bti realizuojami masyvuose, papildant juos tvarkymo procedromis ir upildymo charakteristika. Universalesn sra sudarymo priemon yra dinamins struktros, kurios sudaromos i element su nuorodomis. Tokiuose elementuose saugomos ne tik j reikms, bet ir ryio su kitais elementais apraymai: Reikm Ryio dalis

Dinamins struktros elemento reikm gali bti bet kokia statin arba dinamin struktra, o ryio dalyje yra raomos rodykls kitus to paties srao elementus. Kadangi dinamini struktr element reikms ir nuorodos yra apraomos skirting tip duomenimis, sra elementai realizuojami raais, kuri struktra yra tokia:
struct <Vardas> { <Reikms laukai>; <Ryio dalies laukai>; }

Homogeninse dinaminse struktrose, kuriose visi elementai yra vienodo tipo, apraant ryio dalies rodykles, reikia nurodyti paios naujai apraomos struktros tip. Kreipimasis struktros aprayme save pai vadinamas rekursija, o struktros, kuriose yra tokie kreipiniai, vadinamos rekursyviomis. Rekursyvios struktros elemento aprao pavyzdys:
struct list {int data; struct list *next; } // Rekursyvi nuoroda

I element, kuri ryio dalyje yra viena rodykl, galima sudaryti tik tiesiniais sraais vadinamas nuosekliai sujungtas grandines. Papildant 103

tiesinius sraus tvarkymo procedromis ir iorinio ryio priemonmis, galima sudaryti tokias tipines j modifikacijas: tiesinius sraus, kuriuose nra apribojim srao element analizei, tvarkymui ir apdorojimui; eiles, kuriose nauji elementai prijungiami srao gale, o skaitymui yra prieinamas tik pirmasis elementas (struktra FIFO first in, first out); stekus, kuriuose galima skaityti tik vliausiai rayt element (struktra LIFO last in, first out); dekus, kuriuose elementai gali bti raomi ir skaitomi tiek srao pradioje, tiek gale (struktra DEQUE double-ended que). Tokios srains struktros labai plaiai vartojamos ne tik taikomosiose, bet ir sisteminse programose. Pavyzdiui, stekuose yra saugomi pertraukiam proces parametrai, organizuojami lokals duomenys. Eils yra populiari pagalbini (buferini) atmini, kuriose kaupiami i lt rengini gaunami arba juos siuniami duomenys, organizavimo priemon. Kiekvieno srao tipo realizavimui skirta dinamin struktra turi turti jos elementus apraani struktr, rodykl arba rodykles ioriniams ryiams skirtus elementus ir tokias tvarkymo operacijas: naujo srao sukrimo; naujo elemento prijungimo; elemento paalinimo; srao skaitymo ir analizs; srao tvarkymo. Sudarant sra tvarkymo procedras, reikalingas papildomas susitarimas apie tai, kaip bus ymima srao pabaiga ir kaip bus ymimas tuias sraas. Yra priimta tiek srao pabaig, tiek tui sra dinaminse struktrose ymti nuline rodykle NULL.

7.2. Tiesinis dinaminis sraas


Ryys su srau palaikomas naudojant rodykl jo pradi. Rekomenduojama srao elemento struktra yra i dviej lauk: duomenims saugoti ir ryio rodyklei urayti. Tokia struktra supaprastina veiksmus su srao elementais.

104

Srao elemento struktra gali bti apraoma vienu arba dviem sakiniais:
struct List { int Sk; struct List *next; } *First; struct List { int Sk; struct List *next; }; List *First;

Tiesinio srao grafinis vaizdas parodytas 7.1 pav. ia elementas vaizduojamas staiakampiu, padalintu tiek dali, kiek yra lauk jo struktroje: duomen ir adreso. Duomen lauke saugomos reikms. Rodykls tipo lauke saugomas adresas (nuoroda) kit srao element. Nuoroda pavaizduota linija su rodykle gale. Tos linijos pradia yra nuorodos lauko viduje. Rodykl remiasi element vaizduojant staiakamp bet kurioje vietoje. Jeigu nuoroda neegzistuoja, tuomet linija nra briama ir laukas lieka tuias. Tai reikia, kad adreso reikm neapibrta, iukl. Realiose programose tokia situacija yra neleistina. P 16 58 8 4
NULL 7.1 pav. Tiesinio srao vaizdavimas

16

58

P
NULL

<16>

<58>

<8>

<4>
NULL

7.2 pav. Nuorodos reikm vaizdavimas

Btina urayti tuio adreso reikm konstant NULL. Grafikai tai gali bti ymima vairiais sutartiniais enklais, kas leidia konstruoti maesns apimties paveiksllius. enklai naudojami, kuomet nagrinjamos struktros nra siejamos su konkreia realizacija (pvz., Turbo Paskalyje tuio adreso konstanta yra Nil). Sraus suvokti lengviau, kai sutartini paymjim maiau, todl bus raoma NULL. Be to paveikslliuose bus 105

naudojamas tokio tipo paymjimas: reikm. Tai reik adres viet, kur saugoma nurodyta reikm, pavyzdiui skaiiaus 16 nuoroda bus urayta 16 (7.2 pav.). Tiesinio srao formavimo ir periros iliustracijai panaudosime program Srao formavimas. ioje programoje yra sukurta klas DinSar, kurioje yra apraytas kintamasis P (dinaminio srao pradios rodykl), konstruktorius, destruktorius, bei metodai sraui formuoti ir spausdinti. Programa naudoja klass DinSar objekt A. Klasje yra keturi metodai: srao formavimui paraytas metodas Formuoti. Jame yra imami sveiki skaiiai i failo ir perduodami metodui Elementas, kuris sukuria dinamin element su ta reikme ir prijungia prie formuojamo srao pradios (steko formavimo bdas); srao perirai yra metodas Spausdinti, kuris srao element reikmes surao ekrane viena eilute; klass DinSar konstruktorius DinSar sukuria objekt A ir io objekto srao pradios rodyklei P suteikia reikm NULL, o destruktorius ~DinSar naikina i atminties sra ir objekt A. Detaliau veiksmai bus aptariami atskiruose skyreliuose.
// Srao formavimas (stekas) #include <iostream.h> #include <stdio.h> #include <stdlib.h> // Struktros tipo apibrimas typedef struct list {int sk; struct list *next; } sar; // Klass Dinsar apibrimas class DinSar { sar *P; // Srao pradia public: DinSar(); // Konstruktorius ~DinSar(); // Destruktorius void Formuoti(FILE *); // Formuoja sra void Elementas(int); // Prijungia element void Spausdinti(); // Spausdina sra }; // Pagrindin programa void main() { FILE *D;

106

} // Konstruktorius DinSar::DinSar() { P = NULL; } // Destruktorius DinSar::~DinSar() { sar *D = P; while(P != NULL) { D = P; // Rodykl naikinam element P = P->next; // Kito elemento adresas delete( D ); } // Elemento naikinimas } // Formuoja netiesiogin sra void DinSar::Formuoti(FILE *F) { int k; while(!feof(F)) { fscanf(F, "%i", &k); Elementas(k); } } // Prijungia element void DinSar::Elementas(int Sk) { sar *R; R = new sar; // Naujo elemento sukrimas R->sk = Sk; // Upildymas duomenimis R->next = P; // Prijungimas prie srao P = R; // Srao pradios pakeitimas } // Srao spausdinimas void DinSar::Spausdinti() { sar *D = P; while(D != NULL) { cout << D->sk << " "; // Reikms spausdinimas D = D->next; } // Kito elemento adresas cout << "\n"; }

DinSar A; // Klass DinSar objektas D = fopen("Duom.dat", "r"); if (D == NULL) { cout << "Failo 'Duom.dat' nepavyko atidaryti"; exit (1); } A.Formuoti(D); // Formuojamas sraas fclose(D); A.Spausdinti(); // Spausdinamas sraas A.~DinSar();

107

7.3. Tiesinio srao formavimo iliustracija


Srao formavimo esm sudaro nauj element prijungimas prie srao. Metodo Formuoti vaidmuo yra organizuoti nuosekl duomen skaitym i failo ir j raym dinamin sra. Metodui Elementas perduodama nauja reikm k. Metodas Elementas sukuria nauj element, j upildo duomenimis ir prijungia formuojamo srao pradioje (steko principas), pakeisdamas srao pradios adres. Srao formavimo fragmentas:
typedef struct list { int sk; struct list *next; } sar; // Formuoja netiesiogin sra void DinSar::Formuoti(FILE *F) { int k; while(!feof(F)) { fscanf(F, "%i", &k); Elementas(k); } } // Prijungia element void DinSar::Elementas(int Sk) { sar *R; /*1*/ R = new sar; /*2*/ R->sk = Sk; /*3*/ R->next = P; /*4*/ P = R; }

NULL

7.3 pav. Rodykls P reikm prie cikl

Metodo Formuoti darbo pradioje formuojamas sraas yra tuias, t.y. srao pradios rodykls P reikm yra lygi NULL. Jeigu failas bus tuias, tai tokia reikm ir pasiliks metodui baigus darb. i situacija grafikai parodyta 7.3 pav. Tarkime duomen faile Duom.dat yra tokia skaii seka: 18 7 4 9 Pirm kart cikle (7.4 pav.) i failo perskaitoma reikm k = 18. Ji perduodama metodui Elementas. is metodas sukuria nauj element 108

su ta reikme (1 ir 2 sakiniai), po to jis prijungiamas prie srao pradios (3 sakinys), o srao pradios rodykl perkeliama prie to naujo elemento (4 sakinys), t.y. naujasis elementas tampa pirmuoju srae. Antr kart cikle gauta nauja reikm k = 7 tampa nauju elementu jau turimo srao pradioje (7.5 pav.).
P NULL 18 R NULL Sukuriamas elementas, kurio adres saugo rodykl R, ir upildomi laukai: 1, 2, ir 3 veiksmai.

P 18 R NULL

Srao pradia yra naujas elementas, kurio adres saugo rodykl R. Tas adresas yra uraomas rodyklje P. 4 veiksmas.

7.4 pav. Pirmasis elementas srae

Perklus visus faile esanius skaiius sra, srao pradios rodykl P rodys srao pradi (saugo pirmojo srao elemento adres). Suformuoto srao vaizdas parodytas 7.6 pav. Matome, kad suformuotas sraas saugo failo duomenis prieinga tvarka, nes nauji elementai buvo prijungiami prie srao pradios. Pastaba. Veiksmuose su srao elementais srao pradios rodykls P prarasti negalima, nes tuomet srae esantys duomenys bus neprieinami (prarasti).
P 18 NULL 7 R Pirmuoju veiksmu sukuriamas naujas elementas, kurio adres saugo rodykl R. Antruoju veiksmu raoma reikm k = 7

109

18 NULL 7 Treiuoju veiksmu naujas elementas prijungiamas prie srao pradios.

18 NULL 7 Ketvirtuoju veiksmu srao pradios rodykl perkeliama prie naujo elemento. 7.5 pav. Antrasis elementas srae

9
P

18
NULL

7.6 pav. Suformuotas sraas: faile buvo skaiiai 18 7 4 9

7.4. Tiesinio srao perira


Vienas i daugelio veiksm su srao elementais yra nuosekli j perira nuo srao pradios iki galo spausdinant duomenis. Tam panaudojama papildoma rodykl, kurios pradin reikm yra srao pradios rodykls P saugomas adresas. Toliau nuosekliai darbins rodykls reikm keiiama kito elemento i srao reikme tol, kol peririmas visas sraas (7.7 pav.).
void DinSar::Spausdinti() { sar *D = P; while(D != NULL) { cout << D->sk << " "; D = D->next; } cout << "\n";

// Reikms spausdinimas // Kito elemento adresas

110

Turintiems programavimo gdius silomas lakonikesnis funkcijos uraas:


void DinSar::Spausdinti() { sar *D = P; while(D) { cout << D->sk << " "; D = D->next; } cout << "\n"; }

// Reikms spausdinimas // Kito elemento adresas

Kiekviena programa privalo tvarkyti naudojam atmint taip, kad nesusidaryt avarini situacij. Vienas i toki veiksm yra nebereikalingo srao paalinimas i atminties. Pavyzdio programoje tam skirta destruktorius ~DinSar. ia naudojama papildoma rodykl D alinamo elemento adresui atsiminti. Sraas nuosekliai peririmas naudojant jo rodykl P, kuri turi srao pradios adres. Pirmu veiksmu atsimenamas srao pradios elemento adresas (D = P). Po to srao pradia yra perkeliama prie tolimesnio elemento (P = P->next;), o atjungtas nuo srao elementas D yra paalinamas. 9
P D Darbinei rodyklei D suteikiamas srao pradios adresas: D = P; Galima atspausdinti pirmojo elemento reikm 9: cout << D->sk;

18
NULL

9
P D

18
NULL

Pereinama prie kito elemento: D = D->next; Galima atspausdinti elemento reikm 4: cout << D->sk;

111

9
P D

18
NULL

Pereinama prie kito elemento: D = D->next; Galima atspausdinti elemento reikm 7: cout << D->sk;

9
P D

18
NULL

Pereinama prie kito elemento: D = D->next; Galima atspausdinti elemento reikm 18: cout << D->sk;

9
P D NULL

18
NULL

Pereinama prie kito elemento: D = D->next; Papildoma rodykl D gauna paskutinio elemento ryio dalyje esant adres NULL. i reikm yra srao periros pabaigos poymis. 7.7 pav. Srao element perira

7.5. Tiesinio srao papildymas


Srao papildymas naujais elementais galimas: srao pradioje; srao pabaigoje; srao viduje. Naujo elemento prijungimas srao pradioje sutampa su srao formavimo ciklo veiksmais. Naujo elemento prijungimas srao gale yra tapatus elemento terpimui srao viduje po nurodyto elemento. Veiksm schema parodyta 7.8 pav. ir 112

7.9 pav. Patikrinkite, ar tikrai tinka tie patys veiksmai, kai R rodo paskutin srao element (papildymas gale). 9
P R 123

18
NULL

NULL

Rodykl R rodo element, po kurio reikia terpti nauj element S. Jis suformuotas pilnai. Adresin dalis turi tuio adreso reikm.

7.8 pav. Nauj element S reikia terpti u elemento R

9
P R

18
NULL

123

Naujam elementui S suteikiamas adresas elemento, esanio toliau u elemento R: S->next = R->next; Elemento R rodykl nukreipiama nauj element: R->next = S;

7.9 pav. Naujo elemento terpimas

Atskiras srao papildymo atvejis yra tada, kai sraas visikai tuias. Tuomet pakanka srao pradios rodyklei P suteikti naujo elemento adres:
P = S;

terpimas prie nurodyt element tokio tipo srauose negalimas, nes elementai susieti rodyklmis viena kryptimi. Galimas tik vienas atvejis: terpti prie pirmj, kas tolygu sra papildyti pradioje nauju elementu. terpim prie galima pakeisti terpimu po. Tam reikia surasti element, esant prie mus dominant. Pavyzdiui, reikia rasti element, esant prie didiausi:
sar *R, *R1, *T,*T1; // Didiausios reikms elementas // Elementas, esantis prie didiausi // Papildomos rodykls srao perirai

113

T1 = P; T = P; R1 = P; R = P; while(T != NULL) { if(T->sk > R->sk) { R1 = T1; R = T; } T1 = T; T = T->next; }

Perirjus sra iki galo, rodykl R rodys element su didiausia reikme, o rodykl R1 rodys element, esant prie didiausi. Jos abi rodys pirmj element, kai jo reikm srae didiausia. Tai reikia, kad veiksmuose su sraais visuomet btina nagrinti visas galimas situacijas. terpim prie galima atlikti paprasiau. Jeigu darbo su srau veiksmai neprietarauja element reikmi keitimui vietomis, tuomet siloma tokia terpimo veiksm seka: Turime surast element R, prie kur reikia terpti element S; Sukeiiamos R ir S element reikms (ia int k;):
k = R->sk; R->sk = S->sk; S->sk = k;

terpiamas elementas S po elemento R: S->next = R->next; R->next = S;

7.6. Tiesinio srao element alinimas


Tai prieingas veiksmas terpimui, todl veiksmai analogiki. alinant nurodyt element, btina nagrinti jo padt srae. Jeigu tai pradios elementas, jis paalinamas srao pradios rodykl P perkeliant sekant element: P = P->next;
delete(R);

// alinamas elementas R
// yra pirmas, t.y. R = P

Klasikinis elemento paalinimo i srao atvejis yra, kai turime rodykl alinamj element R ir prie j esant R1 (7.10 pav.).

114

9
P

18
NULL

R1

R1->next = R->next

7.10 pav. Elemento paalinimas

alinant elementus btina atlaisvinti atmint, kuri jie uima. Tam naudojama funkcija delete. Labiau patyrs programuotojas ras lakonikesni priemoni veiksmams atlikti. Kaip vien i j galima pasilyti nurodyto elemento R alinimui (7.11 pav.): *R = *R->next; ia yra tolesnio elemento turinio perklimas nurodyt. Tuo sunaikinamas elemento R turinys. Srae turime du vienodus elementus, kuri tik vienas prieinamas. 9
D

18
NULL

R
7.11 pav. Sraas po elemento paalinimo

Pastaba: io veiksmo negalima taikyti, kai R rodo paskutin element, nes toliau jau nra kit element. iam atvejui btina atskira veiksm grup. Tokios element alinimo procedros negalima taikyti sudtingose srainse struktrose, kur duomen element adresai naudojami naujoms sra sekoms formuoti. Duomenys negali keisti savo pradinio adreso.

7.7. Tiesinio srao element tvarkymas


Tipikiausias srao element tvarkymo bdas yra rikiavimas. Paprasiausias atvejis yra, kai leidiama keisti elementuose duomenis vietomis (analogija su masyvais). Toks bdas priimtinas, kai duomen 115

struktra elemente nesudtinga arba duomen apimtis nedidel. Visais atvejais tikslinga elemente turti tik vien lauk duomenims nurodyti, o duomen pilna hierarchin struktra yra apraoma atskirai.
void DinSar::Rikiavimas() { sar *R = P, *R1; int k; while(R != NULL) { R1 = R->next; while(R1 != NULL) { if (R1->sk > R->sk) { k = R->sk; R->sk = R1->sk; R1->sk = k; } R1 = R1->next; } R = R->next; } }

// Reikmi sukeitimas

Programose dana situacija, kai negalima keisti srao element duomenis vietomis. Reikia sukeisti element sek srae, t.y. keiiamos nuorodos. Norint sukeisti vietomis srae du elementus, reikia turti rodykles ne tik keiiamus elementus, bet ir prie juos esanius. ia reiks pasirpinti keiiam element kaimynais prie ir po (7.12 pav.).

NULL

R1

S1

7.12 pav. R ir S rodo keiiamus vietomis elementus

Reikia sukeisti vietomis elementus R ir S. Tai galima padaryti taip: R1 elemento kaimynu po padaromas elementas S:
R1->next = S; S1->next = R;

S1 elemento kaimynu po turi bti elementas R: Atsimename elemento po R adres:

116

pap = R->next;

Elementas R turi rodyti element po S:


R->next = S->next; S->next = pap;

Elementas S turi rodyti element po R:

Reikia neumirti patikrinti keiiam element srae padt (pradioje, gale ar viduje). Gaunama sudtinga veiksm seka. ymiai paprasiau suformuoti nauj tvarking sra. Tai galima padaryti taip: rasti duotame srae element pagal duot rikiavimo rakt; paalinti surast element i duoto srao; prijungti element prie naujo srao.
void DinSar::Surikiavimas() { sar *T = P, // T senojo srao pradia *D, *D1, *S, *S1; P = NULL; // Naujas sraas tuias while(T) { D = T; // Gretimi du elementai srao perirai D1 = T; S = T; S1 = T; // Didiausias S ir prie j esantis S1 while(D) { // Didiausio paieka if (D->sk > S->sk) { S = D; S1 = D1; } D1 = D; D = D->next; } if (S == T) T = T->next; // alinimas else S1->next = S->next; S->next = P; // Prijungimas prie naujo srao P = S; } // Naujo srao pradia }

iame pavyzdyje nebuvo kuriami nauji elementai. Jie buvo sujungiami nauja seka, pasinaudojant jau inomomis operacijomis. T pat rezultat galima gauti trumpesniu keliu. Silome panagrinti burbuliuko bdu rikiuojani funkcij:
void DinSar::RikiavBurb() { sar **T, *R;

117

int flag = 1; while(flag) { flag = 0; T = &P; while((*T)->next) { if ((*T)->sk > (*T)->next->sk) { R = *T; *T = R->next; R->next = (*T)->next; (*T)->next = R; flag = 1; } T = &(*T)->next; } } }

Tvarkymo ir kiti veiksmai vienkrypiuose srauose yra sudtingi, reikalauja papildom darbo snaud. ymiai yra patogesni dvikrypiai sraai, kur kiekvienas elementas turi rodykles kaimynus prie ir po. Realiai vienkrypiai sraai naudojami su tam tikrais apribojimais: stekai, eils, dekai.

7.8. Eils formavimas


Visuose pateiktuose pavyzdiuose sraas buvo formuojamas naujus elementus prijungiant prie pradios, t.y. steko principu. Ne visuomet tai patogu. Galima sra formuoti j pateikimo eils tvarka (7.13 pav.). Formavimo procesas skaldomas du etapus: Pirmojo elemento sukrimas. Rodykls P ir G rodo pirmj element Kit element prijungimas gale. Reikalinga srao pabaigos rodykl G. Ji rodo element, po kurio reikia padti nauj element.

Papildykite klas tam skirtais metodais FormuotiEile ir ElementasEile ir juos ibandykite. Atkreipkite dmes naujo elemento sukrimo ir prijungimo skirtumus steko ir eils atvejais. 18
P 9

NULL

118

7.13 pav. Eils formavimas void DinSar::FormuotiEile(FILE *F) { sar *D = NULL, *G; int k; if (!feof(F)) { fscanf(F, "%i", &k); ElementasEile(&D, k); G = D; } while(!feof(F)) { fscanf(F, "%i", &k); ElementasEile(&G, k); } P = D; } void DinSar::ElementasEile(sar **P, int Sk) { sar *R; R = new sar; // Suformuojamas elementas R->sk = Sk; R->next = NULL; if (*P) { // Elementas prijungiamas gale (*P)->next = R; *P = R; } else *P = R; // arba jis dar pirmas srae } // Pirmas elementas // Galo rodykl G // Kiti elementai // Prijungimas gale

7.9. Stek tvarkymas


Stekai yra paprasiausi ir lengviausiai tvarkomi tiesiniai dinaminiai sraai. Juose nauji elementai terpiami srao pradioje, o vartojimui prieinamas tik pirmas elementas, kuris po to alinamas. Deklaruojant stekus, pakanka aprayti j element struktras ir rodykles stek pradias. Darbui su steku reikalingos dvi funkcijos: naujo elemento prijungimo prie srao pradios ir pirmojo elemento paalinimo i srao (prie tai tas elementas yra panaudojamas veiksmuose). 7.1 pratimas. Isiaikinkite pavyzdyje aprayt simboli steko tvarkymo funkcij sudarymo principus ir patikrinkite demonstracins programos darb. Programoje simboliai yra atrenkami ir siuniami stek i joje deklaruotos ir inicializuotos simboli eiluts. 119

// Veiksmai su steku #include <iostream.h> struct stack { char d; // Steko element tipas struct stack *next; }; class stekas { public: stack *first; // Steko realizacija (rodykl) stekas() { first = NULL; } // Konstruktorius ~stekas() {}; // Destruktorius stack *Get(){ return first; }; void Push(char); // Steko papildymas void Ekranas(stack *); // Steko perira char Pop(); // Steko skaitymas }; // Pagrindin programa main() { // Tvarkoma eilut ir rodykl j char prad[] = "abcdefgh", *p = prad; stack *d; // Darbinis kintamasis stekas A; // Objekto apraymas // Tvarkomos eiluts parodymas ekrane cout << "Siunciami i steka simboliai: " << p << endl; while(*p) A.Push(*p++); // Steko upildymas cout << "Steko patikrinimas:\n"; d = A.Get(); A.Ekranas(d); // Steko turinio "abcdefgh" parodymas cout << "Skaitymas po viena simboli:\n"; while(A.first) cout << A.Pop() << endl; // Steko ivalymo kontrol if (!A.first) cout << "Tuscias stekas\n"; A.~stekas();

} // Steko papildymas void stekas::Push(char e) { stack *newe; newe = new stack; // Atminties skyrimas newe->d = e; // Naujo elemento reikm newe->next = first; // Senos steko dalies prijungimas first = newe; // Naujas steko adresas }

120

// Rekursyvus steko turinio patikrinimas void stekas::Ekranas(stack *p) { if (p) { // Rekursijos nutraukimo slyga cout << p->d; // Reikms parodymas ekrane Ekranas(p->next);} // Rekursyvus kreipinys tolimesn element else cout << endl; } // Elemento paalinimas i steko char stekas::Pop() { stack *old= first; // Adreso isaugojimas char e = first->d; // Reikms isaugojimas first = first->next; // Pirmo elemento alinimas delete old; // Atminties ilaisvinimas return e; // Paalinto elemento reikm }

Rekursyvi funkcija Ekranas stekui yra perteklin. Joje demonstruojama, kad rekursyvaus tipo dinamini struktr element perrinkim galima glaustai aprayti rekursyviomis funkcijomis. Element perrinkimui taip pat galima vartoti funkcijos viduje deklaruojam lokali rodykl. Naudojant i perrinkimo technik, galima sudaryti toki funkcijos Ekranas modifikacij:
// Ciklinis steko turinio patikrinimas void stekas::Ekranas1(stack *p) { stack *temp = p; // Pagalbin rodykl while(temp) { // Steko perrinkimo ciklas cout << temp->d; // Reikms parodymas ekrane temp = temp->next; } // Rodykl tolimesn element cout << endl; }

Standartins stek valdymo procedros yra labai paprastos ir greitos, todl stekai plaiai vartojami laikinam duomen saugojimui tiek taikomosiose, tiek sisteminse programose. Stekus galima realizuoti ne tik dinaminmis struktromis, bet ir kitais bdais: aparatros pagalba, vartojant specialius indeks registrus. Pavyzdiui, steko registro pagalba tvarkom steko atminties segment kompiliatoriai vartoja lokaliems kintamiesiems saugoti ir informaciniams ryiams tarp funkcij palaikyti.

121

7.10. Eils ir dekai


Eils (7.14 pav.) nuo stek skiriasi tuo, kad jas duomenys yra siuniami ir i j atrenkami prieinguose srao galuose. Pertvarkant stek eil, galima vien jo tvarkymo procedr, pavyzdiui Pop, palikti, o antrj reikia perrayti panaudojant rekursyvi srao perir eils pabaigos paiekai. Suradus pabaig, eil papildoma tokiu pat bdu, kaip ir paprastas sraas. Taip sudarytos funkcijos Add pavyzdys yra pateiktas 7.2 pratime. 7.2 pratimas. ia pateikta eils papildymo funkcija, kuri pritaikyta eilms sudarytoms i 7.1 pratime apraytos struktros stack element. Skaitytojui siloma savarankikai sudaryti ciklin ios funkcijos variant.
// Eils papildymas void stekas::Add(stack *p, char e) { if (!p) { // Jeigu eil tuia p = new stack; p->next = NULL; p->d = e; first = p; } // Eilje atsiranda 1 elementas else if (!p->next) { // Rekursijos pabaigos slyga p->next = new stack; // Naujo elemento prijungimas p->next->next = NULL; p->next->d = e; } else Add(p->next, e); // Rekursija }

Norint i eils padaryti dek, reikia sudaryti dar vien funkcij, kuri leist paalinti galinius eils elementus. Rekursyvios galinio eils elemento alinimo funkcijos realizacija anksiau apraytai struktrai stack atrodo taip:
// alinimas i eils galo char stekas::Del(stack *p) { char s; // alinamasis elementas if (!p->next) { // Jeigu eilje tik 1 elementas s = p->d; delete first; // alinamas pirmas eils elementas first = NULL; return s; }

122

else if (!p->next->next){ s = p->next->d; delete p->next; // alinamas priepaskutinis eils elementas p->next = NULL; return s; } // Jeigu eilje daugiau kaip vienas elementas else Del(p->next); // Rekursija }

Eils pabaigos paiekai vartoti rekursyv arba ciklin jos element perrinkim yra neracionalu. Toks paiekos bdas gali bti pateisinamas tiktai trumpose eilse. Tvarkant ilgas eiles, j element perrinkimo patartina vengti. Tai galima padaryti, papildant eil galinio elemento rodykle, kurios reikm bt vartojama ir keiiama papildant eil naujais elementais. Tokios eils ioriniam apraymui rekomenduojama sudaryti dviej rodykli struktr ir j tvarkyti modifikuotomis steko tvarkymo funkcijomis. Kaip tai yra daroma, iliustruojama 7.3 pratime.
first NULL last

7.14 pav. Eil nusako pradios ir pabaigos rodykls

7.3 pratimas. Naudodami pateiktus simboli eils su dviem rodyklm struktros ir jos tvarkymo funkcij apraymus, sudarykite demonstracin program, kuri leist patikrinti i funkcij darb.
struct stack { char d; struct stack *next; }; // Srao element tipas

struct list { // Eil su dviem iorinm rodyklm stack *first; // Pradios rodykl stack *last; }; // Pabaigos rodykl // Klass apraas class eile { public: list que; // Eils realizacija eile() { // Konstruktorius que.first = NULL; que.last = NULL; };

123

}; // Eils tvarkymo funkcij realizacijos // Eils papildymas gale int eile::Add(char e) { // F-jos Add reikm 1 pranea, kad papildyta skmingai stack *newe; if (!(newe = new stack)) return 0; // Ar yra atmintyje vietos? newe->d = e; // Naujas elementas newe->next = NULL; // Pabaigos ym if (!que.last) { // Jeigu eil tuia que.last = newe; // Naujas pabaigos adresas que.first = newe; } // Naujas pradios adresas else { (que.last)->next = newe; // Elemento prijungimas que.last = newe; } // Naujas pabaigos adresas return 1; // Praneimas apie skming pabaig } // Pradinio elemento paalinimas char eile::Pop() { stack *old= que.first; // Adreso isaugojimas if (!(que.first)) return '\0'; // Praneimas apie tui eilut char e = (que.first)->d; // Reikms isaugojimas que.first = (que.first)->next; // Pirmo elemento naikinimas delete old; // Atminties ilaisvinimas return e; // Reikms grinimas }

~eile() {}; int Add(char); char Pop();

// Destruktorius // Eils papildymas gale // Pradinio elemento paalinimas

7.11. iediniai sraai


Tiesinio vienkrypio srao galiniame elemente raius pirmojo elemento adres, gausime iedin sra: last->next = first; (7.15 pav.).
first 1 2 3 4 5 last

7.15 pav. iedin srao struktra

124

Toliau veiksmuose patogu turti tik vien iorin rodykl last, kuri saugos iedo galinio (paskutinio) elemento adres, o galinio elemento ryio dalyje bus saugoma iedo pradinio elemento adresas (7.16 pav.). T rodykl (last) toliau vadinsime iedo rodykle. Pavadinimai pradia ir galas iede yra slyginiai. Naudojant iuos pavadinimus bus lengviau aikintis veiksmus iede.
Pradia 1 2 3 4 5 Pabaiga last

7.16 pav. iedinis sraas

iediniai sraai gali bti vartojami eili realizavimui sprendiant tokius udavinius, kuriuose reikalinga daugel kart perirti t pat duomen rinkin. iedams yra taikomos tokios standartins tvarkymo operacijos: tuio iedo inicializavimas; naujo elemento terpimas iedo pradioje; papildymas nauju elementu pabaigoje; pradinio elemento paalinimas; paieka ir paalinimas. Tuio iedo, kuris ymimas tuia rodykle NULL, inicializavimas yra toks pats, kaip ir tiesinio srao. Tuo tarpu, kit operacij realizavimas skiriasi. Pavyzdiui, papildant sra naujais elementais, tenka taikyti skirtingas procedras tuiam ir netuiam sraui. Paiekos ir paalinimo operacijos metu turi bti randamas ir paalinamas elementas su duotja rakto reikme. Paieka yra vykdoma nuosekliai perrenkant iedo elementus. alinant reikia iskirti du atvejus: kai yra alinamas elementas, kur rodo iedo iorin rodykl, yra paskutinis ir kai alinamas elementas iede yra vienintelis. Pirmuoju atveju, turi bti keiiama iedo iorins rodykls reikm, o antruoju atveju, iedo iorins rodykls reikmei priskiriama NULL. Atvej, kai reikia alinti iede esant element, kur nerodo iedo rodykl, visuomet galima pakeisti atvej, kai alinamas elementas, kurio adres saugo iedo rodykl.

125

7.4 pratimas. Sudarykite demonstracin program, kuri leist patikrinti veiksmus su iediniu srau. Naudokite klas ziedas ir jos tvarkymo metod apraymus.
struct stack { char d; // iedo element tipas struct stack *next; }; class ziedas { public: stack *last; // iedo realizacija (rodykl) ziedas() { last = NULL; };// Konstruktorius ~ziedas() {}; // Destruktorius int Ins(char); // terpimas iedo pradioje int Add(char); // terpimas iedo pabaigoje char Del(); // Pirmojo iedo elemento paalinimas char DelSerch(char); // Elemento paieka ir alinimas }; // iedo tvarkymo funkcij realizavimas // terpimas iedo pradioje // Funkcijos reikm 1 pranea, kad papildyta skmingai int ziedas::Ins(char e) { stack *newe; if (!(newe = new stack)) // Ar yra atmintyje vietos? return 0; newe->d = e; // Naujas duomen elementas if (last) { // Netuio iedo slyga newe->next = last->next; // Pirmo elem. adreso perdavimas last->next = newe; } // Naujas pradios adresas else last = newe->next = newe; // Tuio iedo papildymas return 1; // Praneimas apie skming pabaig } // iedo papildymas pabaigoje // Funkcijos reikm 1 pranea, kad papildyta skmingai int ziedas::Add( char e ){ stack *newe; if (!(newe = new stack)) // Ar yra atmintyje vietos? return 0; newe->d = e; // Naujas duomen elementas if (last) { // Netuio iedo slyga newe->next = last->next; // Pirmo elem. adreso perdavimas last->next = newe; // Elemento prijungimas pabaigoje last = newe; } // Naujas pradios adresas

126

} // Pirmojo iedo elemento paalinimas char ziedas::Del() { stack *temp; // Pagalbiniai kintamieji char e; if (!last) return '\0'; // Pranesimas apie klaida if (last == last->next) { // iede vienas elementas temp = last; // alinamo elemento adresas last = NULL; // Nauja iorin rodykl } else { // iede yra keletas element temp = last->next; // alinamo elemento adresas last->next = last->next->next; // alinimas i iedo } e = temp->d; // Reikms isaugojimas delete temp; // Atminties ilaisvinimas return e; // Reikms grinimas } // Elemento paieka ir paalinimas iede char ziedas::DelSerch(char e) { stack *temp = last; // Pagalbiniai kintamieji stack *t; if (!last) return '\0'; // Praneimas apie klaid while (((temp->next) != last) && ((temp->next->d) !=e)) temp = temp->next; // Element perrinkimas if ((temp->next->d) == e) // Jeigu elem. buvo surastas if (last == temp->next) // Galinis elementas if (temp == last) { // Jeigu iede 1 elementas last = NULL; // Tuias iedas delete temp; } else { temp->next = last->next; // Elemento alinimas delete last; last = temp; } // Nauja iorin rodykl else { t = temp->next; temp->next = temp->next->next; delete t; } }

else last = newe->next = newe; // Tuio iedo papildymas return 1; // Praneimas apie skming pabaig

127

7.12. Surikiuoto srao papildymas iede


Tiesini sra element rikiavimo tvark galima vertinti j formavimo funkcijose ir jas sudaryti taip, kad, papildant sra naujais elementais, j rikiavimo tvarka ilikt. Tokios funkcijos yra sudaromos i dviej dali. Pirmojoje dalyje yra iekoma srao vieta, kurioje reikia terpti nauj element, o antrojoje apraoma terpimo procedra. Jeigu simboli srao elementai yra saugomi alfabeto tvarka, naujas elementas turi bti raomas prie pirmj srao element, kurio kodas yra didesnis u papildanio simbolio kod arba, jei tokio elemento nra, srao gale. Surikiuoto srao papildymo funkcijos realizacija iede:
void ziedas::Terpti(char e) { stack *t, *temp; // Pagalbiniai kintamieji if (!last) { // Jeigu iedas tuias last = new stack; last->d = e; last->next = last; } else // Jeigu terpiama prie pirm iedo element if (last->next->d > e) { t = new stack; t->d = e; t->next = last->next; last->next = t; } else // Jeigu terpiama po paskutinio iedo elemento if (last->d < e) { t = new stack; t->d = e; t->next = last->next; last->next = t; last = t; } else { // terpimo vietos paieka ir terpimas temp = last->next; while ((temp != last) && ((temp->next->d) < e)) temp = temp->next; t = new stack; t->d = e; t->next = temp->next; temp->next = t; } }

128

7.13. Sraai su neapibrto tipo elementais


Sraai, kuri elementuose tiesiogiai saugomos j reikms, nra universals, nes j tvarkymo funkcij realizacijos priklauso nuo element tipo. Norint sudaryti universalius sraus su vairi tip elementams tinkaniomis tvarkymo funkcijomis, reikia srae saugoti ne paias element reikmes, o rodykles jas. Geriausiai iam tikslui tinka neapibrto (void) tipo rodykls, kurios yra suderinamos su visais kitais rodykli tipais:
struct stack { void *d; struct list *next;

};

Sra su neapibrto tipo duomen element rodyklmis tvarkymo veiksmus reikia atskirti nuo elementams skiriamos atminties tvarkymo veiksm ir veiksm, kurie susij su srae saugom duomen analize, j interpretavimu. Dauguma sra tvarkymo veiksm yra universals ir juos galima aprayti tokiomis funkcijomis, kurios tinka visiems rodykli nurodomiems element tipams. Tuo tarpu, su duomen interpretavimu susij veiksmai paprastai bna specializuoti, priklauso nuo srao element reikmi tipo. Rodykli sra formavimas yra labai galinga duomen tvarkymo priemon, kuri vairioms duomen saugojimo struktroms gali suteikti naujas savybes. Pavyzdiui, tokio srao sudarymas gali pakeisti masyvo rikiavim. Be to, vienam masyvui galima sudaryti kelis rodykli sraus, apraanius skirtingus jame saugom duomen perrinkimo bdus. Apraant neapibrto tipo rodykli sra nurodom duomen interpretavimo operacijas, reikia apibrti i rodykli interpretavimo bd. Interpretavimo bdas yra apibriamas tokia struktra:
(<Duomen tipas>*) <Elemento duomen rodykl>

7.5 pratimas. Patikrinkite pratime pateiktos programos darb. Isiaikinkite joje aprayto universalaus steko tvarkymo funkcij sudarymo principus ir i funkcij pritaikym simboli stekui tvarkyti. Programoje taip pat iliustruojamas specializuotos funkcijos Show sudarymas, kuri gali perduoti ekran tik simboli steko reikmes.
// Saraas su neapibrto tipo elementais #include <iostream.h> char line[] = "Sula"; // Simboli masyvas

129

struct stack { // Universalus srao elementas void *d; // Duomen rodykl struct stack *next; }; class stekas { public: stack *first; // Steko realizacija (rodykl) stekas() { first = NULL; };// Konstruktorius ~stekas() {}; // Destruktorius stack *Get() { return first; }; // Universalios tvarkymo funkcijos void Push(void *); // Papildymas void *Pop(); // Elemento paalinimas void Show(stack *); // Steko turinio parodymas ekrane }; // Pagrindin programa main() { stack *d; // Papildomas kintamasis stekas A; // Objekto apraymas int i = 0; // Simboli masyvo indeksas cout << "Tvarkoma eilute: " << line << endl; while(line[i]) // Simboli masyvo pabaigos slyga A.Push(&line[i++]); // Rodykli steko sudarymas cout << "Steko rodomi simboliai: " << endl; d = A.Get(); A.Show(d); cout << "Trinama rodykle i pirma simboli "; cout << *((char *) A.Pop()) << endl; cout << "Liko rodykles i siuos simbolius: \n"; d = A.Get(); A.Show( d ); } // Srao tvarkymo funkcij realizacijos // Steko papildymas void stekas::Push(void *e) { stack *newe; // Papildomas kintamasis newe = new stack; // Atminties skyrimas newe->d = e; // Naujo elemento duomen rodykl newe->next = first; // Senos steko dalies prijungimas first = newe; // Naujas steko adresas }

130

// Elemento paalinimas i steko void * stekas::Pop() { stack *old = first; // Adreso isaugojimas void *e = first->d; // Reikms rodykls isaugojimas first = first->next; // Pirmo elemento alinimas delete old; // Atminties ilaisvinimas return e; } // Rekursyvus steko patikrinimas void stekas::Show(stack *p) { if (p) { // Interpretavimas ir ivedimas ekran cout << *(char *)(p->d); Show(p->next); } // Rekursyvus kreipinys tolimesn element else cout << endl; }

7.14. Sra su neapibrto tipo elementais panaudojimo pavyzdiai


1 pavyzdys. Tekstiniame faile Stud.dat turime student sra: pavard, vardas, paymi vidurkis. Reikia suformuoti du student sraus: vien - surikiuot pagal abcl ir antr - surikiuot paymi vidurkio majimo tvarka. iai uduoiai atlikti yra daug bd. Paprasiausias yra suformuoti du nepriklausomus sraus, kurie surikiuojami pagal nurodyt rakt. Kitas gali bti toks: duomenys suraomi masyv ir suformuojami du rodykli duomenis sraai pagal nurodyt rakt. Vietoje masyvo galima panaudoti dinamin sra. Silome vienu srau saugoti duomenis ir rezultatus. Duomenys suraomi sra ir sutvarkomi pagal abcl. Srae rezervuojame dar vien lauk nuorodai duomenis. Tas nuorodas surikiuojame pagal student mokymosi vidurk. Failo Stud.dat pavyzdys.
Lapinas Vilkas Baisus Katinas Baisus Pilkas Katinas Didysis 4.5 6.85 3.6 9.5

131

#include #include #include #include #include

<iostream.h> <stdio.h> <stdlib.h> <string.h> <conio.h>

typedef struct studentas { char pavard[10]; char vardas[10]; float vidur; }; typedef struct sar { studentas *st; studentas *vd; sar *next; }; // Klass apraymas class student { sar *P; // Srao pradia public: student() { P = NULL; }; // Konstruktorius void Formuoti(FILE *); // Formuoja sra void Spausdinti(int); // Spausdina sra void Tvarkymas(int); // Tvarkymas }; // Pagrindin programa void main() { FILE *D; student A; clrscr(); D = fopen("stud.dat", "r"); if (D == NULL) { cout << "Failo Stud.dat nepavyko atidaryti!"; exit (1); } A.Formuoti(D); fclose(D); A.Spausdinti(0); // Nesurikiuotas A.Tvarkymas(1); // Rikiavimas pagal abcl A.Tvarkymas(0); // Rikiavimas pagal vidurk A.Spausdinti(1); // Abclinis sraas A.Spausdinti(0); // Sraas pagal vidurk } // Student srao formavimas void student::Formuoti(FILE *F) { sar *D = NULL;

132

} // Student srao spausdinimas void student::Spausdinti(int kaip) { sar *D = P; while(D) { if (kaip) cout << D->st->pavard << " " << D->st->vardas << " " << D->st->vidur << "\n"; else cout << D->vd->pavard << " " << D->vd->vardas << " " << D->vd->vidur << "\n"; D = D->next; } cout << "--------------------\n"; } // Student srao rikiavimas void student::Tvarkymas(int kaip) { // kaip = 1 tvarko pagal abcl st rodykl // kaip = 0 tvarko pagal vidurk vd rodykl sar *R = P, *R1; studentas *k; while(R != NULL ) { R1 = R->next; while(R1 != NULL) { if (kaip) { if (strcmp(R1->st->pavard, R->st->pavard) < 0) { k = R->st; R->st = R1->st; R1->st = k; }} else if (R1->vd->vidur > R->vd->vidur) { k = R->vd; R->vd = R1->vd; R1->vd = k; } R1 = R1->next; } R = R->next; } }

while (!feof(F)) { D = new sar; D->st = new studentas; D->vd = D->st; fscanf(F, "%s%s%f", D->st->pavard, D->st->vardas, &D->st->vidur); D->next = P; P = D; }

2 pavyzdys. Tekstiniame faile Stud.dat turime student sra: pavard, vardas, paymi vidurkis. Yra trys kompiuteri klass, kurias priiri ir tvarko studentai. Reikia suformuoti student darbo klasse sra savaitei. Kasdien paskiriami trys studentai srao eils tvarka. 133

iam udaviniui sprsti patogiausias yra Modifikuojame ankstesnio pavyzdio program.


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

iedinis

sraas.

typedef struct studentas { char pavard[10]; char vardas[10]; float vidur; }; typedef struct sar { studentas *st; sar *next; }; // Klass apraymas class student { sar *P; // Srao pradia public: student() { P = NULL; }; // Konstruktorius void Formuoti(FILE *); // Formuoja sra void Spausdinti(); // Spausdina sra void Darbai(int, int); // Sraai darbui }; // Pagrindin programa void main() { FILE *D; student A; // Objekto apraymas clrscr(); D = fopen("stud.dat", "r"); if (D == NULL) { cout << "Failo Stud.dat nepavyko atidaryti!"; exit(1); } A.Formuoti(D); cout << "---------------------\n"; fclose(D); A.Spausdinti(); cout << "---------------------\n"; A.Darbai(3, 3); } // iedinio student srao formavimas void student::Formuoti(FILE *F) { sar *D = NULL; while(!feof(F)) { D = new sar;

134

} // Student srao spausdinimas void student::Spausdinti() { sar *D; if (P) { // Pirmojo spausdinimas D = P; cout << D->st->pavard << " " << D->st->vardas << " " << D->st->vidur << "\n"; D = D->next; while(D != P) { // Kit spausdinimas cout << D->st->pavard << " " << D->st->vardas << " " << D->st->vidur << "\n"; D = D->next; }} } // Darb sraas void student::Darbai(int Dien, int kiek) { sar *D = P; int i, k; if (!D) { cout << "Sraas tuias\n"; exit; } for(i=1; i<=Dien; i++) { cout << "Diena: " << i << "\n"; for(k=1; k<=kiek; k++) { cout << " " << D->st->pavard << " " << D->st->vardas << "\n"; D = D->next; }} }

D->st = new studentas; fscanf(F, "%s%s%f", D->st->pavard, D->st->vardas, &D->st->vidur); D->next = P; P = D; } if (P) { // Srao pabaigos paieka D = P; while(D->next) D = D->next; D->next = P; } // iedo sudarymas

135

8 skyrius. Dvikrypiai tiesiniai sraai


8.1. Srao struktra
Pagrindinis vienkrypi sra trkumas yra tas, kad juose galimas tik nuoseklus element perrinkimas. Dl to juose lta duomen paieka, neefektyvios su paieka susijusios tvarkymo operacijos. Siekiant ivengti io tiesini sra trkumo, yra sukurtos vairios tiesini sra modifikacijos. Pavyzdiui, realizuojant tiesiniame srae eil, jis yra papildomas iorine pabaigos rodykle, kuri leidia greitai papildyti sra nauju elementu gale. T pat efekt galima pasiekti iedinje tiesinio srao modifikacijoje. Taiau abi ios modifikacijos nepalengvina paiekos pagal poym ir galinio elemento alinimo operacij. Paiekai ir element alinimui geriau tinka dvikrypt tiesini sra modifikacija, kurios elementuose yra dvi rodykls, rodanios pirmesn ir tolimesn gretimus elementus, ir viena arba dvi iorins rodykls (8.1 pav.). Tokiuose srauose galima nuo bet kurio j elemento pasiekti visus kitus elementus. P 12 NULL
8.1 pav. Dvikrypio srao struktra

34

56

78 NULL

Dvikrypi sra element struktra:


Struct sar { int *S; sar *de; sar *ka; } // Duomen rodykl // Rodykl tolimesn element (dein) // Rodykl artimesn element (kair)

Dvikryptis sraas gali bti laikomas dviej vienkrypi sra kompozicija, todl jo tvarkymo funkcijos yra panaios i sra tvarkymo funkcijas. Pagrindinis skirtumas yra tas, kad tvarkymo 136

operacijose reikia formuoti dvi rodykles. Be to, galima sudaryti universalias element terpimo ir alinimo operacijas, kurios tinka visiems srao elementams, ne tiktai galiniams. Pradioje sraas tuias. Todl pirmojo elemento rodykls P (pradia) ir galinio elemento rodykls G (galas) reikms turi bti nulins NULL. Tuias sraas yra inicializuojamas deklaruojant nulines jo rodykles:
sar *P = NULL, *G = NULL;

8.2. Srao formavimas ir perira


Dvikryptis sraas tik P arba G rodykli atvilgiu yra analogikas vienkryiui sraui. Formuojant sra, kai nauji elementai prijungiami srao pradioje (rodykl P ), rodykls G atvilgiu nauji elementai bus jungiami srao gale. Ir atvirkiai. Darome ivad, kad io srao formavimui tinka veiksmai, kurie vykdomi vienkrypiame srae formuojant sra steko ir eils bdais.
// #include #include #include #include Dvikryptis sraas <iostream.h> <stdio.h> <stdlib.h> <conio.h> Rodykl element Rodykl dein Rodykl kair Srao pradia Srao galas }; // Konstruktorius // Destruktorius

typedef struct sar { int *S; // sar *de; // sar *ka; }; // // Klass apraymas class DviKryptys { sar *P; // sar *G; // public: DviKryptys() { P = NULL; G = NULL; ~DviKryptys(); sar *GetP() { return P; }; sar *GetG() { return G; }; void Formuoti(FILE *); // void Spausdinti(); // void SpausdintiAtv(); // };

Formuoja sra Spausdina sra Spausdina sra atvirkiai

137

// Pagrindin programa void main() { FILE *D; DviKryptys A; // Klass DviKryptys objektas clrscr(); D = fopen("Duom.dat", "r"); if (D == NULL) { cout << "Failo Duom.dat nepavyko atidaryti"; exit(1); } A.Formuoti(D); fclose(D); A.Spausdinti(); cout << "***********\n"; A.SpausdintiAtv(); A.~DviKryptys();

} // Srao formavimas, raant pradi void DviKryptys::Formuoti(FILE *F) { sar *R; // Darbinis kintamasis if (!feof(F)) { // Pirmojo elemento prijungimas G = new sar; P = G; P->S = new int; fscanf(F, "%i", P->S); P->ka = NULL; P->de = NULL; } while (!feof(F)) { // Likusi element prijungimas R = new sar; R->S = new int; fscanf(F, "%i", R->S); R->ka = NULL; R->de = P; P->ka = R; P = R; } } // Spausdina sra nuo pradios void DviKryptys::Spausdinti() { sar *D = P; while(D != NULL) { cout << *D->S << "\n"; D = D->de; } }

138

// Spausdina sra nuo galo void DviKryptys::SpausdintiAtv() { sar *D = G; while(D != NULL) { cout << *D->S << "\n"; D = D->ka; } } // Destruktorius DviKryptys::~DviKryptys() { sar *D = P; while(P != NULL) { D = P; P = P->ka; delete(D->S); delete(D); } }

Rodykl P rodo sra, kuriame duomenys saugomi atvirktine tvarka, o rodykl G rodo sra tiesiogine tvarka. Norint sukeisti rodykli reikmes srao tvarkos poiriu, reikia modifikuoti funkcij Formuoti. Silome tai padaryti patiems ir patikrinti. Srao perirai tinka vienkrypio srao periros algoritmas. Sraas nagrinjamas panaudojant vien rodykl: P ir de lauko reikmes arba G ir ka lauko reikmes. Turime galimyb sra perirti tiesiogine ir atvirktine tvarka. Tai demonstruoja spausdinimui skirtos funkcijos.

8.3. Srao papildymas


Galimos trys situacijos: naujo elemento prijungimas srao pradioje (P rodykls atvilgiu), srao gale (G rodykls atvilgiu), bet kurioje srao vietoje (rodykls P ir G nekinta).

Pirmos dvi situacijos atitinka vieno elemento prijungimo veiksmams srao formavimo procese, todl atskirai j neaptarsime. Kuriant funkcij, skirt naujo elemento terpimui, reikia patikrinti situacij ir atlikti jai skirtus veiksmus (prie pirm element, po paskutinio elemento arba srao viduje). Elemento terpimas srao viduje po elemento R yra tapatus veiksmams prie element R.
D->de = R; // Naujas elementas pamato savo naujus kaimynus

139

D->ka = R->ka; (R->ka)->de = D; R->ka = D;

// Elementas D jungiamas sra

terpiant nauj element D prie rodykls R nurodom srao element, reikia suformuoti keturias naujas, punktyrinmis linijomis parodytas, rodykles (8.2 pav.), kurios turi pakeisti dvi element ryius apraanias rodykles. Pradioje reikia sutvarkyti naujo elemento ryius su bsimais kaimynais srae, o po to pakeisti srao element ryius naujj element. P
<12> <34> <56> <78>

NULL NULL
<999>

8.2 pav. Naujo elemento D terpimas prie element R

Universalios dvikrypio srao papildymo funkcijos Terpti realizacija ir panaudojimo pavyzdiai:


void Terpti(sar *, int *); int x = 0, y = 100; // Metodo prototipas // terpiamos reikms

T = A.GetP(); A.Terpti(T, &x); // terpimas srao pradioje A.Terpti(T->de, &x); // terpimas prie antraj element. Jis privalo bti T = A.GetG(); Terpti(T, &y); // terpimas prie paskutin element // terpimas "prie" R element void DviKryptys::Terpti(sar *R, int *sk) { sar *D; D = new sar; // Naujas elementas D->S = sk; // Rodykl reikm

140

if (R == P) { D->de = P; D->ka = NULL; P->ka = D; P = D; } else { D->de = R; D->ka = R->ka; (R->ka)->de = D; R->ka = D; } }

// Kai R rodo pirm: padti pradioje

// Padti srae prie nurodyt R

8.4. Element alinimas


Universali element alinimo funkcija yra paprastesn, nes jai reikia suformuoti tik dvi naujas srao rodykles. ioje funkcijoje reikia atsivelgti atvejus, kai alinamas pradinis elementas, paskutinis elementas ir kai alinamas elementas i srao vidaus (8.3 pav.). Funkcija grina rodykl paalinto elemento duomen saugojimo viet (arba NULL). Tai reikalinga, nes yra alinama nuoroda srae duomenis, bet ne patys duomenys. Kaip elgtis su duomenimis sprendia duomen apdorojimo paprograms. alinimo funkcija skirta nurodyto elemento paalinimui. Tai reikia, kad prie tai buvo atlikta to elemento paieka. Jeigu elementas nebuvo surastas, tai ir nebus panaudota alinimo funkcija. P
<12> <34> <56> <78>

NULL NULL R
8.3 pav. Elemento R paalinimas

Elemento alinimo funkcijoje atsimenama ir grinama rodykl duomenis, kuriuos buvo nuoroda alinamame elemente. is veiksmas iai funkcijai yra perteklinis (nebtinas), nes atliekant alinamo elemento paiek yra nagrinjami duomenys, o tai reikia, kad juos jau turime.
R>de>ka = R>ka; R>ka>de = R>de;

141

alinimo funkcijos Mesti pavyzdyje nagrinjamos visos trys situacijos, bet nenagrinjama situacija, kai sraas tuias ir ar alinamo elemento rodykl netuia. To daryti nebtina, nes programos dalyje, kurioje nagrinjami paalinimo i srao kandidatai, btina patikrinti, ar toks elementas egzistuoja. Silome papildyti pavyzdio program ia funkcija ir patikrinti jos darb.
int *Mesti(sar *); // Metodo prototipas

T = A.GetP(); A.Mesti(T); // alinamas pirmas elementas T = A.GetG(); A.Mesti(T); // alinamas paskutinis elementas T = A.GetP(); A.Mesti(T->de); // alinamas antras elementas // alinti R element int *DviKryptys::Mesti(sar *R) { int *sk = R->S; if (R == P) { // Jeigu srao pradioje P = P->de; if (P != NULL) P->ka = NULL; } else if (R == G) { // Jeigu srao pabaigoje G = G->ka; if (G != NULL) G->de = NULL; } else { // Jeigu srao viduje R->de->ka = R->ka; R->ka->de = R->de; } delete(R); return sk; }

8.5. Tvarkymo veiksmai


Srao element tvarkymo veiksmams priskiriamos paiekos, atrankos ir rikiavimo operacijos. Paiekos veiksmams negalima sudaryti universali paprogrami, nes tai susieta su konkreiu udaviniu, duomenim struktra ir konkreiu paiekos raktu. Paiekoje galima skirti du bdus: Srae duomenys rakto atvilgiu yra nesutvarkyti. Paieka atliekama nuosekliai perirint visus srao elementus. Paieka nutraukiama, kai

142

surandamas reikalingas elementas. Tik vis sra perirjus galima suinoti, kad neradome reikalingo elemento. Srao duomenys rakto atvilgiu yra sutvarkyti. Paieka vykdoma nuosekliai perirint elementus. Paieka nutraukiama suradus tinkam element arba susidarius situacijai, kai tolesnis srao nagrinjimas yra beprasmis: jau tikrai toliau srae negali bti iekomas elementas. Pavyzdiui, telefon knygoje, iekant abonento pagal pavard, nebtina perskaityti viso srao iki galo.

Duomen atrankos veiksmai priskirtini naujo srao formavimui, nes yra sudaromas naujas nuorod jau turimus duomenis sraas. Pavyzdiui, turime student sra. Galima sudaryti nuorod sra tik pirmo kurso studentus. Rikiavimo pagal duot rakt funkcijos yra analogikos funkcijoms, skirtoms darbui su vienkrypiu srau. ia reikia nepamirti, kad sraas dvikryptis ir reikia koreguoti dvi rodykles elementui. io tipo srauose veiksm su rodyklmis padvigubja, taiau paiekai skirt rodykli sumaja. Jeigu rikiavime leidiama keisti vietomis duomenis, tuomet naudojamos tik vienos krypties rodykls (pradios arba pabaigos). Jeigu reikia tvarkyti nuorodas, tuomet veiksmai tampa komplikuoti. Problema isprendiama, kuomet srae saugomi ne duomenys, o nuorodos juos. Rikiavimo metu keiiame vietomis tas nuorodas. Duomenys savo padties nekeiia. Tai leidia formuoti atskirus nuorod, tvarkingus pagal vairius poymius, sraus. Pavyzdiui, turime telefon abonent sra. Galima sudaryti nuorod sra pagal pavardes, abcls tvarka. Galima sudaryti sra, kuriame bt nuorodos t pat abonent sra, tik telefon numeri didjimo seka. Dvikryptis sraas gali bti naudojamas su tam tikrais apribojimais. Tai dvigubo steko bei eils tipo sraai. Vartotinas dvigubo iedo sraas, nes jame terpimo bei alinimo veiksmai nesudtingi, be to paprastas srao skenavimas pirmyn-atgal. Dirbant su srainmis struktromis, visuomet btina tikrinti nagrinjamo elemento padt srae: kratinis ar viduje. To galima ivengti, jeigu srao kratinius elementus tursime fiktyvius, t.y. jie nebus susieti su duomenimis, atliks buferini element funkcij. Tuias sraas bus tuo atveju, kai bus tik tie elementai. Vienkrypiame srae paprastai toks elementas formuojamas pradioje, taiau eils atveju j naudinga turti ir gale. Dvikryptis sraas paprastai turi du kratinius tuius elementus, 143

nors pakanka ir vieno. Tie elementai gali bti pastovs arba formuojami laikinai, kol bus atlikti atitinkami veiksmai, po to jie alinami.

8.6. Panaudojimo pavyzdys


Tekstiniame faile Stud.dat turime student sra: pavard, vardas, mokymosi vidurkis. Reikia paalinti nepaangius studentus. Formuosime dvikrypt sra. Element alinimo veiksmuose sra papildysime pradioje ir gale tuiais elementais. Gausime situacij, kai visi duomen elementai yra srao viduje pradios ir galo atvilgiu. Element alinimas supaprastja.
// #include #include #include #include #include Panaudojimo pavyzdys <iostream.h> <stdio.h> <stdlib.h> <string.h> <conio.h>

typedef struct studentas { char pavard[10]; char vardas[10]; float vidur; }; typedef struct sar { studentas *st; sar *de; sar *ka; }; // Klass Studentai apibrimas class Studentai { sar *P; // sar *G; // public: // Studentai() { P = NULL; G = NULL; } void Formuoti(FILE *); // void Spausdinti(); // void Tvarkymas(float); // }; // Pagrindin programa void main() { FILE *D; Studentai A; // Klass clrscr();

Srao pradia Srao galas Konstruktorius Formuoja sra Spausdina sra Tvarkymas

Studentai objektas

144

} // Student srao formavimas void Studentai::Formuoti(FILE *F) { sar *R; if (!feof(F)) { R = new sar; R->st = new studentas; fscanf(F, "%s%s%f", R->st->pavard, R->st->vardas, &R->st->vidur ); R->de = NULL; R->ka = NULL; P = R; G = R; } while(!feof(F)) { R = new sar; R->st = new studentas; fscanf(F, "%s%s%f", R->st->pavard, R->st->vardas, &R->st->vidur); R->ka = G; G->de = R; R->de = NULL; G = R; } } // Srao spausdinimas void Studentai::Spausdinti(){ sar *D = P; while(D != NULL) { cout << D->st->pavard << " " << D->st->vardas << " " << D->st->vidur << "\n"; D = D->de; } } // alinimas i srao void Studentai::Tvarkymas(float vd) { sar *R, *D; R = new sar; // "Tuias" elementas srao pradioje

D = fopen("stud.dat", "r"); if (D == NULL) { cout << "Failo Stud.dat nepavyko atidaryti "; exit(1); } A.Formuoti(D); fclose(D); A.Spausdinti(); cout << "---------------------\n"; A.Tvarkymas(4.5); A.Spausdinti();

145

R->ka = NULL; R->de = P; R->st = NULL; P->ka = R; P = R; R = new sar; // "Tuias" elementas srao gale R->de = NULL; R->ka = G; R->st = NULL; G->de = R; G = R; R = P->de; while(R->de != NULL) { // alinimo ciklas if (R->st->vidur < vd) { R->de->ka = R->ka; R->ka->de = R->de; D = R; R = R->ka; delete(D->st); // alinimas rodykls student delete(D); } // alinimas srao elementas R = R->de; } R = P; // "Tuio" elemento alinimas i srao pradios P = R->de; P->ka = NULL; delete(R); // "Tuio" elemento alinimas i srao galo R = G; G = R->ka; if(G) G->de = NULL; else P = NULL; // Sraas tuias delete(R); }

146

9 skyrius. Tiesini sra rinkiniai


9.1. Sra struktra
Apdorojant duomenis, ne visuomet patogu turti vien duomen sra, ypa kai t duomen daug. Patogu turti kelet atskir tiesini sra. Pavyzdiui, turime universiteto kiekvieno fakulteto student sraus. Galima sudaryti tiek sra, kiek yra fakultet. Taiau prireikus papildyti duomenis naujo fakulteto srau, reikia modifikuoti program. Tai nepatogu. Galima suformuoti rodykli fakultetus masyv, paliekant rezerv naujiems sraams registruoti. Tokio srao schema parodyta 9.1 pav.
Masyvas IF AP HM NULL NULL NULL NULL Sraai NULL

9.1 pav. Daugiasrain struktra, organizuojama masyvu. Sra raktiniai odiai ir rodykls sraus saugomos masyve

Lankstesn struktra gaunama, kai vietoje masyvo yra formuojamas nuoseklus sraas, vienkryptis arba dvikryptis (9.2 pav.). Tokio srao elementas turi rodykl duomen tiesin sra ir srao pavadinimo lauk (arba rodykl t pavadinim). Gauname akot sra, kurio struktra universali duomen atvilgiu: nereikia modifikuoti program papildant nauju duomen srau. Tinka visi veiksmai, aptarti tiesiniams sraams. Priklausomai nuo pradini duomen funkcins tarpusavio priklausomybs ir planuojam apdorojimo veiksm yra projektuojama srain struktra. J tikslinga parinkti toki, kad veiksmai bt kuo paprastesni. Kurdami akot struktr mes i anksto numatome tam tikr duomen suskirstym, klasifikavim. Gerai suprojektuota struktra supaprastina veiksmus. 147

P NULL IF FM TT HM

NULL NULL NULL NULL

9.2 pav. Tiesini sra rinkinys

9.2. Srao panaudojimo pavyzdys


Tekstiniame duomen faile yra student sraas: pavard, vardas, fakultetas. Reikia suformuoti duomen sra pagal fakultetus. Panaudosime sra, kurio schema parodyta 9.2 pav. Duomen skaitymo metu iekosime akos su studento fakulteto pavadinimu. Jeigu nebus, sukursime nauj element pagrindiniame srae su naujo fakulteto pavadinimu ir atidarysime ak su to studento pavarde ir vardu. Jeigu rasime element su tuo fakultetu, tai akoje sukursime nauj element su naujo studento pavarde ir vardu. Baigus skaityti duomen fail tursime akot sra, kuriame studentai bus suskirstyti fakultetais. Srao papildymas naujais duomenimis yra tapatus formavimui. alinant studentus i srao gali susidaryti situacija, kai fakultete neliks nei vieno studento. Tuo atveju tikslinga paalinti i pagrindinio srao element su fakulteto pavadinimu. Galimas atvejis, kai nealiname fakulteto elemento, bet nuorodoje student sra paraome tuio adreso reikm NULL. Duomen failas: Studf.dat
Petraitis Jurgelis Batuotas Lapinas Medinis Ramusis Petras Jurgis Katinas Rudas Jurgis Petras IF HM EK IF IF HM 8.9 5.6 7.8 10 8 6.3

148

// #include #include #include #include #include

Srao panaudojimo pavyzdys <iostream.h> <stdio.h> <stdlib.h> <string.h> <conio.h>

typedef struct studentas { char pavard[10]; char vardas[10]; char fakult[10]; float vidur; }; typedef struct sar { studentas st; sar *kitas; }; typedef struct fakultetas { char fak[10]; fakultetas *sek; sar *stud; }; // Klass Uni apraymas class Uni { fakultetas *P; // Dinaminio srao pradia public: Uni() { P = NULL; }; // Konstruktorius void Formuoti(FILE *); // Formuoja sra void Spausdinti(sar *); // Spausdina sra void Visi_stud(); void Pasirink(); }; // Pagrindin programa void main() { FILE *D; Uni A; // Klass Uni objektas clrscr(); D = fopen("studf.dat", "r"); if (D == NULL) { cout << "Failo Studf.dat nepavyko atidaryti "; exit(1); } A.Formuoti(D); fclose(D); A.Visi_stud(); A.Pasirink();

149

// Srao formavimas void Uni::Formuoti(FILE *F) { fakultetas *R; sar *A; int yra; while(!feof(F)) { A = new sar; fscanf(F, "%s%s%s%f", A->st.pavard, A->st.vardas, A->st.fakult, &A->st.vidur); yra = 0; R = P; while(!yra && R) if (strcmp(A->st.fakult, R->fak) == 0) else R = R->sek; if (!yra) { R = new fakultetas; R->stud = NULL; strcpy(R->fak, A->st.fakult); R->sek = P; P = R; } A->kitas = R->stud; R->stud = A; }

yra = 1;

} // Spausdina vieno fakulteto student sra void Uni::Spausdinti(sar *R) { while(R) { cout << R->st.pavard << " " << R->st.vardas << " " << R->st.vidur << "\n"; R = R->kitas; } cout << "------------------------\n"; } // Spausdina vis fakultet student sraus void Uni::Visi_stud() { fakultetas *R = P; cout << "=== Fakultet ir student sraai ===\n\n"; while(R) { cout << "Fakultetas " << R->fak << ":\n"; Spausdinti(R->stud);

150

} // Pageidaujamo fakulteto student srao spausdinimas void Uni::Pasirink() { fakultetas *R; char fk[10], s; int yra, rinkti = 1; while(rinkti) { cout << "Fakultetas= "; cin >> fk; yra = 0; R = P; while(!yra && R) if (strcmp(fk, R->fak) == 0) else R = R->sek;

R = R->sek;

yra = 1;

if (yra) { cout << R->fak << ":\n"; Spausdinti( R->stud ); } else cout << fk << " srae nerastas\n"; cout << "------------------------\n"; cout << "Ar dar renkate fakultet(T)?"; cin >> s; if ((s != 'T') && (s != 't')) rinkti = 0;

} }

151

10 skyrius. Netiesiniai sraai


10.1. Srao struktra
Sraas, kurio elementus ryio tvarka negalima idstyti vien grandin, vadinamas netiesiniu. Tai grafus vaizduojantys sraai. ia virns atitinka srao element reikmes, o virnes jungiantys lankai atitinka rodyklmis apraomus ryius tarp j. Nuo grafo virni sujungim bd priklauso jo savybs, grafo virni perrinkimo bdai. Veiksm su sraais sudtingumas priklauso nuo graf struktros ir duomen apdorojimo algoritm. Patys paprasiausi ir daniausiai vartojami yra medio tipo netiesiniai sraai (10.1 pav.), kuri elementus galima idstyti kelis hierarchijos (pavaldumo) lygius taip, kad pradiniame, nuliniame, lygyje bt tik vienas elementas, o kiekvien emesnio hierarchijos lygio element vest tiktai viena nuoroda ir tik i auktesnio hierarchijos lygio elemento.
Pradia

D0

0-is lygis

D11

D12

D13

1-sis lygis

D21

D22

D23

D24

D25

2-sis lygis

emesnius hierarchinius lygius

10.1 pav. Medio tipo srao grafinis vaizdas

152

Apraant programose medio tipo struktras, yra paprastai ribojamas nuorod emesnius hierarchijos lygius (rodykli) skaiius. Jei jis apribojamas dviem, tai toks medis yra vadinamas binariniu. Binarini medi elementai yra apraomi taip pat, kaip ir dvikrypi sra elementai, ryio dalyje formuojant dvi nuorodas. Tiktai priimta ias nuorodas ymti kitokiais vardais, pabriant, kad medio akos yra nukreiptos dein arba kair pus (de, ka):
struct medis { void *data; medis *ka; medis *de; } // Duomen rodykl // Kairs medio akos rodykl // Deins medio akos rodykl

Binariniai mediai labai gerai tinka organizuoti tokioms saugojimo struktroms, i kuri danai tenka pagal poymius atrinkinti pavienius elementus arba nedideles j grupes. Apraant medio tipo struktras, taip pat reikia apibrti j formavimo, tvarkymo bei apdorojimo procedras.

10.2. Formavimas
Formavimo veiksmai priklauso nuo srao struktros ir duomen tarpusavio priklausomybs. Universali paprogrami negalima sudaryti.
Duomen rinkinys: 5 8 3 1 4 6 3 7 5

8
NULL

1
NULL NULL

4
NULL NULL

3
NULL NULL NULL

7
NULL

10.2 pav. Binarinis medis

153

Medio formavim iliustruosime tokiu pavyzdiu. Tarkime, kad reikia sudaryti med, kuriame bt saugomi elementai, turintys sveik skaii reikmes. Skaiiai gaunami i failo, kuriame jie surayti atsitiktine tvarka. Medyje juos reikia patalpinti didjimo tvarka (10.2 pav.). Formuosime binarin med. Tai bus padaryta taip. Pirmas medio elementas turs pirmojo skaiiaus reikm. Kitiems skaiiams bus sukuriami elementai, kuri vieta medyje bus randama tokiu dsniu: jeigu nauja reikm yra maesn u nagrinjamo medio elemento saugom reikm, tai pereiname prie kairiojo elemento, kitaip prie deiniojo. Naujas elementas pakabinamas medyje toje vietoje, kur randamas akos galas, t.y. elementas su rodykls reikme NULL. Naujas elementas su nauja reikme turi turti ka ir de reikmes NULL.
// #include #include #include #include Medio sudarymo pavyzdys <iostream.h> <stdio.h> <stdlib.h> <conio.h>

typedef struct medis { int sk; medis *de; medis *ka; }; // Klass Binmedis apraymas class Binmedis { medis *P; // Medio virn public: Binmedis() { P = NULL; }; // Konstruktorius void Formuoti(FILE *); // Formuoja med medis *Get() { return P; }; void Padeti(medis *); // Naujo elemento vieta medyje void Spausdinti(); // Spausdina reikmes didjimo tvarka // Spausdina reikmes majimo tvarka void SpausdintiRek(medis *); medis *Rasti(int); // Duotos reikms paieka medyje }; // Pagrindin programa void main() { FILE *D; medis *R; Binmedis A; // Objekto apraymas clrscr(); D = fopen("duom.dat", "r");

154

if (D == NULL) { cout << "Failo Duom.dat nepavyko atidaryti "; exit(1); } A.Formuoti(D); fclose(D); A.Spausdinti(); // Didjimo tvarka cout << "\n" << "======================\n"; R = A.Get(); A.SpausdintiRek(R); // Majimo tvarka cout << "\n" << "======================\n"; for(int i=0; i<=10; i++) { // Paiekos iliustracija R = A.Rasti(i); if (R) cout << i << " Radau!\n"; else cout << i << "* neradau\n"; }

} // Medio formavimas void Binmedis::Formuoti(FILE *F) { medis *R; while(!feof(F)) { // Naujas elementas R = new medis; R->ka = NULL; R->de = NULL; fscanf(F, "%i", &R->sk); if (!P) P = R; // Elementas dedamas med else Padeti(R); } } // Padti element medyje void Binmedis::Padeti(medis *R) { medis *D = P, *T; while(D) { T = D; // Tuios akos paieka if (R->sk < D->sk) D = D->ka; else D = D->de; } if (R->sk < T->sk) T->ka = R; // Elemento prijungimas else T->de = R; } // Spausdinimas didjimo tvarka void Binmedis::Spausdinti() { medis *R = P; struct stekas {medis *S; // Stekas medio trasavimui stekas *sek; } *A = NULL, *D;

155

} // Spausdinimas majimo tvarka (su rekursija) void Binmedis::SpausdintiRek(medis *R) { if (R) { SpausdintiRek(R->de); cout << R->sk << " "; SpausdintiRek(R->ka); } } // Elemento, turinio nurodyt reikm paieka medis *Binmedis::Rasti(int Sk) { medis *R = P; while(R && (R->sk != Sk)) if (Sk < R->sk) R = R->ka; else R = R->de; return R; // Neradus grinama reikm NULL }

while(R || A) { if (R) { D = new stekas; D->sek = A; A = D; A->S = R; R = R->ka; } else { R = A->S; D = A; A = A->sek; delete(D); cout << R->sk << " R = R->de; } }

// Virns adreso uraymas stek

// Perjimas kair // Kratinio elemento adresas imamas i steko

";

// Spausdinama reikm // Perjimas dein

10.3. Perira
Perrenkant medyje esanias reikmes yra vadovaujamasi mediui sukurti naudotais principais. Pavyzdio med galima perirti skaii didjimo arba majimo tvarka. Perira pradedama nuo medio virns ir iekome toliausiai kairje esanios akos virns, kurios reikm bus maiausia. J spausdiname ir pasukame artimiausi dein ak, nuo kurios vl iekome toliausiai kair pus esanios virns. T.y. kartojame medio formavimo proces. Kadangi mediu galime judti tik viena kryptimi (nra nuorod auktesn lyg), tai btina atsiminti virnes, per 156

kurias buvo nusileidiama iki atitinkamos virns. Tam naudojamas stekas, kur galima organizuoti masyve, tiesiniu srau arba ireikti netiesiogiai panaudojant rekursin paiekos bd. Pavyzdio programoje yra funkcija Spausdinti, kuri skirta spausdinti medio reikmes didjimo tvarka ir kuri stekui naudoja tiesin sra. Funkcija SpausdintiRek skirta spausdinti medio saugomas reikmes majimo tvarka ir yra rekursin. Iekant medyje duotos reikms yra vadovaujamasi vienu i medio periros bd: kairiniu arba deininiu. Pavyzdio programoje funkcija Rasti demonstruoja paiek kairiniu bdu. i funkcij galima patobulinti: duomenys yra tvarkingai sudti, todl paiek galima nutraukti, kuomet tolesn perira tampa beprasm (iekoma reikm tampa maesne u aktyvaus elemento saugom reikm). Binarini medi skleidimu yra vadinamas vis j element perrinkimas. Nuo perrinkimo bdo priklauso, kokia tvarka medyje saugomi duomenys yra perduodami juos apdorojanioms funkcijoms. Naudojami trys pagrindiniai skleidimo bdai: kairysis, deinysis ir centrinis. Naudojant kairj skleidimo bd, kiekviename elemente i pradi yra perrenkama kairiosios rodykls rodoma medio aka. Po to apdorojami elemento saugomi duomenys ir perrenkama deinioji aka. Skleidimas yra pradedamas nuo medio kamieno. Deinysis skleidimas vykdomas prieinga kairiajam skleidimui tvarka, o centrinio skleidimo atveju, i pradi apdorojamas duomen elementas ir tik po to perrenkamos kairioji ir deinioji akos. Visi aptarti skleidimo bdai yra labai glaustai apraomi rekursinmis funkcijomis. Pavyzdiu gali bti pavyzdyje pateiktos medyje saugom reikmi spausdinimas.

157

11 skyrius. Savarankikas darbas


11.1. Programos pavyzdys
Darbo su srainmis struktromis gdiai susidaro savarankikai raant programas. Silome pabandyti visas nagrintas dinamines struktras sudtingumo seka. Tai galite padaryti su tuo paiu vienu udaviniu, modifikuojant padarytas programas. Js galsite palyginti sra taikymo galimybes, j efektyvum. Imdami kiekvienai struktrai skirtingas uduotis, tursite galimyb ibandyti ne tik sraines struktras, bet ir pagilinti inias program struktros krime. Sraini struktr studijas silome baigti atskiro udavinio programos padarymu. ia reikt suprojektuoti toki savo dinamin duomen struktr, kuri bt racionaliausia pasirinktam udaviniui. Pavyzdio uduotis. Kelioni agentra turi silom turistini kelioni sra. inomas kelions tipas, trukm, vieta ir kaina. Keliautojas renkasi kelion pagal du kriterijus: trukm ir kain. Reikia sudaryti sra kelioni, nevirijani bsimo keliautojo galimybi. Duomen srao pavyzdys. Duomenys saugomi tekstiniame faile Kelione.sar (11.1 pav.). Vienoje eilutje yra vienos kelions duomenys, surayti tokia tvarka: pirmose 10 pozicij kelions tipas, toliau trukm dienomis, 10 pozicij skiriama vietovs pavadinimui ir eiluts gale kaina litais. Duomen faile tui eilui negalima palikti.
Dviratis Eiti Traukinys Laivas Joti Valtis 15 10 15 25 5 12 Lietuva Dzukija Turkija Afrika Utena Neris 200 100 1200 2500 230 345

11.1 pav. Kelioni srao pavyzdys

158

Rezultat pavyzdys. Rezultatai lenteli formoje kaupiami tekstiniame faile vardu Kelione.rez (11.2 pav.). Pavyzdyje yra duomen ir pasirinkimui tinkam kelioni lentels. Pasirinkimo sraas yra surikiuojamas pagal trukm ir kain.
Siulomu kelioniu sarasas +----+------------+--------+------------+---------+ | Nr.| Keliones t.+ Trukme + Vieta + Kaina + +----+------------+--------+------------+---------+ | 1 | Valtis | 12 | Neris | 345 | | 2 | Joti | 5 | Utena | 230 | | 3 | Laivas | 25 | Afrika | 2500 | | 4 | Traukinys | 15 | Turkija | 1200 | | 5 | Eiti | 10 | Dzukija | 100 | | 6 | Dviratis | 15 | Lietuva | 200 | +----+------------+--------+------------+---------+ Atrinktu kelioniu sarasas +----+------------+--------+------------+---------+ | Nr.| Keliones t.+ Trukme + Vieta + Kaina + +----+------------+--------+------------+---------+ | 1 | Joti | 5 | Utena | 230 | | 2 | Eiti | 10 | Dzukija | 100 | | 3 | Valtis | 12 | Neris | 345 | | 4 | Dviratis | 15 | Lietuva | 200 | | 5 | Traukinys | 15 | Turkija | 1200 | +----+------------+--------+------------+---------+ 11.2 pav. Rezultat failo pavyzdys

Programos duomen struktra. Kelions duomenims aprayti skirta struktra:


struct kelione { char char int int tipas[10]; vieta[10]; trukme; kaina; };

Duomenys bus saugomi tiesiniu vienkrypiu srau:


typedef struct sar { kelione S; sar *sek; };

Programoje sukurta klas Kelions. Duomen srao rodykl P, atrinkt kelioni srao rodykl K. 159

Klass metod apraymas

Pagrindin funkcija. P duomen srao rodykl. K rezultat srao rodykl. F failinis kintamasis. ia atidaromi ir udaromi failai, formuojamas duomen sraas P ir rezultat sraas K, rikuojamas sraas K, spausdinami sra duomenys lentelmis. Veiksmams atlikti naudojami padaryti metodai. void Keliones::Formuoti(FILE *F); Funkcijai perduodamas atidarytas duomen failas F. ia skaitomi duomenys po vien eilut ir formuojamas duomen sraas. Srao pradia P. Sraas formuojamas steko principu. Panaudojama funkcija Padeti void Keliones::Padeti(sar **P, kelione N); Sukuria nauj element su duotos kelions N duomenimis ir prijungia prie srao P pradios. void Keliones::Spausdinti(sar *P, FILE *F); Srao P saugomus duomenis lentels forma surao tekstin fail F. void Keliones::Rikiuoti(sar *P); Srao P duomenis surikiuoja pagal nurodyt rakt, aprayt funkcijoje Raktas. Sraas rikiuojamas daliniu Minmax bdu. Rikiavimo metu duomenys keiiami vietomis. int Keliones::Raktas(kelione A, kelione B); Palyginami dviej kelioni A ir B duomenys. Jeigu B kelions trukm maesn u A arba, kai trukms vienodos, B kelions kaina yra didesn u A kelions kain, tai grinama reikm 1 (reikia sukeisti vietomis A su B), kitaip grinama reikm 0. void Keliones::Rinkti(); ia keliautojo paklausiama didiausia galima kelions kaina ir ilgiausia galima trukm. I srao P atrenkami tinkami duomenys ir suformuojamas naujas sraas K. Sraas formuojamas steko principu. Naudojama funkcija Padeti. void Keliones::Naikinti(sar *P); Funkcija paalina sra P i atminties.

160

sar *Keliones::GetP() { return P; }; Grina vis duomen srao pradios rodykl P. sar *Keliones::GetK() { return K; }; Grina atrinkt duomen srao pradios rodykl K.
Programos tekstas

#include #include #include #include #include

<iostream.h> <stdio.h> <stdlib.h> <conio.h> <string.h>

struct kelione { char tipas[10]; char vieta[10]; int trukme; int kaina; }; typedef struct sar { kelione S; sar *sek; }; // Klass Keliones apraas class Keliones { sar *P; // Vis kelioni srao pradia sar *K; // Atrinkt kelioni sraas public: Keliones() { P= NULL; K= NULL; };// Konstruktorius void Formuoti(FILE *); // Formuoja sra void Padeti(sar **, kelione); sar *GetP() { return P; }; sar *GetK() { return K; }; void Spausdinti(sar *, FILE *); // Spausdina sra void Rikiuoti(sar *); // Rikiuoja int Raktas(kelione, kelione); // Rikiavimo raktas void Rinkti(); // Atrenkami duomenys void Naikinti(sar *); // Srao alinimas }; // Pagrindin programa void main() { FILE *F; Keliones A; // Klass Keliones objektas sar *T; // Pagalbinis kintamasis clrscr(); cout << "Programa darba pradejo\n\n";

161

F = fopen("Kelione.sar", "r"); if (F == NULL) { cout << "Failo 'Kelione.dat' nepavyko atidaryti "; exit(1); } A.Formuoti(F); fclose(F); F = fopen("Kelione.rez", "w"); if (F == NULL) { cout << "Failo 'Kelione.rez' nepavyko sukurti"; exit(1); } fprintf(F, "Siulomu kelioniu sarasas\n\n"); T = A.GetP(); A.Spausdinti(T, F); A.Rinkti(); T = A.GetK(); A.Rikiuoti(T); fprintf(F, "Atrinktu kelioniu sarasas\n\n"); T = A.GetK(); A.Spausdinti(T, F); fclose(F); T = A.GetP(); A.Naikinti(T); T = A.GetK(); A.Naikinti(T); cout << "Pabaiga. Rezultatai faile 'Kelione.rez'";

} // Elemento raymas void Keliones::Padeti(sar **P, kelione N) { sar *D = new sar; D->S = N; D->sek = *P; *P = D; } // Srao formavimas void Keliones::Formuoti(FILE *F) { kelione S; do { fscanf(F, "%s%i%10s%i", S.tipas, &S.trukme, S.vieta, &S.kaina); Padeti(&P, S); }

162

while(!feof(F)); } // Srao spausdinimas void Keliones::Spausdinti(sar *P, FILE *F) { sar *D = P; int i = 1; fprintf( F,"+----+------------+--------+------------"); fprintf( F,"+---------+\n" ); fprintf( F,"| Nr.| Keliones t.+ Trukme + Vieta "); fprintf( F,"+ Kaina +\n" ); fprintf( F,"+----+------------+--------+------------"); fprintf( F,"+---------+\n" ); while(D) { fprintf( F,"| %2d | %10s | %6d | %10s | %6d |\n", i++, D->S.tipas, D->S.trukme, D->S.vieta, D->S.kaina); D = D->sek; } fprintf( F,"+----+------------+--------+------------"); fprintf( F,"+---------+\n" ); fprintf( F, "\n\n\n"); } // Rikiavimo raktas int Keliones::Raktas(kelione A, kelione B) { return(B.trukme < A.trukme) || ((B.trukme == A.trukme ) && (B.kaina > B.kaina)); } // Rikiavimas void Keliones::Rikiuoti(sar *P) { sar *R = P, *D; kelione K; while(R) { D = R->sek; while(D) { if (Raktas(R->S, D->S)) { K = R->S; R->S = D->S; D->S = K; } D = D->sek; } R = R->sek; } } // Duomen atrinkimas void Keliones::Rinkti() { sar *D = P; int Sk1, Sk2; cout << "Kokia maksimali kaina ? "; cin >> Sk1; cout << "\n"; cout << "Kokia maksimali trukme? ";

163

} // Srao paalinimas void Keliones::Naikinti(sar *P) { sar *R = P, *D; while(R) { D = R; R = R->sek; delete(D); } }

cin >> Sk2; cout << "\n"; while(D) { if ((D->S.trukme <= Sk2) && (D->S.kaina <= Sk1)) Padeti(&K, D->S); D = D->sek; }

11.2. Uduotys
U1. Turime tekstiniame faile meteorologini stebjim rezultatus: data, krituli pobdis, krituli kiekis. Suformuoti sra: krituli pobdis, bendras kiekis, vidurkis. Sutvarkyti duomenis pagal krituli pobd ir krituli kiek. Ivesti tris lenteles: duomen, sutvarkyt duomen ir skaiiavim rezultat. U2. Turime tekstiniame faile darbuotoj iniarat: pavard, adresas, darbo pavadinimas, data, dirbta valand. Kitame tekstiniame faile turime darb vertinimo normatyvus: darbo pavadinimas, valandos kainis. Suformuoti atlyginim sra ir j sutvarkyti pagal atlyginimo dyd ir pavard: pavard, adresas, dirbtas valand kiekis, atlyginimas. Ivesti tris lenteles: dvi duomen ir skaiiavim rezultat. U3. Turime tekstiniame faile bibliotekos lankytoj sra: pavard, vardas, skaitytojo bilieto numeris, knyg pamimo data, paimt knyg kiekis, leistinas skaityti dien skaiius. Suformuoti skaitytoj, kurie vluoja grinti knygas, sra, ir j sutvarkyti pagal vlavim ir pavard: pavard, vardas, skaitytojo bilieto numeris, vluojamas dien skaiius, knyg kiekis. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. 164

U4. Turime tekstiniame faile student sra: pavard, vardas, grups ifras, egzamin pavadinimai ir paymiai. Suformuoti pirmn, kuri paymi vidurkis yra duotame intervale [a, b], sra ir j sutvarkyti pagal grupes ir pavardes: pavard, vardas, grups ifras, paymi vidurkis. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U5. Turime tekstiniame faile student sra: pavard, vardas, grups ifras, vis egzamin paymiai. Suformuoti sra: pavard, vardas, grups ifras, paymi vidurkis. J sutvarkyti pagal grups ifr ir paymi vidurk. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U6. Turime tekstiniame faile student sra: pavard, vardas, grups ifras, vis egzamin paymiai. Suformuoti sra: pavard, vardas, grups ifras, kiek koki paymi turi. J sutvarkyti pagal grups ifr ir paymi vidurk. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U7. Turime tekstiniame faile student sra: pavard, vardas, grups ifras, vis egzamin paymiai. Suformuoti sra: pavard, vardas, grups ifras, mokymosi vidurkis. J sutvarkyti pagal grups ifr ir mokymosi vidurk. Ivesti lenteles: duomen ir skaiiavim rezultat, pirmn (mokosi vidurkiu >8) ir atsiliekani (mokosi vidurkiu <6). U8. Turime tekstiniame faile student sra: pavard, vardas, grups ifras, vis egzamin paymiai. Suformuoti sra: pavard, vardas, grups ifras, atuntuk,devintuk ir deimtuk kiekiai. J sutvarkyti pagal atuntuk, devintuk, deimtuk kiek. Ivesti lenteles: duomen ir skaiiavim rezultat. U9. Turime tekstiniame faile student darbo prie kompiuteri apskaitos sra: pavard, vardas, grups ifras, kompiuterio registracijos numeris, data, darbo pradios laikas, darbo pabaigos laikas.

165

Suformuoti sra: pavard, vardas, grups ifras, kompiuterio registracijos numeris, data, darbo laikas minutmis. J sutvarkyti pagal dirbt laik ir pavard. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U10. Turime tekstiniame faile student apskaitos sra: pavard, vardas, stojimo Universitet data, vis egzamin paymiai. Suformuoti sra: pavard, vardas, kursas, atuntuk, devintuk, deimtuk kiekiai. J sutvarkyti pagal deimtukus, devintukus, atuntukus. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U11. Turime tekstiniame faile student sra: pavard, vardas, grups ifras, gimimo data, vis egzamin paymiai. Suformuoti sra: pavard, vardas, amius, kiek koki paymi turi. J sutvarkyti pagal ami ir mokymosi vidurk. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U12. Turime tekstiniame faile viebuio gyventoj sra: pavard, vardas, atvykimo data, ivykimo data, kaina u par. Suformuoti sra: pavard, vardas, atvykimo data, ivykimo data, mokestis. Duomenis ir rezultatus sutvarkyti pagal atvykimo dat. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U13. Turime tekstiniame faile viebuio gyventoj sra: pavard, vardas, atvykimo data, ivykimo data, paros kaina. Suformuoti sra: pavard, vardas, atvykimo data, gyventa par, mokestis J sutvarkyti pagal gyvenimo trukm ir mokest. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U14. Turime tekstiniame faile viebuio gyventoj sra: pavard, vardas, atvykimo data, gyventa par, paros kaina. Suformuoti sra: pavard, vardas, atvykimo data, ivykimo data, mokestis. J sutvarkyti pagal pavardes ir vardus. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U15. Turime tekstiniame faile viebuio gyventoj sra: pavard, vardas, atvykimo data, gyventa par, kambario tipas. 166

Kitame tekstiniame faile turime kainorat: kambario tipas, paros kaina. Suformuoti sra: pavard, vardas, atvykimo data, ivykimo data, mokestis. J sutvarkyti pagal mokest. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U16. Turime knyg sra: autorius, pavadinimas, ileidimo metai, tiraas, kaina. Suformuoti sra: autorius, pavadinimas, ileidimo metai, tirao pinigin vert. Sra sutvarkyti pagal ileidimo dat. Ivesti lenteles: duomen ir skaiiavim rezultat. U17. Turime tekstiniame faile viebuio gyventoj sra: pavard, vardas, atvykimo data, gyventa par, kambario tipas. Kitame tekstiniame faile turime kainorat: kambario tipas, kaina, gyvenimo kaina, buitini paslaug kaina, pelno procentas. Suformuoti sra: pavard, vardas, atvykimo data, gyventa par, mokestis. J sutvarkyti pagal atvykimo dat. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U18. Turime sra: detal, pagaminimo data, kiekis. Kitame tekstiniame faile turime kainorat: detal, gamybos ilaid kaina, pelno procentas. Suformuoti sra: detal, pardavimo kaina, kiekis. J sutvarkyti pagal kain ir kiek. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U19. Turime sra: detal, pagaminimo data, kiekis. Kitame tekstiniame faile turime kainorat: detal, mediag kaina vienete, darbo snaudos vienetui, kitos papildomos ilaidos vienos detals gamybai. Suformuoti sra: detal, kiekis, pardavimo kaina, priskaiiuotas atlyginimas. J sutvarkyti pagal kiek ir atlyginim. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. 167

U20. Turime sra: detal, parduotas kiekis, pardavimo data. Kitame tekstiniame faile turime kainorat: detal, kaina. Suformuoti sra: detal, pardavimo data, pardavimo kaina, suma. J sutvarkyti pagal dat ir kain. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U21. Turime sra: prek, gautas kiekis, parduotas kiekis, pardavimo data. Kitame tekstiniame faile turime kainorat: prek, kaina. Suformuoti sra: prek, likutis, pardavimo kaina, pajamos. J sutvarkyti pagal kain ir pajamas. Ivesti dvi lenteles: duomen ir skaiiavim rezultat. U22. Turime sra: prek, pagaminimo data, vartojimo laikas. Suformuoti sra: prek, pagaminimo data, vartojimo laikas, vartojimo pabaigos data. J sutvarkyti pagal pagaminimo dat ir pavadinim. Ivesti dvi lenteles: duomen ir skaiiavim rezultat.

168

169

También podría gustarte