Kovcs Gyrgy
Debreceni Egyetem
Tartalomjegyzk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Elosz . . . . . . . . . . . . . . . . . . . .
A gyakorlat kvetelmnyei . . . . . . .
Irodalom . . . . . . . . . . . . . . . . . .
A C programozsi nyelv . . . . . . . . .
A tmb . . . . . . . . . . . . . . . . . . .
5.1 Teljes keress . . . . . . . . . . . . .
5.2 Lineris keress . . . . . . . . . . .
5.3 Binris keress . . . . . . . . . . . .
5.4 Szlsortk kivlasztsos rendezs
5.5 Bubork rendezs . . . . . . . . . .
5.6 Gyorsrendezs . . . . . . . . . . . .
Halmazok . . . . . . . . . . . . . . . . .
Multihalmazok . . . . . . . . . . . . . .
Kt- s tbbdimenzis tmb . . . . . . .
Ritkamtrix . . . . . . . . . . . . . . . .
9.1 Hrom soros reprezentci . . . . .
9.2 Ngy soros reprezentci . . . . .
Sor . . . . . . . . . . . . . . . . . . . . . .
10.1 Rgztett sor . . . . . . . . . . . . .
10.2 Vndorl sor . . . . . . . . . . . . .
10.3 Ciklikus sor . . . . . . . . . . . . .
10.4 Plda . . . . . . . . . . . . . . . . .
Verem . . . . . . . . . . . . . . . . . . . .
11.1 Plda . . . . . . . . . . . . . . . . .
Rekord . . . . . . . . . . . . . . . . . . .
12.1 Keress . . . . . . . . . . . . . . . .
12.2 Rendezs . . . . . . . . . . . . . . .
12.3 Ritka mtrix . . . . . . . . . . . . .
12.4 Sor . . . . . . . . . . . . . . . . . .
Dinamikus memriakezels . . . . . . .
Egy irnyba lncolt lista . . . . . . . . .
14.1 Fggvnyekkel . . . . . . . . . . .
14.2 Eljrsokkal . . . . . . . . . . . . .
14.3 Rekurzi . . . . . . . . . . . . . . .
14.4 typedef . . . . . . . . . . . . . . . .
Ktirnyba lncolt lista . . . . . . . . . .
15.1 Fggvnyek . . . . . . . . . . . . .
15.2 Eljrsok . . . . . . . . . . . . . . .
ltalnos binris fa . . . . . . . . . . . .
1A
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
2
2
2
2
3
6
8
10
13
15
18
24
28
32
32
34
38
38
40
42
43
47
48
50
52
56
59
60
64
67
68
72
73
74
75
75
79
79
gykovacs
szerzo email elrhetosgei: e-mail: gyuriofkovacs@gmail.com, url: http://www.inf.unideb.hu/
1
Kovcs Gyrgy
17 Binris keresofa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Irodalomjegyzk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
1. Elosz
A gyakorlataimon leadott anyagok kzirata, NEM LEKTORLT, HIBKAT TARTALMAZ, HASZNLATT SENKINEK SEM JAVASLOM!
2. A gyakorlat kvetelmnyei
A gyakorlat teljestshez a flv sorn ketto zh legalbb 61%-os teljestse szksges. A flv vgn
a kt zh egyike javthat.
3. Irodalom
Az flv sorn trgyalt algoritmusok zmnek pszeudokdja megtallhat a Muszaki
Knyvkiadnl
megjelent Algoritmusok [1] cmu knyvben.
4. A C programozsi nyelv
A C programozsi nyelv elsajttsa nem rsze az adatszerkezetek s algoritmusok trgy tematikjnak. A C nyelv irodalma szles. A Magasszinu programozsi nyelvek 1 linken tallhat gyakorlati
jegyzetben szmos utals s technikai rszlet tallhat a klnbzo adatszerkezetek C-ben trtno
megvalstsra vonatkozan. A flv elso felben statikus memriakezelssel brzolhat adatszerkezetekkel foglalkozunk, gy a C nyelv alapelemein tl a ktirny elgaztat utasts, az elort lpsszm
ciklus, a fggvnyek s tmbk hasznlatnak ismerete elegendo az adatszerkezetek s algoritmusok
anyag elsajttshoz.
5. A tmb
A tmb defincija: homogn, statikus adatszerkezet.
A homogenits arra utal, hogy azonos tpus adatelemekbol pl fel,
a statikussg pedig azt jelenti, hogy minden tmb mrete rgztett, nem vltoztathat.
A tmb elemeinek elrse kzvetlen, minden elem hivatkozhat az indexvel. A C programozsi
nyelvben N mretu,
tipus tpus, azonosito nevu tmbt az albbi deklarcis utastssal hozhatunk
ltre.
tipus azonosito[N];
Lssunk egy egyszeru pldt: az albbi kdban ltrehozunk egy egszeket (int) tartalmaz 5 elemu
tmbt (4,6,8,10,12) kezdortkkel, s kirom a konzolra a tmbben trolt rtkeket:
#include <stdio.h>
int main(int argc, char** argv)
{
int t[5]= {4, 6, 8, 10, 12};
int i;
for ( i= 0; i < 5; ++i )
printf("%d ", t[i]);
return 0;
}
F ONTOS
A fenti fggvnyben a t paramter a tmb, amelyben keresnk, n a tmb mrete, ugyanis egy tmb
mrett mindig t kell adnunk paramterknt s k a keresett egsz tpus rtk. A fenti fggvny
nagyon knnyen trhat float tpus tmbre:
int teljesKereses(float t[], int n, float k)
{
int i;
for ( i= 0; i < n; ++i )
Kovcs Gyrgy
if ( t[i] == k )
return i;
return -1;
}
Knnyen lthat, hogy csak a paramterknt kapott tmb s a keresett rtk tpust kell trnunk a
paramterlistn. A visszatrsi rtk tovbbra is int tpus, hiszen vagy egy indexet adunk vissza,
vagy a -1 rtket!
A teljes keress csak egy koncepci, a konkrt megvalsts problmtl fgg. A fentiekben egszeket,
majd lebegopontos rtkeket tartalmaz tmbkre implementltuk a teljes keress algoritmust. A
teljes keress egy specilis esete, amikor nem egy konkrt rtket keresnk, hanem a tmbben szereplo legkisebb vagy legnagyobb rtket vagy annak helyt. Ebben az esetben termszetesen nincs
szksg a keresett k rtkre, hiszen nem ismerjk.
int legkisebbErtek(int t[], int n)
{
int min= t[0];
int i;
for ( i= 1; i < n; ++i )
if ( min > t[i] )
min= t[i];
return min;
}
Knnyu ltni, hogy a klnbsg csupn az, hogy most a min vltozban a legkisebb elem indext
troljuk, az algoritmus koncepcija ugyanaz, kezdeti felttelezsnk, hogy a legkisebb elem a tmb
elso eleme (int min= 0). Mivel a min most egy rtket trol, rtelemszeruen
mdostanunk kell
azon utastsokat, amelyekben felhasznljuk a min rtkt.
5.1. Feladat: rjon fggvnyeket, amelyek visszaadjk a paramterknt kapott egsz tpus tmbben
tallhat legnagyobb rtket s annak helyt!
5.1. Megolds: A fentiek alapjn:
5.2. Feladat: rjon foprogramot az elozo fggvnyek felhasznlsval, amely a konzolrl egszekkel
feltlt egy 10 elemu tmbt, majd kirja a tmbben tallhat legkisebb s legnagyobb elemeket, azok
helyt. Ezt kvetoen beolvas egy egsz szmot a konzolrl s ha szerepel a tmbben, kirja annak
indext, ha nem szerepel, a tmbben, akkor -1-et!
5.2. Megolds: A teljessg kedvrt az albbiakban mg lerjuk az egsz foprogramot, amely fordthat
s futtathat, a ksobbiekben hasonl esetben csak magt a main fggvnyt fogjuk megrni:
5.1.1. forrskd: teljeskereses.c
#include <stdio.h>
int teljesKereses(int t[], int n, int k)
{
int i;
for ( i= 0; i < n; ++i )
if ( t[i] == k )
return i;
return -1;
}
int legkisebbErtek(int t[], int n)
{
int min= t[0];
int i;
for ( i= 1; i < n; ++i )
if ( min > t[i] )
min= t[i];
return min;
}
int legkisebbErtekHelye(int t[], int n)
{
int min= 0;
int i;
for ( i= 1; i < n; ++i )
if ( t[min] > t[i] )
min= i;
return min;
}
Kovcs Gyrgy
int legnagyobbErtek(int t[], int n)
{
int max= t[0];
int i;
for ( i= 1; i < n; ++i )
if ( max < t[i] )
max= t[i];
return max;
}
int legnagyobbErtekHelye(int t[], int n)
{
int max= 0;
int i;
for ( i= 1; i < n; ++i )
if ( t[max] < t[i] )
max= i;
return max;
}
int main(int argc, char** argv)
{
int t[10], i, k;
printf("adjon meg 10 egesz szamot:\n");
for ( i= 0; i < 10; ++i )
scanf("%d", &(t[i]));
printf("legkisebb ertek: %d\n", legkisebbErtek(t, 10));
printf("legkisebb ertek helye: %d\n", legkisebbErtekHelye(t, 10));
printf("legnagyobb ertek: %d\n", legnagyobbErtek(t, 10));
printf("legnagyobb ertek helye: %d\n", legnagyobbErtekHelye(t, 10));
printf("adjon meg egy keresendo erteket:\n");
scanf("%d", &k);
printf("%d\n", teljesKereses(t, 10, k));
return 0;
}
A fenti program kimenete a (3,2,5,4,7,0,9,-1,6,6) rtkek begpelse, valamint a keresendo 6 rtk esetn:
adjon meg 10 egesz szamot:
3 2 5 4 7 0 9 -1 6 6
legkisebb ertek: -1
legkisebb ertek helye: 7
legnagyobb ertek: 9
legnagyobb ertek helye: 6
adjon meg egy keresendo erteket:
6
8
A lineris keress funkcijt tekintve megegyezik a teljes keresssel, azaz a keresett elem indext adja
vissza ha az szerepel a tmbben, s -1-et, ha nem szerepel benne. A klnbsg az a felttelezs,
hogy a tmb rendezett, azaz egsz szmok esetn azokat nvekvo sorrendben tartalmazza. Ekkor
ugyanis ha pldul a 10 rtket keressk a nvekvo sorrendbe rendezett tmbben s az elejrol, azaz
a legkisebb rtktol indulva elrnk egy olyan elemig, amely nagyobb, mint 10, abbahagyhatjuk a
keresst, hiszen a rendezettsg miatt biztos, hogy a tmb htra lvo rszben mr csak 10-tol nagyobb
rtkek szerepelnek.
int linearisKereses(int t[], int n, int k)
{
int i;
for ( i= 0; i < n; ++i )
if ( t[i] >= k )
break;
if ( i == n )
return -1;
if ( t[i] == k )
return i;
return -1;
}
A fenti formjban a lineris keress az algoritmus sz szerinti megvalstsa. Elindulunk egy ciklussal s addig megynk, amg el nem ri a ciklusvltoz (i) a tmb vgt vagy a keresett rtktol
nagyobb vagy azzal egyenlo szmot tallunk a tmbben, ekkor ugyanis a break utastssal megszaktjuk a futst. Ezt kvetoen if utastsokkal dntjk el, hogy pontosan melyik szituci llt elo:
ha az i ciklusvltoz rtke n, akkor a tmb vgre rtnk anlkl, hogy teljeslt volna az if
felttele, gy biztos, hogy nincs a keresett rtk a tmbben, teht a visszatrsi rtk -1;
ha a vezrls ezen az elgaztat utastson tl lp, akkor azt ellenorizzk, hogy a keresett
rtken lltunk-e meg, azaz a for ciklus magjban tallhat >= felttelbol pontosan az egyenlosg teljeslt-e. Ha igen, visszaadjuk az i rtkt;
ha nem rtk el a tmb vgt s az egyenlosg sem teljeslt a ciklus magjban, akkor csak a >
relci teljeslhetett, azaz nagyobb rtket talltunk a keresettnl, de azt nem, gy a visszatrsi
rtk -1. Itt nincs szksg jabb if-re, hiszen ha a harmadik return utastshoz r a vezrls,
csak ez a szituci llhat fenn.
Fontos, hogy annak vizsglata, hogy az i vltoz elrte-e a tmb vgt megelozze annak vizsglatt,
hogy a tmb i. eleme megegyezik-e a keresett elemmel. Ha a kt felttel vizsglatot fordtott sorrendben rnnk, futsi hibhoz jutnnk abban az esetben, amikor az i elri a tmb vgt, ugyanis a ciklus lefutsa utn az i vltoz rtke n lenne, azonban egy n mretu tmbt csak a 0,...,n-1
rtkekkel lehet indexelni, gy a t[i] == k felttel vizsglatban i=n esetn tlindexels ll elo.
Lssuk, hogyan rhat a fenti algoritmus elegnsabb, de nem hatkonyabb formban:
int linearisKereses(int t[], int n, int k)
{
int i;
for ( i= 0; i < n && t[i] <= k; ++i )
if ( t[i] == k )
return i;
return -1;
}
Az utbbi kdban sszevontuk a ciklus kilpsi feltteleit. Vigyzni kell azonban, hogy az i < n
vizsglat a felttelben megelozze a t[i] <= k vizsglatot. Az indok az korbbihoz hasonlan a
tlindexels elkerlse. Kihasznlva hogy az && opertor rvidzr opertor, i=n esetn a bal oldaln
ll kifejezs hamis, gy a jobb oldaln ll kifejezs nem kerl kirtkelsre, vagyis a tlindexels
nem ll elo.
Az algoritmus utbbi formja elegnsabb ugyan, mert rvidebb, de nem hatkonyabb, ugyanis a
legtbb cikluslpsben hrom felttel ellenorzst vgzi, mg a korbbi implementci csak kt felttelt
ellenoriz cikluslpsenknt.
F ONTOS
Kovcs Gyrgy
5.3. Feladat: Mdostsa az egszek tmbjn lineris keresst vgzo fggvnyt gy, hogy kirja a
kimenetre, hnyadik lpsben (azaz hnyadik hasonlts utn) kpes dntst hozni!
5.3. Megolds: A lpsek szma a ciklusvltoz rtkbol knnyen kiszmthat, ugyanis a ciklusvltoz rtktol ppen egyel tbb hasonltst vgznk (a +1 hasonlts a 0-val kezdodo indexelsbol
addik).
int linearisKereses(int t[], int n, int k)
{
int i;
for ( i= 0; i < n; && t[i] <= k; ++i )
if ( t[i] == k )
{
printf("%d. lepesben megtalaltam\n", i + 1);
return i;
}
printf("%d lepes utan biztosan nincs benne\n", i + 1);
return -1;
}
Binris keress esetn szintn azzal a felttelezssel lnk, hogy a tmb rendezett. A binris keress
egy iteratv keress, amelyben mindig egy indextartomny kzpso elemt vizsgljuk. A kiindulsi
tartomny a tmb teljes indextartomnya. Ezt kvetoen ha a tmb kzpso eleme a keresett elem,
akkor visszaadjuk azt, ha nem az, akkor kihasznlva hogy rendezett a tmb:
ha a keresett elem nagyobb, mint a kzpso eleme a vizsglt tartomnyak, akkor a tartomny
als hatrt a kzpso elem utni elemre lltjuk, hiszen ekkor a keresett elem a tartomny felso
felben kell, hogy szerepeljen,
ha a keresett elem kisebb, mint a kzpso elem, akkor a vizsglt tartomny felso hatrt a
kzpso elem elotti elemre lltjuk, hiszen a keresett elem a tartomny als felben kell, hogy
szerepeljen.
A tartomny mdostsa utn jra vizsgljuk a kzpso elemet. Mindezt iteratvan addig folytatjuk,
amg meg nem talljuk a keresett elemet, vagy az als hatr tl nem halad a felso hatron, azaz a
keressi tartomny 0 elemure
nem szukl.
Knnyu ltni, hogy minden iteratv lpsben a vizsglt tartomny hossza felezodik, ami azt jelenti,
hogy n elemu tmb esetn log2 n lpsben 1 elemu tartomnyhoz, azaz egy elemhez jutunk, amelyrol
rgtn eldntheto, hogy a keresett elem-e vagy sem. A binris keress a leggyorsabb keress, ami
rendezett tmbkn vgrehajthat.
A binris keress C kdja:
int binarisKereses(int t[], int n, int k)
{
int alsoh= 0, felsoh= n - 1, kozep;
for ( kozep= (alsoh + felsoh) / 2; alsoh <= felsoh; kozep= (alsoh + felsoh) / 2 )
{
if ( t[kozep] == k )
return kozep;
if ( t[kozep] < k )
alsoh= kozep + 1;
else
felsoh= kozep - 1;
}
return -1;
}
5.4. Feladat: Mdostsa az egszek tmbjn binris keresst vgzo fggvnyt gy, hogy kirja a
kimenetre, hnyadik lpsben (azaz hnyadik hasonlts utn) kpes dntst hozni!
5.4. Megolds: Mivel itt nem a szokvnyosnak mondhat mdon hasznljuk a ciklusvltozt, be kell
vezetnnk egy j vltozt, amely a ciklus lpseit szmolja.
int binarisKereses(int t[], int n, int k)
{
int alsoh= 0, felsoh= n - 1, kozep, i= 0;
for ( kozep= (alsoh + felsoh) / 2; alsoh <= felsoh; kozep= (alsoh + felsoh) / 2 )
{
++i;
if ( t[kozep] == k )
{
printf("%d. lepesben megtalaltam\n", i );
return kozep;
}
if ( t[kozep] < k )
alsoh= kozep + 1;
else
felsoh= kozep - 1;
}
printf("%d lepes utan biztosan nincs benne\n", i );
return -1;
}
5.5. Feladat: Mdostsuk a fenti kereso fggvnyeket gy, hogy azoknak egy kezdet s veg nevu
paramterrel meg lehessen adni azt az indextartomnyt, amelyben keresnik kell! (A veg paramter
azt az utols indexet kapja rtkl, amelyet mg ellenorizni kell.)
5.5. Megolds:
int teljesKereses(int t[], int k, int kezdet, int veg)
{
int i;
for ( i= kezdet; i <= veg; ++i )
if ( t[i] == k )
return i;
return k;
}
int linearisKereses(int t[], int k, int kezdet, int veg)
{
int i;
for ( i= kezdet; i <= veg && t[i] <= k; ++i )
if ( t[i] == k )
return i;
return -1;
}
int binarisKereses(int t[], int k, int kezdet, int veg)
{
int alsoh= kezdet, felsoh= veg, kozep;
10
Kovcs Gyrgy
for ( kozep= (alsoh + felsoh) / 2; alsoh <= felsoh; kozep= (alsoh + felsoh) / 2 )
{
if ( t[kozep] == k )
return kozep;
if ( t[kozep] < k )
alsoh= kozep + 1;
else
felsoh= kozep - 1;
}
return -1;
}
5.6. Feladat: Adott a rendre (1, 2, 2, 5, 6, 8, 10, 12, 12) rtkeket tartalmaz tmb. llaptsa meg, hogy
a binris keress hnyadik lpsben tallja meg a
2 elemet,
5 elemet,
1 elemet,
hnyadik lpsben ll meg, ha a 0 elemet kell megkeresnie?
5.6. Megolds:
2: 2. lpsben,
5: 4. lpsben,
1: 3. lpsben,
0: 4. lpsben ll meg.
5.4. Szlsortk
kivlasztsos rendezs
Az lineris keress s binris keress algoritmusokban azzal a felttelezssel ltnk, hogy a tmb,
amelyben keresnk, rendezett. Most azt nzzk meg, hogy egy rendezetlen tmbt hogyan tudunk
gyorsan rendezni. Az egyik legegyszerubb
keress a szlsortk kivlasztsos rendezs. Ennek koncepcija a kvetkezo:
tegyk fel, hogy a tmb elemeit nvekvo sorrendbe szeretnnk rendezni.
Ekkor ha kivlasztjuk a tmb legkisebb elemt, majd megcserljk azt az elso elemmel, a tmb
elso eleme biztosan j helyen lesz, ugyanis nvekvo sorrendbe rendezett tmb esetn az elso
elem a legkisebb elem.
Ezt kvetoen tekintsk az eredeti tmbnek azon rsztmbjt, amelyik az eredeti tmb msodik
(vagyis 1 indexu)
elemvel kezdodik s a tmb vgig tart.
Ha erre megismteljk az elozo lpst, azaz megkeressk a legkisebb elemt (ami a teljes tmb
msodik legkisebb eleme) s megcserljk azt a rsztmb elso elemvel (ami a teljes tmbnek a
msodik eleme), akkor biztosak lehetnk benne, hogy a teljes tmb elso kt eleme mr j helyen
van, hiszen az elso elem az egsz tmb legkisebb eleme, a msodik eleme pedig az teljes tmb
msodik legkisebb eleme.
A fenti lpseket ismtelve a tmb vgig, a tmb rendezett vlik.
A minimum kivlasztsos nvekvo rendezs C kdja:
void minimumKivalasztasosNovekvoRendezes(int t[], int n)
{
int min, i, j, tmp;
for ( i= 0; i < n; ++i )
{
11
min= i;
for ( j = i; j < n; ++j )
if ( t[j] < t[min] )
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
A fggvny void visszatrsi tpusa azt jelenti, hogy nincs visszatrsi rtke, azaz lnyegben
eljrst runk. Ekkor nincs szksg a return utastsra sem, azaz nincs visszatrsi rtk. Ennek
azaz oka, hogy a rendezs minden esetben kivitelezheto, nincs informci, amelyet vissza szeretnnk
juttatni a hvsi krnyezetbe. Ngy vltozt hasznlunk, a min vltozt a legkisebb elem keressnl
hasznljuk fel, az i s j ciklusvltozk, mg a tmp vltozt kt vltoz rtknek cserjre hasznljuk.
A minimumkivlasztsos rendezs koncepcionlis lersnl olvashat, hogy a legkisebb rtket meg
kell cserlnnk a vizsglt tmb elso elemvel s ez a legegyszerubben
elem indexe
rendezetlen tmb:
1. lps utn
2. lps utn
3. lps utn
4. lps utn
0.
3
0
0
0
0
1.
5
5
3
3
3
2.
0
3
5
3
3
3.
6
6
6
6
5
4.
3
3
3
5
6
Lssuk, hogyan tehetjk absztraktabb az algoritmusunkat, a legkisebb rtk helynek keresst fggvnyknt kiemelve:
int legkisebbErtekHelyeKezdettel(int t[], int n, int kezdet)
{
int i, min= kezdet;
for ( i= kezdet + 1; i < n; ++i )
if ( t[i] < t[min] )
min= i;
12
Kovcs Gyrgy
return min;
}
void minimumKivalasztasosNovekvoRendezes2(int t[], int n)
{
int min, i, j, tmp;
for ( i= 0; i < n; ++i )
{
min= legkisebbErtekHelye(t, n, i);
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
5.8. Feladat: Mdostsa gy a minimum kivlasztsos nvekvoen rendezo algoritmust, hogy az minimum kivlasztssal cskkeno sorrendbe rendezze a paramterknt kapott tmbt!
5.8. Megolds:
void minimumKivalasztasosCsokkenoRendezes(int t[], int n)
{
int min, i, j, tmp;
for ( i= n-1; i > 0; ++i )
{
min= i;
for ( j = 0; j < i; ++j )
if ( t[j] < t[min] )
min= j;
13
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
5.9. Feladat: Mdostsa gy a minimum kivlasztsos nvekvoen rendezo algoritmust, hogy az maximum kivlasztssal nvekvo sorrendbe rendezze a paramterknt kapott tmbt!
5.9. Megolds:
void maximumKivalasztasosNovekvoRendezes(int t[], int n)
{
int max, i, j, tmp;
for ( i= n-1; i > 0; ++i )
{
max= i;
for ( j = 0; j < i; ++j )
if ( t[j] > t[max] )
max= j;
tmp= t[max];
t[max]= t[i];
t[i]= tmp;
}
}
mg n-3 alkalommal. Mivel minden ismtls egy jabb elemet tesz a helyre, n-1 ismtls utn az egsz tmb rendezett lesz.
A gyakorlatban a msodik pontban lert muveletsort
14
Kovcs Gyrgy
void novekvoBuborekRendezes(int t[], int n)
{
int i, j, tmp;
for ( i= 0; i < n; ++i )
for ( j = n - 1; j > i; --j )
if ( t[j] < t[j-1] )
{
tmp= t[j-1];
t[j-1]= t[j];
t[j]= tmp;
}
}
A klso ciklus ciklusvltozja (i) vezrli azt, hogy a pronknti csert a tmb vgtol indulva hnyadik
(i.) elemig kell vgrehajtani. A belso ciklus pedig a tmb vgtol indulva az i. elemig a szomszdos
elemek relatv sorrendjt a nvekvo rendezsnek megfelelo mdon lltja. Az albbiakban a klso
ciklus lpsei utn a tmb llapott mutatjuk be (flkvrrel szedtk az egyes lpsekben mr biztosan j helyen lvo elemeket):
elem indexe
rendezetlen tmb:
1. lps utn
2. lps utn
3. lps utn
4. lps utn
0.
3
0
0
0
0
1.
5
3
3
3
3
2.
0
5
3
3
3
3.
6
3
5
5
5
4.
3
6
6
6
6
A fenti pldban lthat, hogy a tmb mr a 2. lpsben teljesen rendezett vlt. Az algoritmus
hatkonyabb teheto, ha figyeljk, hogy vltozik-e a tmbnk, s ha nem, akkor abbahagyjuk a rendezo algoritmust, hiszen mr rendezett. Ehhez ltrehozunk egy segdvltozt (f), melynek rtkt
minden klso ciklus lps elejn 0-ra lltjuk, ha rtk csere trtnik, akkor pedig 1-re. Ha a belso ciklus lefutsa utn az f rtke mg mindig 0, azaz nem trtnt rtk csere, az azt jelenti, hogy a tmb
rendezett, fggetlenl attl, hogy hnyadik lpsben jrunk az i vltozval, azaz abbahagyhatjuk a
rendezst s befejezhetjk az eljrs futst a paramter nlkli return utastssal:
void novekvoBuborekRendezes2(int t[], int n)
{
int i, j, tmp, f;
for ( i= 0; i < n; ++i )
{
f= 0;
for ( j = n - 1; j > i; --j )
if ( t[j] < t[j-1] )
{
f= 1;
tmp= t[j-1];
t[j-1]= t[j];
t[j]= tmp;
}
if ( f == 0 )
return;
}
}
15
5.11. Feladat: Mdostsa a nvekvo bubork rendezst oly mdon, hogy a belso ciklus a tmb elejrol
induljon s a felttelben az i. elemet az i+1. elemhez hasonltsa!
5.11. Megolds:
void novekvoBuborekRendezes(int t[], int n)
{
int i, j, tmp;
for ( i= n-1; i >= 0; --i )
for ( j = 1; j <= i; ++j )
if ( t[j] < t[j-1] )
{
tmp= t[j-1];
t[j-1]= t[j];
t[j]= tmp;
}
}
5.12. Feladat: rja meg a cskkeno bubork rendezst oly mdon, hogy a belso ciklus a tmb elejrol
induljon s a felttelben az i. elemet az i+1. elemhez hasonltsa!
5.12. Megolds:
void csokkenoBuborekRendezes(int t[], int n)
{
int i, j, tmp;
for ( i= n-1; i >= 0; --i )
for ( j = 1; j <= i; ++j )
if ( t[j] > t[j-1] )
{
tmp= t[j-1];
t[j-1]= t[j];
t[j]= tmp;
}
}
5.6. Gyorsrendezs
A gyorsrendezs koncepcija hasonl a binris keress koncepcijhoz, azaz a rendezendo elemeket
megfelezi, majd a rendezst a kt fl tartomnyon hajtja vgre:
Elso lpsknt jelljnk ki egy elemet (x), amelyet a megfelelo helyre szeretnnk rakni.
16
Kovcs Gyrgy
Tegyk ezt az elemet a tmb vgre (cserljk meg az utols elemmel) s inicializljuk az
aktualis vltoz rtkt 0-ra.
Induljunk el a tmb elejrol s a tmb utols elotti elemig ha valamely elemre (y) teljesl, hogy
kisebb, mint a korbban kijellt x elem, akkor ezen y elemet cserljk meg a tmb aktualis
sorszm rtkt az y rtkkel, majd nveljk az aktualis valtoz rtkt 1-gyel.
Knnyu ltni, hogy a fenti muveletsor
17
visszatrsi rtke, azaz az aktualis vltoz rtke azon elemnek az indexe, amely biztosan a
helyn van. Mivel tudjuk, hogy tole balra csak tole kisebb elemek, tole jobbra csak tole nagyobb
elemek vannak, meghvjuk jra a gyorsRendezesKezdetEsVeg fggvnyt, gy paramterezve,
hogy az a tmb kezdettol a j helyen lvo elemig, vagy a j helyen lvo elemet kveto elemtol a
tmb vgig fusson le. Knnyu ltni, hogy a rekurzv hvsok sorn a tmb rendezett vlik.
int t[10]= {4, 2, 6, 1, 7, 3, 8, 9, 0, 2};
gyorsRendezesKezdetEsVeg(t, 0, 10);
kdrszlet a fggvny alkalmazsst szemllteti Ahhoz, hogy knnyebb tegyk a hasznlatt, rhatunk
egy egyszeru burkol (n. wrapper) fggvnyt, amely elfedi elolnk a rekurzv fggvny 0 paramternek
megadst:
void gyorsRendezes(int t[], int n)
{
gyorsRendezesKezdetEsVeg(t, 0, n);
}
Az albbi pldban a korbban vizsglt pldn keresztl mutatom be az algoritmus lpseit az egyes
particionlsi lpsek utn (flkvrrel szedtk az egyes lpsekben mr biztosan j helyen lvo elemeket):
elem indexe
rendezetlen tmb:
1. lps utn
2. lps utn
3. lps utn
4. lps utn
0.
3
0
0
0
0
1.
5
5
5
3
3
2.
0
3
3
3
3
3.
6
6
3
5
5
4.
3
3
6
6
6
(kijellt elem: 0)
(a 0 van a helyn, kijellt elem: 6)
(a 6 a helyre kerlt, kijellt elem: 3 (az 1. 3-as)
(a msodik 3-as kerlt a helyre, a kijellt elemek: 3, 5)
(mivel az utoljra kijellt rsztmbk 1 elemuek,
5.13. Feladat: rjon programot, amely a bemenetrol beolvasva 10 egsz szmot, feltlt egy egszekbol ll 10 elemu tmbt, rendezi azt nvekvoleg minimumkivlasztsos rendezssel, majd tovbbi
szmokat olvas be addig, amg a -1 rtket nem olvassa be, s minden beolvasott szm utn kirja,
hogy a szm benne van-e a tmbben, vagy nincs. A keresshez hasznljon binris keresst!
5.13. Megolds:
5.6.2. forrskd: rendezkeres.c
#include <stdio.h>
void minimumKivalasztasosNovekvoRendezes(int t[], int n)
{
int min, i, j, tmp;
for ( i= 0; i < n; ++i )
{
min= i;
for ( j = i; j < n; ++j )
if ( t[j] < t[min] )
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
18
Kovcs Gyrgy
int binarisKereses(int t[], int n, int k)
{
int alsoh= 0, felsoh= n - 1, kozep;
for ( kozep= (alsoh + felsoh) / 2; alsoh <= felsoh; kozep= (alsoh + felsoh) / 2 )
{
if ( t[kozep] == k )
return kozep;
if ( t[kozep] < k )
alsoh= kozep + 1;
else
felsoh= kozep - 1;
}
return -1;
}
int main(int argc, char** argv)
{
int t[10];
int i;
printf("adjon meg 10 szamot:\n");
for ( i= 0; i < 10; ++i )
scanf("%d",&(t[i]));
minimumKivalasztasosNovekvoRendezes(t, 10);
printf("adjon meg egy szamot:\n");
scanf("%d", &i);
while ( i != -1 )
{
if ( binarisKereses(t, 10, i) != -1 )
printf("benne van\n");
else
printf("nincs benne\n");
printf("adjon meg egy szamot:\n");
scanf("%d", &i);
}
return 0;
}
meg 10 szamot:
6 4 7 5 6 3 9
meg egy szamot:
benne
meg egy szamot:
van
meg egy szamot:
6. Halmazok
A halmaz adatszerkezet a matematikai halmaznak megfelelo struktra, amely tetszoleges tpus elemeket tartalmazhat. Legfontosabb tulajdonsgga, hogy minden elembol csak egyet tartalmazhat.
Ellenttben a tmbbel, a C nyelv nem tartalmaz beptett nyelvi eszkzt halmazok ltrehozsra,
ezrt a meglvo eszkzeinket kell felhasznlnunk arra, hogy halmaz adatszerkezetet hozzunk ltre.
19
pedig fggvnyekkel. Egy halmazt a matematikban nagyon gyakran annak indiktorfggvnyvel reprezentlunk. Az indiktorfggvny olyan fggvny, amely 1 rtket vesz fel azokon a pontokon, amelyek
elemei egy halmaznak, s 0 rtket azokon a pontokon, amelyek nem elemei a halmaznak. A
(1)
x=
iI{i:i0i<100i|3=0}
iZ
y=
x2 I{i0i<1}
x=
iI{i:i0i<100i|3=0} =
99
X
iI{i:i|3=0} ,
i=0
iZ
hiszen amelyik egsz szm nem eleme a [0, 99] intervallumnak, arra az indiktor fggvny rtke
biztosan 0. Azt az intervallumot, amelyen egy indiktorfggvny 1 rtket is felvehet, a tovbbiakban
alaphalmaznak nevezzk. Tekintsk az albbi kifejezst,
(4)
x=
99
X
iI{i:i|10=0} ,
i=0
amely a [0,99] intervallumban 10-zel oszthat egsz szmok sszegt jelenti. A fenti kifejezsben a
szumma utn szereplo i vltoz nmagt jelenti. egy pici mdostssal azonban a
(5)
x=
9
X
10iIi:||true| ,
i=0
kifejezs ugyanazt jelenti, mint a korbbi, azonban az indiktor fggvny mr csak a [0,9] halmazon vesz fel 1 rtket. A kt kifejezs eredmnye megegyezik, azaz a 10i fggvnnyel a szumma
utn lekpeztk az [0,99] intervallumbeli 10-zel oszthat szmok sszegt adja. Ebbol a pldbl jl
lthat, hogy egy egyszeru transzformcival, a halmaz tetszoleges elemhez egy j rtk rendelheto,
gy pldul a [0,9] halmazzal tetszoleges 10 elemu halmaz reprezentlhat, ha tallunk egy megfelelo
transzformcit (fggvnyt), amely az i [0, 9] rtkhez meg tudja hatrozni a reprezentlt halmaz
valamely elemt.
A fentiek miatt (teht mivel az egsz szmok egy N elemu halmazval tetszoleges azonos elemszm,
nem csak szmhalmaz reprezentlhat), a tovbbiakban csak egszeket tartalmaz halmazokkal fogunk dolgozni.
F ONTOS
20
F ONTOS
Kovcs Gyrgy
A fenti kifejezs eredmnyeknt ltrejn egy 100 elemu tmb, amely minden eleme 0. Ez teht azt
jelenti, hogy az A halmaz indiktorfggvnye az alaphalmaz minden elemn 0-t vesz fel, teht a
[0, N 1] intervallum egyik eleme sincs benne az A halmazban. Nem res halmazt rtelemszeru
kezdortkadssal hozhatunk ltre:
int B[10]= {0, 0, 1, 0, 1, 0, 1, 0, 1, 0};
A B halmaz indiktor fggvnye, azaz a B tmb 2., 4., 6. s 8. indexu eleme 1, teht a B halmaz
szemlletesen a 2, 4, 6 s 8 szmokat tartalmazza.
Tartalmazs vizsglat. A krds, hogy egy adott halmaz esetn az k rtk eleme-e a halmaznak?
Ennek megvlaszolsra egy logikai fggvnyt runk:
int eleme(int A[], int n, int k)
{
return k < n && A[k];
}
A fenti fggvny elso paramtere egy tmb, teht egy halmaz, msodik paramtere a tmb mrete,
azaz az alaphalmaz szmossga. A harmadik paramter a vizsglt elem, amelyrol el kell dntennk,
benne van-e a tmbben. A visszatrsi rtk logikai. Ha a k < n nem teljesl, akkor a keresett k elem
nincs benne az alaphalmazban, gy a visszatrsi rtk 0 lesz. Ha benne van, akkor kirtkelsre kerl
az A[k] rszkifejezs, amely ppen akkor 1, teht igaz, ha a k benne van a halmazban.
Halmazok metszete. Halmazok metszett nagyon egyszeru eljrssal szmthatjuk ki. Az eljrsnak paramtere lesz a kt halmaz, amelyiknek a metszett szeretnnk venni, azaz kt egsz tpus
tmb, egy harmadik, az elozoekkel megegyezo mretu halmaz (tmb), amelybe az eredmnyt kiszmtjuk,
valamint az alaphalmaz (vagyis a tmbk) mrete.
void metszet(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] && B[i];
}
Knnyu ltni, hogy a C eredmny tmbben ppen akkor lesz egy eleme rtke 1, ha az mind az A,
mind a B tmbben 1, azaz mindkt tmbben benne van.
21
Halmazok unija. Halmazok unijt az elozohz hasonl paramterezsu egyszeru eljrssal szmthatjuk
ki:
void unio(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] || B[i];
}
A fenti megoldsban felhasznltuk, hogy ha az A[i] rtke vagy B[i] rtke nem nulla, azaz 1,
akkor a logikai "vagy" muvelet
Knnyu ltni, hogy az A[i] && !B[i] kifejezs ppen akkor lesz igaz, azaz 1 rtku,
ha az A tmb
i. eleme 1, s a B tmb i. eleme 0.
Halmaz komplementere. A halmaz komplementert szmt eljrs csak hrom paramtert vr: a
halmazt, amelynek komplementert ki szeretnnk szmtani, a halmazt, amelybe a komplementert ki
szeretnnk szmtani, valamint az alaphalmaz mrett.
void komplementer(int A[], int B[], int n)
{
int i;
for ( i= 0; i < n; ++i )
B[i]= !A[i];
}
A ciklus magjban egy negci szerepel, melynek eredmnyeknt a B tmb i. eleme ppen akkor lesz
1, ha az A tmb i. eleme 0, s fordtva.
Halmaz szmossga. A halmaz szmossgt megad fggvny mg a fentiektol is egyszerubb,
paramterknt csak egy halmazt, azaz egy halmaz indiktorfggvnyt (tmb), valamint az alaphalmaz szmossgt (tmb mrete) vrja:
int szamossag(int A[], int n)
{
int i, sum= 0;
for ( i= 0; i < n; ++i )
sum+= A[i];
return sum;
}
Egyszeruen
kiszmtjuk a tmbben lvo 1 rtkek sszegt majd visszaadjuk azt visszatrsi rtkknt.
22
Kovcs Gyrgy
6.1. Feladat: Mdostsa a metszetet, unit, klnbsget s komplementert szmt eljrsokat gy,
hogy a ciklusok magjban egy matematikai muvelet
ne vltozzon!
6.1. Megolds:
Metszet: A[i]*B[i],
uni: 1 - (1 - A[i])*(1 - B[i]),
klnbsg: A[i]*(A[i] - B[i]),
komplementer: 1 - A[i].
6.2. Feladat: Mdostsa a metszetet, unit s klnbsget szmt eljrsokat gy, hogy feltesszk,
a tmbk mrete, teht a halmazok alaphalmaza klnbzo, s az elso paramterknt kapott tmb
mrete a nagyobb, valamint az eredmny halmaz alaphalmaza (a harmadik tmb paramter mrete)
megegyezik az elso paramterknt kapott tmb mretvel.
6.2. Megolds:
void metszet(int A[], int n, int B[], int m, int C[])
{
int i;
for ( i= 0; i < m; ++i )
C[i]= A[i] && B[i];
for ( ; i < n; ++i )
C[i]= 0;
}
void unio(int A[], int n, int B[], int m, int C[])
{
int i;
for ( i= 0; i < m; ++i )
C[i]= A[i] || B[i];
for ( ; i < n; ++i )
C[i]= A[i];
}
void kulonbseg(int A[], int n, int B[], int m, int C[])
{
int i;
for ( i= 0; i < m; ++i )
C[i]= A[i] && !B[i];
for ( ; i < n; ++i )
C[i]= A[i];
}
A fenti kdokat kiegsztettk teht egy jabb mret paramterrel. A fggvnyek trzsben tallhat elso ciklus minden esetben megegyezik a korbbi esetekkel, az egyetlen klnbsg, hogy a ciklusvltoz felso hatra a kisebbik tmb mrete, ugyanis az alaphalmazoknak csak a kzs rszn
rtelmezhetoek a muveletek.
23
6.3. Megolds: A szimmetrikus differencia egy szm, amely kt halmaz klnbzosgt jellemzi.
Defincija
(6)
A B = |A\B| + |B\A|,
teht egy elem akkor szmtand bele az A s B halmaz szimmetrikus differencijba, ha benne van
az A halmazban, de nincs benne a B-ben, vagy benne van a B halmazban, de nincs benne az A-ban.
Ezek alapjn
int szimmetrikusDifferencia(int A[], int B[], int n)
{
int i, sum= 0;
for ( i= 0; i < n; ++i )
sum+= (A[i] && !B[i]) || (B[i] && !A[i]);
return sum;
}
Knnyu ltni, hogy a logikai kifejezs ppen azt fejezi ki, hogy az i rtk vagy benne van A-ban,
de nincs benne B-ben, vagy benne van B-ben, de nincs benne A-ban. Ha a kt rszkifejezs valamelyike igaz, akkor a logikai "vagy"-nak ksznhetoen az egsz kifejezs rtke "igaz", azaz 1 lesz, amit
hozzadunk a sum vltozhoz.
6.4. Feladat: rja t a szimmetrikus differencit szmt fggvnyben szereplo kifejezst matematikai
muveletre!
6.5. Feladat: rjon foprogramot, amely a konzolrl feltlt kt 5 elemu halmazt, azaz beolvassa az
indiktorfggvnyket, mint egsz szmokat, majd a kiszmtja s a kimenetre rja a metszetk s
unijuk szmossgt!
6.5. Megolds:
6.0.1. forrskd: halmaz.c
#include<stdio.h>
void metszet(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] && B[i];
}
void unio(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] || B[i];
}
int szamossag(int A[], int n)
{
int i, sum= 0;
for ( i= 0; i < n; ++i )
sum+= A[i];
return sum;
}
24
Kovcs Gyrgy
A fenti alkalmazs lefuttatsakor valamint a plda bemenet begpelsekor az albbi kimenetet kapjuk:
kerem az elso halmaz indikator fuggvenyet:
1 0 1 1 0
kerem az masodik halmaz indikator fuggvenyet:
1 1 1 0 0
a halmazok metszetenek szamossaga:
2
a halmazok uniojanak szamossaga:
4
7. Multihalmazok
F ONTOS
A multihalmaz adatszerkezet a halmaz adatszerkezet (s matematikai fogalom) ltalnostsa. A koncepcionlis klnbsg: mg egy halmazban egy elembol
csak egy szerepelhetett, a multihalmazban
egy elembol
tetszoleges
muvelettel
25
if ( multihalmaz[j] > 0 )
--multihalmaz[j];
Megjegyezzk, hogy a fenti eljrs esetn feltettk, hogy a vizsglt k rtk benne van a [0, N 1]
tartomnyban, ezrt az indexhatrok vizsglata nem szerepel az eljrsban. A fenti eljrs nem csak
multihalmaz, hanem halmaz esetn is mukdik.
A megoldsban a hromoperandus opertort hasznltuk, termszetesen a hromoperandus opertor helyett egy egyszeru if utasts is hasznlhat a ciklus magjban.
Klnbsg. A klnbsgkpzshez rendre ki kell vonni egyik halmaz elemszmaibl a msik halmaz megfelelo elemszmait, gyelnnk kell azonban arra, hogy az eredmnyknt eloll multihalmazban nem szerepelhet negatv elemszm, ha az A halmazban valamelyik elembol kevesebb van,
mint a B halmazban, akkor a klnbsghalmazba 0 kerl az adott elembol.
void kulonbseg(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] < B[i] ? 0 : A[i] - B[i];
}
A fenti eljrsban szintn a hromoperandus opertort hasznltuk a kifejezs rvidtse vgett, termszetesen if utastssal is megvalsthat.
26
Kovcs Gyrgy
Vegyk szre, hogy a multihalmazokra megrt eleme s szamossag fggvnyek ugyangy mukd
nek s hasznlhatak halmazokra is.
7.1. Feladat: Mdostsa az unio, metszet s kulonbseg eljrsokat gy, hogy klnbzo mretu
alaphalmazokkal rendelkezo multihalmazok esetn is mukdjenek.
Felteheto, hogy ha az A s B
halmaz alaphalmaznak mrete klnbzo, akkor az A, teht elso paramter lesz nagyobb, s a C
paramterknt tvett multihalmaz mrete megegyezik az A mretvel!
7.1. Megolds:
void unio(int A[], int B[], int C[], int sizeAC, int sizeB)
{
int i;
for ( i= 0; i < sizeB; ++i )
C[i]= A[i] + B[i];
for ( ; i < sizeAC; ++i )
C[i]= A[i];
}
void metszet(int A[], int B[], int C[], int sizeAC, int sizeB)
{
int i;
for ( i= 0; i < sizeB; ++i )
C[i]= A[i] < B[i] ? A[i] : B[i];
for ( ; i < sizeAC; ++i )
C[i]= 0;
}
void kulonbseg(int A[], int B[], int C[], int sizeAC, int sizeB)
{
int i;
for ( i= 0; i < sizeB; ++i )
C[i]= A[i] < B[i] ? 0 : A[i] - B[i];
for ( ; i < sizeAC; ++i )
C[i]= A[i];
}
A fenti fggvnek paramterezse azonos, a sizeAC paramter tartalmazza az A s C multihalmazok azonos alaphalmaznak mrett, mg a sizeB a B multihalmaz alaphalmaznak szmossgt
tartalmazza.
7.2. Feladat: Mdostsa a multihalmazokra megrt eleme fggvnyt gy, hogy az ellenorizze azt is,
hogy a vizsglt k rtk (melyrol el szeretnnk dnteni, hogy benne van-e a multihalmazban vagy
sem), benne van-e az alaphalmazban, azaz a paramterknt kapott tmbnk indexelsekor nem kvetnk-e el alul- vagy tlindexelst!
7.2. Megolds:
int eleme(int A[], int n, int k)
{
27
A fenti pldban a return utni logikai kifejezsek sorrendje viszonylag kttt, ugyanis kihasznljuk, hogy az && opertor rvidzr opertor. Ha az A[k] kifejezst a logikai kifejezs elejre
rnnk, i < 0 vagy i >= n esetben tlindexels llhatna elo.
7.3. Feladat: rjon foprogramot, amely a konzolrl feltlt kt 5 elemu multihalmazt, azaz beolvassa
rendre elemeik szmt, mint egsz szmokat, majd a kiszmtja s a kimenetre rja a metszetk s
unijuk szmossgt!
7.3. Megolds:
7.0.1. forrskd: multihalmaz.c
#include<stdio.h>
void metszet(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] + B[i];
}
void unio(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] < B[i] ? A[i] : A[i] - B[i];
}
int szamossag(int A[], int n)
{
int i, sum= 0;
for ( i= 0; i < n; ++i )
sum+= A[i];
return sum;
}
int main(int argc, char** argv)
{
int a[5], b[5], c[5];
int i;
printf("kerem az elso multihalmaz elemeit:\n");
for ( i= 0; i < 5; ++i )
scanf("%d", &(a[i]));
printf("kerem az masodik multihalmaz elemeit:\n");
for ( i= 0; i < 5; ++i )
scanf("%d", &(b[i]));
metszet(a, b, c, 5);
printf("a multihalmazok metszetenek szamossaga: %d\n", szamossag(c,5));
unio(a, b, c, 5);
printf("a multihalmazok uniojanak szamossaga: %d\n", szamossag(c,5));
return 0;
}
A fenti alkalmazs lefuttatsakor valamint a plda bemenet begpelsekor az albbi kimenetet kapjuk:
kerem az elso multihalmaz elemeit fuggvenyet:
2 0 3 4 0
F ONTOS
28
Kovcs Gyrgy
Fontos megjegyeznnk, hogy a fenti felrsban az azonosito nevu tmb M elemu egszeket tartalmaz tmbk N elemu tmbje. Kt dimenzis tmb (mtrix) esetn annak i, j indexu elemt
azonosito[i][j] mdon rhetjk el. Lssunk egy konkrt pldt, amelyben ltrehozok egy tmbt, majd a kimenetre rom az rtkeit, gy, hogy minden sorban a msodik paramternek (M) megfelelo
mretu rsztmbk elemei kerljenek:
int t[3][2]= {{1,2},{2,3},{3,4}};
int i,j;
for ( i= 0; i < 3; ++i )
{
for ( j= 0; j < 2; ++j )
printf("%d ",t[i][j]);
printf("\n");
}
Vegyk szre, hogy az i,j indexvltozk felso hatra annak a dimenzinak a mrete, amely helyen
alkalmazzuk o ket. Tbbdimenzis tmbk esetn hasonlan jrunk el, csak tovbb nveljk a dimenzik szmt. Az albbiakban egy hrom dimenzis esetet vizsglunk:
int t[2][3][4]= {{{1,2,3,4},{2,3,4,5},{3,4,5,6}},{{4,5,6,7},{5,6,7,8},{6,7,8,9}}};
int i, j, k;
for ( i= 0; i < 2; ++i )
29
{
for ( j= 0; j < 3; ++j )
{
for ( k= 0; k < 4; ++k )
printf("%d ", t[i][j][k]);
printf("\n");
}
printf("\n");
}
A kt- illetve tbbdimenzis adatszerkezetek funkcijukat tekitve vagy egy matematikai konstrukci megvalsulsai (pl. mtrix), vagy egyszeruen
a ktdimenzis tmbket
F ONTOS
30
Kovcs Gyrgy
Valstsuk meg a fenti mtrix szorzst megvalst eljrst, tetszoleges mretu mtrixokra:
void matrixSzorzas(float a[], int sa, int oa, float b[], int sb, int ob, float c[])
{
int i, j, k;
float sum;
for ( i= 0; i < sa; ++i )
{
for ( j= 0; j < ob; ++j )
{
sum= 0;
for ( k= 0; k < oa; ++k )
sum+= a[oa * i + k] * b[k * ob + j];
c[ob * i + j]= sum;
}
}
}
31
8.2. Feladat: rjon foprogramot, amely beolvassa egy 2 3 (a) valamint 3 2 (b) mretu,
lebegopontos
rtkeket tartalmaz mtrix elemeit soronknt, kirja o ket mtrixos alakban, sszeszorozza o ket ab
valamint ba alakban, majd kirja az eredmnyeket is mtrixos alakban! A megoldshoz hasznlja fel
a korbban ltrehozott eljrsokat!
8.2. Megolds: A megolds sorn ltre kell hoznunk kt 6 mretu,
egydimenzis tmbt a 2 3
valamint 3 2 mretu mtrixok trolsra, valamint mivel az eredmny mtrixok 2 2 valamint 3 3
mretuek,
32
Kovcs Gyrgy
9. Ritkamtrix
F ONTOS
0 0 0
0 2 0
(7)
0 1 0
0 0 0
3
0
0
2
33
1
1
0
0
A fenti mtrixban a gyakori elem szemmel lthatan a 0. A mtrix mrete 4 5, a gyakori elem elofordulsainak szma 14, azaz a hromsoros reprezentci egy hrom sorbl s soronknt 4 5 14 = 6
elembol ll struktra lesz:
sor
oszlop
rtk
0
3
3
0
4
1
1
1
2
1
4
1
2
1
1
2
3
2
Knnyu ltni, hogy az eredeti mtrix brzolshoz 20 rtket kellett trolni, ezen utbbi hromsoros reprezentcihoz azonban elegendo 18 rtk trolsa, teht helyfelhasznls szempontjbl
hatkonyabb. Termszetesen ha mg "ritkbb" lenne a kiindulsi mtrix, az brzols mg hatkonyabb
lenne. Krds, hogy a fenti hrom soros reprezentcit hogyan valsthatjuk meg egy programban?
A vlasz ismt az, hogy egydimenzis tmbk segtsgvel, azaz a ritka mtrixok reprezentcijhoz
hasznlt hrom sort hrom darab egydimenzis tmbbel brzolva. Ennek megfeleloen, az albbi
fggvny paramterknt kap egy sorfolytonosan reprezentlt egszeket tartalmaz ktdimenzis
tmbt, sorainak s oszlopainak szmt, a gyakori elemet, valamint hrom egydimenzis tmbt,
amelyek mrete egy olyan szm, amelytol biztosan kevesebb a nem-gyakori elemek szma a ktdimenzis tmbben. A fggvny visszatrsi rtke a nem-gyakori elemek pontos szma.
int felepit3sor(int t[], int sorok, int oszlopok, int gyakoriElem, int sor3[], int
oszlop3[], int ertek3[])
{
int i, j, k= 0;
for ( i= 0; i < sorok; ++i )
for ( j= 0; j < oszlopok; ++j )
if ( t[i*oszlopok + j] != gyakoriElem )
{
sor3[k]= i;
oszlop3[k]= j;
ertek3[k]= t[i*oszlopok + j];
++k;
}
return k;
}
A fenti fggvny ltrehozza teht a paramterknt kapott mtrix hrom soros reprezentcijt a szintn paramterknt kapott egydimenzis tmbkben. Megjegyezzk, feltettk, hogy az egydimenzis
tmbk mrete nagyobb vagy egyenlo a gyakori elemtol klnbzo mtrix elemek szmval. Hrom
soros reprezentci esetn teht egy mtrixot hrom egydimenzis tmb valamint a gyakori elem
reprezentl!. rjuk most meg azt a fggvnyt, amely paramterknt kapja egy mtrix hrom soros
reprezentcijt (hrom tmb s azok pontos mrete), a gyakori elemmel nem megegyezo elemek
szmt (azaz az a hromsoros reprezentci tmbjeinek mrett), a gyakori elemet, valamint az s, o
koordintkat s visszatrsi rtkknt visszaadja az s, o koordintj elemet!
int elem(int sor3[], int oszlop3[], int ertek3[], int meret, int gyakoriElem, int s, int
o)
{
int i;
for ( i= 0; i < meret; ++i )
F ONTOS
34
Kovcs Gyrgy
if ( sor3[i] == s && oszlop3[i] == o )
return ertek3[i];
return gyakoriElem;
}
Knnyu ltni, hogy az utols ciklusban tulajdonkppen egy teljes keresst valstunk meg, azaz
megvizsgljuk a hrom soros reprezentcihoz hasznlt sor3 s oszlop3 tmbket, hogy tartalmazzke azon elem indext (s,o), amelyet la akarunk krdezni, ha ugyanis tartalmazzk, akkor visszaadjuk
az ertek3 tmb megfelelo elemt, ha nem tartalmazzk, akkor visszaadjuk a gyakori elemet.
9.2. Ngy soros reprezentci
A ngysoros reprezentci a hromsoros reprezentci kibovtse egy jabb sorral, amely a hromsoros reprezentciba bekerlt minden elemhez a hromsoros reprezentci azon indext tartalmazza,
amely az elem oszlopban a kvetkezo nem-gyakori elem. Ha nincs ilyen, akkor a specilis -1 rtket
tartalmazza. Teht a korbban is hasznlt
0 0 0 3 1
0 2 0 0 1
(8)
0 1 0 0 0
0 0 0 2 0
mtrix esetn:
sor
oszlop
rtk
mutat
0
3
3
5
0
4
1
-1
1
1
2
4
1
4
1
-1
2
1
1
-1
2
3
2
-1
Knnyu ltni teht, hogy az elso nem-gyakori elem a 3, amelynek oszlopban a kvetkezo az utols
sorban tallhat 2. Ez a 2 a hromsoros brzols utols, azaz 5 indexu eleme, ezrt a 3 elemhez tartoz mutat az 5, ami gy teht a megfelelo oszlop kvetkezo nem-gyakori elemre mutat a hromsoros brzolsban. A ngysoros reprezentcit felpto fggvny pedig az albbi:
int felepit4sor(int t[], int sorok, int oszlopok, int gyakoriElem, int sor3[], int
oszlop3[], int ertek3[], int mutato3[])
{
int i, j, k= 0;
for ( i= 0; i < sorok; ++i )
for ( j= 0; j < oszlopok; ++j )
if ( t[i*oszlopok + j] != gyakoriElem )
{
sor3[k]= i;
oszlop3[k]= j;
ertek3[k]= t[i*oszlopok + j];
++k;
}
for ( i= 0; i < k; ++i )
{
for ( j= i+1; j < k; ++j )
if ( oszlop3[i] == oszlop3[j] )
break;
if ( j == k )
mutato3[i]= -1;
else
mutato3[i]= j;
}
return k;
}
35
A ngysoros reprezentcit felpto fggvny elso rsze, azaz a sor3, oszlop3 s ertek3 tmbk
kitltse megegyezik a hromsoros reprezentcit felpto eljrssal. Ezt kveti egy for-ciklus, amely
rendre vgig megy a mr kitlttt hromsoros reprezentcin, s minden elemhez olyan elemet keres,
amelyiknek az oszlop indexe megegyezik az ppen vizsglt elemvel. Ha tall ilyet, akkor berakja a
mutato3 tmb megfelelo helyre az indext, ha nem tall, akkor -1-et rak a mutat tmbbe. Knnyu
ltni, hogy ezen utbbi ciklus belseje ppen egy teljes keress, ahol a visszatrsi rtk a mutato3
tmb i indexu helyre kerl.
A hromsoros reprezentcinl megrt elem fggvny ngysoros reprezentcinl is hasznlhat.
9.1. Feladat: Ksztse el az albbi mtrix hrom s ngysoros reprezentcijt!
1 1
1 1
1 1
(9)
2
0
1
9.1. Megolds: Knnyu ltni, hogy a gyakori elem az 1. Ez alapjn teht a hromsoros reprezentci:
sor
oszlop
rtk
0
2
2
1
2
0
sor
oszlop
rtk
mutat
0
2
2
1
1
2
0
-1
9.2. Feladat: Ksztse el az albbi ngysoros reprezentcihoz tartoz mtrix-ot, ha a mtrix ngy
sorbl s hrom oszlopbl ll, a gyakori elem pedig 1!
sor
oszlop
rtk
mutat
0
1
1
-1
2
2
2
-1
9.2. Megolds:
(10)
1 1 1
1 1 1
1 1 2
1
1
1
9.3. Feladat: rjon eljrst, amely paramterknt kapja egy ktdimenzis tmb hromsoros reprezentcijt (3 tmb, azok pontos mrete), a gyakori elemet valamint a mtrix mrett (sorok, oszlopok
szma) s a kimenetre rja a mtrixot mtrix alakban! (Feltehetjk, hogy a hromsoros reprezentciba
a sorfolytonos brzolsnak megfelelo sorrendben kerltek be az elemek!)
9.3. Megolds:
36
Kovcs Gyrgy
void kiir(int sor3[], int oszlop3[], int ertek3[], int meret, int gyakoriElem, int sorok
, int oszlopok)
{
int i, j;
for ( i= 0; i < sorok; ++i )
{
for ( j= 0; j < oszlopok; ++j )
printf("%d ", elem(sor3, oszlop3, ertek3, meret, gyakoriElem, i, j));
printf("\n");
}
}
37
4 elemu 0. sorat:
4 elemu 1. sorat:
4 elemu 2. sorat:
4 elemu 3. sorat:
4 elemu 4. sorat:
9.5. Feladat: A ritka mtrixok hrom- s ngysoros trolsnak elonye teht, hogy kevesebb helyen
lehet trolni o ket, mint magt a teljes mtrixot. Szmolja ki, hogy egy N M mretu,
egszeket
tartalmaz mtrix esetn legfeljebb hny nem-ritka elem fordulhat elo a mtrixban, hogy a hrom,
valamint ngysoros reprezentci kevebb helyet foglaljon a memriban, mint az eredeti mtrix!
9.5. Megolds: A hromsoros reprezentci esetn minden egyes nem-gyakori elem elofordulst
hrom adattal rgztnk, a krds teht az, hogy melyik az az n rtk, amelyre
(11)
3n < M N
38
Kovcs Gyrgy
n<
MN
3
olyan elem lehet a mtrixban, amely nem egyezik meg a gyakori elemmel. Ngysoros reprezentci
esetn hasonlan addik az
(13)
F ONTOS
n<
MN
4
megolds. Megjegyezzk, hogy a fenti szmtsoknl kihasznltuk, hogy mind az indexek, mind a
mtrix rtkei int egsz tpusak, gy mretk megegyezik. Ms tpus adatoknl, vagy ms tpussal
indexelt mtrix esetn ms rtket kaphatunk a hatkonysg felso hatrra!
10. Sor
F ONTOS
rendelkezik:
A sor a muveleteib
ol is lthatan dinamikus adatszerkezet, azaz a benne trolt elemek mrete vltozhat. Viselkedst tekintve FIFO adatszerkezet, ami az angol First In, First Oout kifejezsbol ered,
ami arra utal, hogy amelyik elem eloszr bekerl a sorba, az is kerl ki belole eloszr. A sornak teht
nem rheto el minden eleme kzvetlenl, gy, mint a tmbnek, mindig csak egy elemhez frhetnk
hozz.
Szemlletesen a sort gy kpzelhetjk el, mint egy sort egy bevsrlkzpont pnztrnl, aki elobb
bell a sorba, az is ll ki eloszr a sorbl, s senki ms nem ll ki a sorbl, csak amikor sorrakerl,
teht a berkezs sorrendjben trtnik a tvozs is.
A sorhoz kapcsoldan a fenti muveleteket
F ONTOS
Termszetesen a sorokat kezelo algoritmusokat is nagyon sok fle mdon meg lehet valstani, mi
most az egyszerusg
kedvrt olyan megvalstst nznk meg, amely globlis vltozkkal dolgozik. A programunk teht szemben az eddigiekkel egyetlen adatszerkezettel fog dolgozni, amely minden fggvnybol s eljrsbl elrheto lesz. A globlis vltoz olyan vltoz, amelyet a kd szvegben fggvnydefincikon kvl helyezhetnk el, s a vltoz tetszoleges
ot
kveto fggvnyben
hasznlhat, paramtertads nlkl.
A kvetkezo hrom vltozata a sornak mind ugyanazt az adatszerkezetet valstja meg, az egyes
megvalstsok csak abban klnbznek, hogy melyik hogyan kezeli azokat az eseteket, amikor
az elemek elrik a tmb vgt, stb.
10.1. Rgztett sor
A rgztett sor
39
vizsgljuk.
Ltrehozs. Sor ltrehozsa pldnkban egy tetszoleges mretu globlis tmb vltoz ltrehozst
s egy szintn globlis veg vltoz ltrehozst, valamint a -1-re lltst jelenti. A veg vltoz
rtke teht mindig a sor aktulis utols elemnek indexe a tmbben, a -1 azt jelzi, hogy res a sor.
Teht a
const int N= 20;
int sor[20];
int veg= -1;
kdrszlettel ltrehoztunk egy res sort. Esetnkben az N konstans trolja a tmb mrett, azaz a sor
maximlis elemszmt.
res sor vizsglata. Azt, hogy res-e a sor egyszeruen
egy olyan fggvnnyel vizsglhatjuk meg,
amely logikai igaz rtket ad vissza ha a sorban nincs egyetlen elem sem (a veg vltoz rtke -1).
int uresSor()
{
return veg == -1;
}
Elso elem elrse. (TOP) A sor elso eleme mindig a tmb elso eleme lesz, gy a sor elso elemt
a tmb 0 indexu elemnek elrsvel krdezhetjk le. Az albbi fggvny visszaadja a sor elso elemnek rtkt:
int top()
{
return sor[0];
}
Elem hozzadsa. (PUT) Elem hozzadst a veg vltoz felhasznlsval vgezzk egy nagyon
egyszeru eljrsban, amely paramterknt kapja azt az elemet (esetnkben egsz szmot), amelyet be
szeretnnk tenni a sor vgre.
void put(int x)
{
if ( veg == N - 1 )
printf("A sor tele van!\n");
else
{
++veg;
sor[veg]= x;
}
}
40
Kovcs Gyrgy
Elem eltvoltsa. (GET) Elem eltvoltsa mindig az elso elem, teht a 0 indexu tmb elem eltvoltst
jelenti. Clunk, hogy az eltvolts utn az eddigi msodik elem legyen a 0 indexu,
teht a tmb elemeit a tmb elejre kell cssztatni, azaz
int get()
{
int i;
int aktualis= -1;
if ( veg == -1 )
printf("A sor res!\n");
else
{
aktualis= sor[0];
for ( i= 0; i < veg; ++i )
sor[i]= sor[i+1];
--veg;
}
return aktualis;
}
Ha res a sor, semmi sem trtnik. Ha a sor azonban nem res, akkor az elso elem eltvoltst s a
tbbi elem elore cssztatst egy lpsben vgezzk, a tmb i+1. elemt a tmb i. elemre vltoztatva, majd cskkentjk a veg vltoz rtkt, hiszen a tmb gy mr kevesebb elemet tartalmaz.
10.2. Vndorl sor
A vndorl sor a sor adatszerkezetnek a rgztett sortl egy hatkonyabb megvalstsa. A hatkonysg
abban nyilvnul meg, hogy mg rgztett sornl az elemeket minden egyes get muveletnl
mozgatni
kell, a vndorl sor esetn az elso elem indext egy jabb int tpus vltozban tartjuk nyilvn,
gy eltvoltsnl, amikor a msodik elem vlik a sor j elso elemv, elegendo a sor kezdett jelzo
indexvltoz rtkt nvelni egyel. Elem mozgatsra csak akkor van szksg, ha a sor vge elrt a
tmb vgt, ekkor az sszes elemet a sor elejre cssztatjuk.
Ltrehozs. Hasonl a rgztett sorhoz, a klnbsg, hogy egy jabb, kezdet vltozt is ltrehozunk:
const int N= 20;
int sor[20];
int veg= -1;
int kezdet= 0;
41
Az elso elem elrs a sor kezdett jelzo kezdet vltozban trolt index
int top()
{
return sor[kezdet];
}
j elem hozzadsa. (PUT) j elemet a sor vgre rakhatunk be, a korbbihoz hasonl mdon:
void put(int x)
{
int i;
if ( kezdet == 0 && veg == N - 1 )
{
printf("A sor megtelt!\n");
return;
}
else if ( veg == N - 1 )
{
for ( i= kezdet; i < N; ++i )
sor[i - kezdet]= sor[i];
veg-= kezdet;
kezdet= 0;
}
++veg;
sor[veg]= x;
}
A sor vgre j elemet berak fggvny egy kicsit komplexebb, mint a rgztett sor esetn. Az elso if
felttelben azt vizsgljuk meg, hogy tele van-e a tmb, azaz a kezdet vltoz rtke 0, a veg vltoz
rtke N-1-e. Ha igen, akkor nem tudunk j elemet hozzadni a sorhoz, kirunk egy hibazenetet,
majd befejezzk az eljrst. Az else if gban tallhat felttel akkor fog teljeslni, ha a veg vltoz
elrte a tmb vgt, azonban a kezdet vltoz rtke nem 0, azaz a sor kezdete elvndorolt a tmb
kezdetrol, gy ha elorecssztatjuk az elemeket gy, hogy a kezdet vltoz a 0 index-re mutasson,
akkor a tmb vgn jra lesz hely j elemeknek. A for ciklus ezt az elorecssztatst valstja meg.
Ezt kvetoen mivel ppen a kezdet vltoz rtknek megfelelo szm lpst tett meg minden elem
a tmb eleje fel, a veg vltozbl kivonjuk a kezdet rtkt, hogy megkapjuk a sor aktulis utols
elemnek indext, mg a kezdet vltoz rtkt 0-ra lltjuk. Ezt kvetoen, ha a vezrls eljut a
++veg utastsig, az azt jelenti, hogy tudunk berakni j elemet a sor vgre, gy megnveljk az
utols elem indext egyel (veg), s betesszk az j elemet a sor vgre.
Elem eltvoltsa. (GET) Az elso elem eltvoltsa nagyon egyszeru,
a kezdet rtkt kell csak
nvelnnk egyel.
int get()
{
if ( kezdet > veg )
{
printf("A sor res!\n");
return -1;
}
else
++kezdet;
return sor[kezdet-1];
}
42
Kovcs Gyrgy
F ONTOS
A ciklikus a sor a sorok tmbbel trtno megvalstsnak leghatkonyabb mdja, ciklikus megvalsts esetn sohasem fordul elo elem mozgats, minden esetben csak a sor kezdett s vgt
jelzo vltozkat manipulljuk. Ha a veg vltoz elrte a tmb vgt, akkor az elejn fog jra megjelenni, teht a sor mintegy krberhet a tmbn. Az indexmuveletek
azt jelenti,
hogy minden get muveletnl
sorn hozzadunk egyet a vltoz rtkhez. Ezt kvetoen mr ezen vltoz alapjn el tudjuk dnteni, hogy
res-e a sor.
Ltrehozs.
const int N= 20;
int sor[20];
int veg= -1;
int kezdet= 0;
int elemSzam= 0;
j elem hozzadsa. (PUT) Ha a sorban lvo elemek szma kisebb, mint a maximlis elemszm 1, az azt jelenti, hogy van mg hely a sorban, teht felvehetjk az x paramter rtkt a sor vgre:
void put(int x)
{
if ( elemSzam < N - 1 )
{
veg= (veg + 1) % N;
sor[veg]= x;
++elemSzam;
}
else
{
43
10.4. Plda
Lssunk most egy egyszeru pldt, res sorbl kiindulva a tblzatban foglalom ssze, hogy egy
5 elemu tmbben trolt sor tartalma hogyan vltozik az egyes megvalstsok esetn. A pldban
pirossal jelzem a sor elso elemt (amely teht minden esetben a top fggvny visszatrsi rtke), s
flkvrrel szedem az utols elemet. Az alulvons jelek az 5 elemu tmb egyes helyeit jelzik.
Muvelet
put(3)
put(5)
put(2 + 2)
get()
get()
get()
put(1)
put(5)
put(7)
put(6)
get()
get()
Rgztett sor
3____
35___
354__
54___
4____
_____
1____
15___
157__
1576_
576__
76___
Vndorl sor
3____
35___
354__
_54__
__4__
_____
___1_
___15
157_
1576_
_576_
__76_
Ciklikus sor
3____
35___
354__
_54__
__4__
_____
___1_
___15
7__15
76_15
76__5
76___
44
Kovcs Gyrgy
int uresSor()
{
return veg == -1;
}
int top()
{
return sor[0];
}
void put(int x)
{
if ( veg == N - 1 )
printf("A sor tele van!\n");
else
{
++veg;
sor[veg]= x;
}
}
int get()
{
int i;
int aktualis= -1;
if ( veg == -1 )
A
zres!\n");
printf("A sor
else
{
aktualis= sor[0];
for ( i= 0; i < veg; ++i )
sor[i]= sor[i+1];
--veg;
}
return aktualis;
}
int main(int argc, char** argv)
{
int szam;
do
{
printf("kerek egy szamot:\n");
scanf("%d", &szam);
if ( szam == -1 )
break;
put(szam);
}while ( 1 );
printf("a sor elemei:\n");
while ( ! uresSor() )
{
printf("%d ", top());
get();
}
return 0;
}
45
egy szamot:
egy szamot:
egy szamot:
egy szamot:
egy szamot:
elemei:
6
10.1. Feladat: Hrom elemu tmbben reprezentlva a rgztett, vndorl s ciklikus sorokat, mi lesz
a sorok tartalma s mi lesz a kezdet, veg, elemSzam vltozk rtke az albbi muveletek
egyms
utn trtno vgrehajtst kvetoen?
put(3);
put(2);
put(2);
get();
10.1. Megolds: A megoldsban pirossal jelltem a sor elso, flkvrrel a sor utols elemt.
Rgztett sor: 2 2 2 (veg=1).
Vndorl sor: 3 2 2 (veg=2, kezdet=1).
Ciklikus sor: 3 2 2 (veg=2, kezdet=1, elemSzam=2).
A megoldsban zlddel jellt rtkek nem rszei a sornak, azonban a vgrehajtott muveletek
utn az
adott helyeken megtallhatak a tmbkben.
10.2. Feladat: Ngy elemu tmbben reprezentlva a rgztett, vndorl s ciklikus sorokat, mi lesz a
sorok tartalma s mi lesz a kezdet, veg, elemSzam vltozk rtke az albbi kdrszlet vgrehajtsa
utn?
int a= 2;
put(3);
put(a*a);
put(a + 2);
put(a % 2);
a= get();
get();
put(a);
10.2. Megolds: A megoldsban pirossal jelljk a sor elso, flkvrrel a sor utols elemt.
Rgztett sor: 4 0 3 0 (veg=2).
Vndorl sor: 4 0 3 0 (kezdet=0, veg=2),
Ciklikus sor: 3, 4 4 0 (kezdet=2, veg=0, elemSzam=3).
Megjegyezzk, hogy az elozo pldhoz hasonlan a zlddel szedett rtkek nem rszei a soroknak, a
muveletek
ciklikus soron,
majd a kimenetre rja a sor reprezentcijra hasznlt tmb tartalmt. A sor elso elemt a tmbben
egy azt megelozo . karakterrel jelezze, a sor utols elemt pedig egy azt megelozo _ karakterrel.
10.3. Megolds: A megoldshoz egyszeruen
egy programba szervezzk a ciklikus sort kezelo put
eljrst s get fggvnyt, majd miutn a foprogramba (main-fggvnybe) bemsoltuk az elozo feladat muveletsort,
46
Kovcs Gyrgy
i ciklusvltoz rtke pp kezdet vagy veg-e, s ha igen, akkor kirjuk a sorban trolt szm elott kirjuk a megfelelo szimblumot.
10.4.2. forrskd: ciklikussor.c
#include <stdio.h>
const int N= 4;
int sor[4];
int veg= -1;
int kezdet= 0;
int elemSzam= 0;
void put(int x)
{
if ( elemSzam <= N - 1 )
{
veg= (veg + 1) % N;
sor[veg]= x;
++elemSzam;
}
else
{
printf("A sor tele van!\n");
}
}
int get()
{
if ( elemSzam > 0 )
{
kezdet= (kezdet + 1) % N;
--elemSzam;
}
else
{
printf("A sor
A
zres!\n");
return -1;
}
return sor[(kezdet-1)%N];
}
int main( int argc, char** argv)
{
int i;
int a= 2;
put(3);
put(a*a);
put(a + 2);
put(a % 2);
a= get();
get();
put(a);
for ( i= 0; i < N; ++i )
{
if ( i == kezdet )
printf(".");
if ( i == veg )
printf("_");
printf("%d ", sor[i]);
}
return 0;
}
47
11. Verem
A verem a sorhoz hasonl nagyon egyszeru adatszerkezet. Legfontosabb muveletei:
A verem a sorhoz hasonlan dinamikus adatszerkezet, teht elmletben tetszoleges sok elemet tartalmazhat, az egydimenzis tmbkkel trtno megvalstsban azonban a tmb mrete korltozni
fogja a verem mrett. A verem LIFO adatszerkezet, azaz Last In Last Out: teht az utoljra berakott
elem kerl ki a verembol eloszr.
Szemlletesen a verem egy tnyleges veremknt, azaz gdrknt kpzelheto el, trgyakat tesznk
a verembe, egyms tetejre, s amikor ki akarunk venni egy elemet, mindig csak a legfelsot tudjuk
kivenni, teht azt, amit utoljra tettnk bele.
A vermet is globlis vltozn keresztl valstjuk meg, a megvalstshoz hasznlt tmbn kvl
egyetlen vltozra van csak szksgnk, amely a verem tetejnek indext, azaz az utoljra berakott
elem indext fogja tartalmazni. A vermet mindig a tmb vge fel bovtjk.
Ltrehozs.
const int N= 20;
int verem[20];
int teteje= -1;
int uresVerem()
{
return teteje == -1;
}
A verem csak akkor lehet res, ha nincs benne egyetlen elem sem, teht a tetejnek indexe -1.
Felso elem elrse. (TOP)
int top()
{
return verem[teteje];
}
F ONTOS
48
Kovcs Gyrgy
j elem hozzadsa. (PUSH) Az albbi push eljrs a paramterknt kapott x rtket fogja berakni
a verem tetejre, ha van mg hely a tmbben.
void push(int x)
{
if ( teteje != N - 1 )
{
++teteje;
verem[teteje]= x;
}
else
printf("A verem tele van!\n");
}
egyszeruen
11.1. Plda
A kvetkezo tblzatban nhny egyszeru muvelet
sorn vizsgljuk, hogyan vltozik a verem tartalma s a teteje vltoz, ha a verem egy 4 elemu tmbbel kerl reprezentlsra.
Muvelet
put(3)
get()
put(2)
put(3)
put(2)
put(3)
get()
get()
Verem tartalma
3___
____
2___
23__
232_
2323
232_
23__
teteje
0
-1
0
1
2
3
2
1
A kvetkezo egyszeru pldaprogramban a verem s a sor fo felhasznlst szemlltetem. A sort leggyakrabban egyfajta bufferknt hasznljk, azaz ha valamilyen berkezo adathalmazt a berkezs
sorrendjben kell feldolgozni, akkor tmenetileg egy sor adatszerkezetben lehet trolni o ket. Ha az
egyesvel rkezo adatokat a berkezs sorrendjvel ellenkezo sorrendben kell feldolgozni, akkor
viszont a verem adatszerkezetet alkalmazzk. Az albbi pldaprogramban a felhasznltl egsz
szmokat krnk a -1 rtkig, s minden egsz szm megadsa utn a beolvasott rtket berakjuk
egy verembe. A verem maximlis mrete 20 lesz. A beolvasst kvetoen kirtjk az adatszerkezetet
gy, hogy a megfelelo fggvnyeit hasznljuk az elemek elrsre s eltvoltsra.
11.1.1. forrskd: verem.c
#include <stdio.h>
const int N= 20;
int verem[20];
int teteje= -1;
int uresVerem()
{
return teteje == -1;
}
int topVerem()
{
return verem[teteje];
}
void push(int x)
{
if ( teteje != N - 1 )
{
++teteje;
verem[teteje]= x;
}
else
printf("A verem tele van!\n");
}
int pop()
{
if ( teteje != -1 )
--teteje;
return verem[teteje+1];
}
int main(int argc, char** argv)
{
int szam;
do
{
printf("kerek egy szamot:\n");
scanf("%d", &szam);
if ( szam == -1 )
break;
push(szam);
}while ( 1 );
printf("a verem elemei:\n");
while ( ! uresVerem() )
{
printf("%d ", topVerem());
pop();
}
return 0;
}
49
50
Kovcs Gyrgy
6 3 4 2
11.1. Feladat: Mi lesz a 3 elemu tmbbel reprezentlt verem tartalma s a teteje vltoz rtke az
albbi muveletek
vgrehajtsa utn?
push(3);
push(2);
push(2);
pop();
11.1. Megolds: A verem tartalma 3, 2 lesz, a teteje vltoz rtke pedig 1 lesz.
11.2. Feladat: Mi lesz a 4 elemu tmbbel reprezentlt verem tartalma s a teteje vltoz rtke az
albbi muveletek
vgrehajtsa utn?
int a= 2;
push(3*a);
push(a);
push(0);
a= pop();
push(pop());
push(a + pop());
11.2. Megolds: A harmadik push utasts utn a verem tartalma (6, 2, 0; teteje= 2). Ezt kvetoen
arra kell gyelnnk, hogy a paramterlistn szereplo kifejezs mindig, minden krlmnyek kztt
kirtkelodik a paramtertads elott, teht a paramterlistn lvo muvelet
hamarabb kerl vgrehajtsra, mint az a fggvny/eljrs, amelyiknek a paramterlistjn szerepel. Ennek megfeleloen a
a=pop(); utasts egyszeruen
eltvoltja a felso elemet (0), s berakja annak rtkt az a vltozba.
A kvetkezo, push(pop()); utasts kiveszi a felso elemet (2), majd vissza is rakja azt a verembe
a push muvelettel,
teht a verem lnyegben nem vltozik. Az utols utasts ismt kiveszi a felso
elemet (2), majd visszarakja annak s az a vltoznak az sszegt. Mivel az a rtke megint csak 0,
ebben a specilis esetben a verem ismt nem vltozik, azaz a verem tartalma (6, 2; teteje= 1).
12. Rekord
Definci szerint a rekord heterogn, statikus adatszerkezet. Heterogenitsa arra utal, hogy a legklnbzobb tpus adatokat tartalmazhatja, szemben a tmbbel, amely mindig csak egy bizonyos tpus
adatot tartalmazhatott. Statikussga a szoksos tulajdonsg: egy rekord mrete nem vltoztathat. A
rekordot a gyakorlatban szmtalan helyen alkalmazzuk, valahnyszor ssze szeretnnk fogni sszetartoz adatokat egy egysgg, egy vltozv. Egy rekord definilsa minden esetbe egy j, sajt
adattpus ltrehozst jelenti, teht valahnyszor rekordot hozunk ltre, azaz definilunk, mindig
ltrejn egy j tpus, amelyet mindenhol hasznlhatunk a programunkban, ahol eddig atomi tpus
szerepelt. Rekord defincijnak szintaktikja az albbi:
struct azonosito
{
tipus azonosito;
[tipus azonosito;]...
};
A struct alapsz utn szereplo azonost lesz az j, rekord tpus neve. A blokkban szereplo utastsok deklarcis utastsok, a blokkban szereplo azonostkkal ltrehozott vltozkat a rekord tpus
mezoinek nevezzk. A deklarcis utastsok sszevonhatak, azaz ha azonos tpus mezoket szeretnnk ltrehozni, akkor felsorolhatjuk a mezoneveket a megfelelo tpus egyszeri kirsa utn.
51
Nagyon fontos, hogy a ;-t ne hagyjuk le a struktra definci vgrol! Miutn definiltunk egy ilyen
struktrt, ami a C nyelv beptett rekord tpusa, tetszoleges helyen hasznlhatjuk a struct azonosito
kifejezst, ahol eddig atomi tpust hasznltunk. Miutn deklarltunk egy ilyen struktra tpus vltozt, az lnyegben egy vltozban fogja ssze a mezoit, mint egyfajta "alrendelt" vagy al-vltozkat,
s azokat a . minosto opertorral rhetjk el. Lssunk egy pldt arra, hogyan hozhatunk ltre egy
pont2D nevu struktrt, amely az Euklideszi sk egy egsz koordintj pontjt hivatott reprezentlni.
struct pont2D
{
int x;
int y;
}
Ezt kvetoen a kdunkban brhol ltrehozhatunk struct pont2D tpus vltozt, pldul az albbi
deklarcis utastssal:
struct pont2D p;
amelyben a p vltozt hoztuk ltre. A vltoznak adhatunk kezdortket, gy, ahogy tmbk esetn
is, azaz kapcsoszrjelben felsoroljuk a mezok rtkt, a mezok defincibeli sorrendjnek megfeleloen:
A fenti utasts hatsra a p vltoz x mezojnek rtke 1 lesz, mg a y mezo rtke 2. A . opertorral rhetjk el egy struct pont2D tpus vltoz mezoit, amelyet aztn gy hasznlhatunk, mint
brmely ms vltozt, teht kifejezsekben, tadhatjuk paramterknt, s rtkads bal oldaln is
llhat. Az albbi kdrszletben megvltoztatom a p vltoz x s y mezoit 0-ra, majd kirom a tartalmukat a konzolra, ezt kvetoen beolvasok kt egsz szmot a bemenetrol a scanf fggvnnyel,
egyenesen a p x s y mezoibe, majd kirom ismt a mezok tartalmt.
p.x= 0;
p.y= 0;
printf("%d %d\n", p.x, p.y);
scanf("%d %d", &(p.x), &(p.y));
printf("%d %d\n", p.x, p.y);
12.1. Feladat: Hozzon ltre rekord tpust, amely az Euklideszi-tr hrom dimenzis (lebegopontos
koordintkat is felveheto) pontjaink brzolsra hasznlhat!
12.1. Megolds:
struct pont3D
{
float x, y, z;
};
12.2. Feladat: Hozzon ltre rekord tpust, amely hallgatk informciit tartalmazhatja, 6 karakteres
sztringben a neptunkdjt s egsz tpus vltozban a szletsi vt!
12.2. Megolds:
52
Kovcs Gyrgy
struct hallgato
{
char neptunkod[7];
int szul_ev;
};
Ne felejtsk el, hogy 6 karakteres sztring trolshoz 7 elemu karaktertmbt kell ltrehoznunk, a
sztringet zr \0 karakter miatt.
12.3. Feladat: Hozzon ltre egy struct hallgato tpus vltozt s adjon neki tetszoleges kezdortket!
12.3. Megolds:
struct hallgato h= {"ABC123", 1985};
12.4. Feladat: rjon fggvnyt, amely paramterknt kapja egy hrom dimenzis objektum pontjait egy pont3D tpus elemeket tartalmaz tmbknt s visszatrsi rtkknt egy pont3D tpus
rtket ad vissza, amely az objektum slypontjt tartalmazza. (Egy ponthalmaz slypontjnak koordintit gy kaphatjuk meg, hogy a halmaz pontjainak koordintit koordintnknt tlagoljuk.)
12.4. Megolds:
struct pont3D sulypont(struct pont3D t[], int n)
{
int i;
struct pont3D sp= {0, 0, 0};
for ( i=
{
sp.x+=
sp.y+=
sp.z+=
}
0; i < n; ++i )
t[i].x;
t[i].y;
t[i].z;
sp.x/= n;
sp.y/= n;
sp.z/= n;
return sp;
}
53
12.5. Megolds:
int teljesKereses(struct hallgato t[], int n, char nk[])
{
int i;
for ( i= 0; i < n; ++i )
if ( strcmp(t[i].neptunkod, nk) == 0 )
return i;
return -1;
}
Hasonltsuk ssze a fenti kdot az egsz szmok tmbjben teljes keresst vgzo fggvnnyel. Jl
lthat, hogy maga az algoritmus ugyanaz, a klnbsg csak a paramterezsben (hiszen most struct hallgato
tpus adatok kztt keresnk), s a hasonltsban van, amelyhez mivel sztringekkel dolgozunk, a
strcmp fggvnyt kell hasznlnunk.
12.6. Feladat: rjon programot, amely ltrehoz egy 5 elemu,
struct hallgato tpus vltozkat
tartalmaz tmbt, feltlti azt a konzolrl a scanf fggvnnyel, majd neptun kdokat olvas be
egszen addig s kirja a megfelelo hallgat szletsi vt egszen addig, amg a felhasznl a "vege"
sztringet nem gpeli be neptun kd helyett!
12.6. Megolds:
12.1.1. forrskd: hallgatokereses.c
#include <stdio.h>
struct hallgato
{
char neptunkod[7];
int szul_ev;
};
int teljesKereses(struct hallgato t[], int n, char nk[])
{
int i;
for ( i= 0; i < n; ++i )
if ( strcmp(t[i].neptunkod, nk) == 0 )
return i;
return -1;
}
int main(int argc, char** argv)
{
struct hallgato h[5];
char tmp[7];
int i, j;
for ( i= 0; i < 5; ++i )
scanf("%s %d", h[i].neptunkod, &(h[i].szul_ev));
while ( 1 )
{
printf("kerek egy neptunkodot:\n");
scanf("%s", tmp);
if ( strcmp(tmp, "vege") == 0 )
break;
j= teljesKereses(h, 5, tmp);
if ( j == -1 )
printf("ismeretlen neptun-kod\n");
else
printf("%d\n", h[j].szul_ev);
54
Kovcs Gyrgy
}
return 0;
}
55
12.8. Feladat: Alaktsuk t most a kdot a paramtertadsokat globlis vltozkon keresztl egyszerustve!
12.8. Megolds:
12.1.3. forrskd: hallgatokereses3.c
#include <stdio.h>
struct hallgato
{
char neptunkod[7];
int szul_ev;
};
struct hallgato h[5];
char nk[7];
int n= 5;
int teljesKereses()
{
int i;
for ( i= 0; i < n; ++i )
if ( strcmp(h[i].neptunkod, nk) == 0 )
return i;
return -1;
}
void feltolt()
{
int i;
for ( i= 0; i < n; ++i )
scanf("%s %d", h[i].neptunkod, &(h[i].szul_ev));
}
void kiir()
{
int x;
x= teljesKereses();
if ( x == -1 )
printf("ismeretlen hallgato\n");
else
printf("%d\n", h[x].szul_ev);
}
int main(int argc, char** argv)
{
char tmp[5];
feltolt();
while ( 1 )
{
printf("kerek egy neptunkodot:\n");
scanf("%s", tmp);
if ( strcmp(tmp, "vege") == 0 )
break;
kiir();
}
return 0;
56
Kovcs Gyrgy
}
a beszdes
fggvny s eljrsnevekbol knnyen kitallhat rnzsre a program mukdse,
a fggvnyek s
eljrsok szintn egyszeruek,
sszehasonltva az egszeket rendezo kddal, knnyu ltni, hogy klnbsg csak a paramterezsben, a tmp segdvltoz tpusban s a hasonltsban van.
12.10. Feladat: rjon eljrst, amely egy struct hallgato tpus elemekbol ll tmbt neptunkd szerint rendez. A rendezs a minimum kivlasztsos nvekvo rendezs legyen!
12.10. Megolds: Mivel a neptun-kd mezo sztring tpus, a hasonltshoz a strcmp fggvnyt kell
hasznlnunk!
void rendezNK(struct hallgato t[], int n)
{
struct hallgato tmp;
int i, j, min;
for ( i= 0; i < n; ++i )
{
min= i;
for ( j= i+1; j < n; ++j )
if ( strcmp(t[j].neptunkod, t[min].neptunkod) < 0 )
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
57
Jl lthat, hogy a ez a megolds a szletsi v szerint rendezo kdtl egyedl a rendezsi felttelben tr el, ahol felhasznltuk azt, hogy a strcmp fggvny negatv rtket ad vissza, ha az elso
paramtere alfabetikus rendezs szerint kisebb, mint a msodik.
12.11. Feladat: Mdostsa a szletsi v szerint rendezo eljrst gy, hogy az azonos szletsi vhez
tartoz elemek neptun kd szerinti nvekvo sorrendbe legyenek rendezve!
12.11. Megolds: A megoldshoz egyedl a rendezsi felttelt kell bovtennk. rtelemszeruen
most
akkor lesz kisebb egy elem a msiknl, ha kisebb a szletsi ve, vagy megegyezik a szletsi v, de
kisebb a neptun kd rtke alfabetikusan:
void rendezSzulEvNK(struct hallgato t[], int n)
{
struct hallgato tmp;
int i, j, min;
for ( i= 0; i < n; ++i )
{
min= i;
for ( j= i+1; j < n; ++j )
if ( t[j].szul_ev < t[min].szul_ev || (t[j].szul_ev == t[min].szul_ev && strcmp(t[
j].neptunkod, t[min].neptunkod) == 0 ))
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
12.12. Feladat: rjon eljrst, amely paramterknt kap egy hallgatk adatait tartalmaz struct hallgato
tpus tmbt, valamint annak mrett, s kirja a tmb elemeit azok trolsi sorrendjben a konzolra!
12.12. Megolds:
void kiir(struct hallgato t[], int n)
{
int i;
for ( i= 0; i < n; ++i )
printf("%s %d\n", t[i].neptunkod, t[i].szul_ev);
}
12.13. Feladat: rjon programot, amely feltlt egy 5 elemu tmbt hallgatk adataival, majd rendezi a
tmbt elobb szletsi v, majd neptun-kd, majd szletsi v s neptun kd szerint, s kirja mindhrom rendezs utn a tmb tartalmt a konzolra!
12.13. Megolds:
12.2.4. forrskd: hallgatorendez.c
#include <stdio.h>
struct hallgato
{
char neptunkod[7];
int szul_ev;
};
void rendezSzulEv(struct hallgato t[], int n)
58
Kovcs Gyrgy
{
struct hallgato tmp;
int i, j, min;
for ( i= 0; i < n; ++i )
{
min= i;
for ( j= i+1; j < n; ++j )
if ( t[j].szul_ev < t[min].szul_ev )
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
void rendezNK(struct hallgato t[], int n)
{
struct hallgato tmp;
int i, j, min;
for ( i= 0; i < n; ++i )
{
min= i;
for ( j= i+1; j < n; ++j )
if ( strcmp(t[j].neptunkod, t[min].neptunkod) < 0 )
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
void rendezSzulEvNK(struct hallgato t[], int n)
{
struct hallgato tmp;
int i, j, min;
for ( i= 0; i < n; ++i )
{
min= i;
for ( j= i+1; j < n; ++j )
if ( t[j].szul_ev < t[min].szul_ev || (t[j].szul_ev == t[min].szul_ev && strcmp(t[
j].neptunkod, t[min].neptunkod) == 0 ))
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}
void kiir(struct hallgato t[], int n)
{
int i;
for ( i= 0; i < n; ++i )
printf("%s %d\n", t[i].neptunkod, t[i].szul_ev);
}
int main(int argc, char** argv)
{
struct hallgato t[5];
int i;
for ( i= 0; i < 5; ++i )
{
59
60
Kovcs Gyrgy
12.15. Feladat: rja t a hrom soros reprezentcit felpto fggvnyt s az hrom soros reprezentci
egy elemt elro fggvnyt gy, hogy azok struct sor3 tpus tmbket vrjanak paramterknt!
12.15. Megolds:
int felepit3sor(int t[], int sorok, int oszlopok, int gyakoriElem, int sor3[])
{
int i, j, k= 0;
for ( i= 0; i < sorok; ++i )
for ( j= 0; j < oszlopok; ++j )
if ( t[i*oszlopok + j] != gyakoriElem )
{
sor3[k].sor= i;
sor3[k].oszlop= j;
sor3[k].ertek= t[i*oszlopok + j];
++k;
}
return k;
}
int elem(int sor3[], int meret, int gyakoriElem, int s, int o)
{
int i;
for ( i= 0; i < meret; ++i )
if ( sor3[i].sor == s && sor3[i].oszlop == o )
return sor3[i].ertek;
return gyakoriElem;
}
12.4. Sor
A sor adatszerkezet megvalstsa sem a leheto legelegnsabb, ugyanis globlis vltozkat hasznlunk,
gy fggvnyeink csak egyetlen sor kezelsre kpesek a programban.
12.16. Feladat: Hozzunk ltre egy sajt adattpust, amely alkalmas arra, hogy egy 10 elemu tmbben
trolt sort reprezentljon (legyen benne egy 10 elemu tmb, valamint egy vege mezo), majd alaktsuk t a rgztett sort kezelo fggvnyeket s eljrsokat gy, hogy a sort, amelyen dolgozniuk kell,
mindig megkapjk paramterknt!
12.16. Megolds: A sort reprezentl struktra:
struct sor
{
int t[10];
int vege;
};
61
A fenti fggvnyekben a get eljrs abban klnbzik, a korbban haszlttl, hogy nem adja vissza visszatrsi rtkknt a sor elso elemt, ezzel szemben magt a sor reprezentl adatszerkezetet
adja vissza. Ennek a megkzeltsnek azaz oka, hogy valahnyszor megvltozik a sor (put s get
muveletek),
az rtk szerinti paramtertadssal tvett, sort reprezentl struktrt vissza kell juttatni a hvsi krnyezetbe s rtkl kell adni annak a paramternek, amellyet a paramterlistjn
tadtunk neki, ahhoz hogy a mdosts ott is rvnybe lpjen. A paramterknt tvett sor ebben az
esetben NEM az az objektum, amelyre meghvtuk, hanem annak msolata!
12.17. Feladat: rjon programot, amely a fenti fggvnyek felhasznlsval kt sort kezel: a-t s b-t.
A felhasznl parancsokat ad meg, s a program elvgzi a megfelelo soron a megfelelo muveletet!
A
lehetsges parancsok a put s a get, a parancsot minden esetben egy karakter kveti, a az a sorra
utal, b a b sorra, put esetn tovbbi paramter a szm, amelyet be szeretnnk szrni. Pldul a
62
Kovcs Gyrgy
put a 2 parancs hatrsa bekerl az a sorba a 2 rtk. A get b parancs eltvoltja a b sor legelso
elemt. Amikor a felhasznl a "vege" sztringet gpeli be, a program kirja a sorok tartalmt s befejezi
futst.
12.17. Megolds:
12.4.5. forrskd: sorvezerlovel.c
#include <stdio.h>
struct sor
{
int t[10];
int vege;
};
struct sor ujSor()
{
struct sor t;
t.vege= -1;
return t;
}
int uresSor(struct sor s)
{
return s.vege == -1;
}
struct sor put(struct sor s, int x)
{
if ( s.vege == 9 )
printf("a sor tele van\n");
else
{
++s.vege;
s.t[s.vege]= x;
}
return s;
}
int top(struct sor s)
{
return s.t[0];
}
struct sor get(struct sor s)
{
if ( uresSor(s) )
A
zres\n");
printf("a sor
else
--s.vege;
return s;
}
void kiir(struct sor s)
{
int i;
for ( i= 0; i <= s.vege; ++i )
printf("%d ", s.t[i]);
printf("\n");
}
int main(int argc, char** argv)
{
struct sor a, b;
63
char tmp[5];
char c;
int x, par;
a= ujSor();
b= ujSor();
while ( 1 )
{
par= scanf("%s %c %d", tmp, &c, &par);
if ( strcmp(tmp, "vege") == 0 )
break;
if ( strcmp(tmp, "put") == 0 )
{
if ( c == a )
a= put(a, x);
else if ( c == b )
b= put(b, x);
else
printf("ismeretlen sor azonosito\n");
}
else if ( strcmp(tmp, "get") == 0 )
{
if ( c == a )
a= get(a);
else if ( c == b )
b= get(b);
else
printf("ismeretlen sor azonosito\n");
}
else
printf("ismeretlen utasitas\n");
}
printf("az a sor tartalma:\n");
kiir(a);
printf("a b sor tartalma:\n");
kiir(b);
return 0;
}
64
Kovcs Gyrgy
F ONTOS
ahol a * jelzi azt, hogy az azonost nem egy tipus tpus rtket, hanem egy olyan memriacmet
tartalmaz, amelyen egy tipus brzols rtk tallhat. Pldk mutatk ltrehozsra:
char* character_mutato;
float* float_mutato;
struct hallgato* hallgato_mutato;
Jegyezzk meg, hogy mivel a mutatk minden esetben egy memriacmet tartalmaznak, azok mrete
minden esetben a gpi sz hossz, azaz pldul 32 bites architektrn a fenti hrom mutat mrete
egyarnt 4-4 bjt. 64 bites architektrn a fenti mutatk mrete 8-8 bjt. Mutatk hasznlathoz kt
krdst kell mg tisztznunk:
Milyen rtkeket adhatunk mutatknak?
Hogyan kezelhetjk a mutatk ltal cmzett adatokat?
Az elso krds kapcsn jegyezzk meg, hogy egy mutatnak sohasem adhatunk explicit mdon
rtket, azaz sohasem tehetjk meg azt, hogy character_mutato= 2342. Ennek az az oka, hogy a
programok rsakor nincs rla tudomsunk, hogy a program a memrinak pontosan melyik rszn
fog elhelyezkedni, ezrt explicit mdon nem dolgozhatunk cmekkel! Egyetlen specilis rtk van,
amelyet egy mutathoz hozzrendelhetnk, ez pedig a NULL mutat, ami azt jelenti, hogy a mutat sehov sem mutat. Mutatk ltrehozsakor, azaz deklarlsakor azok rtke hatrozatlan, ezrt
a memria egy vletlenszeru rszt cmzik, amelyet nem hasznlhatunk, hiszen ha egy memria
terletet hasznlni szeretnnk, azt jeleznnk kell elobb az opercis rendszernek. A mutat vltozkat rdemes teht a NULL rtkkel inicializlni, jelezve azt, hogy sehov sem mutatnak. Ha explicit mdon nem adhatunk rtket a mutatknak, akkor hogyan tehetjk meg? Jegyezzk meg, hogy
az opercis rendszer minden vltoz szmra fenntart egy memriaterletet, ezrt pldul ha egy
vltoz cmkomponenst, azaz cmt le tudnnk krdezni, akkor ezt a cmet mr rtkl adhatnnk
65
egy megfelelo mutat tpus vltoznak. Egy cmkomponenssel rendelkezo programozsi eszkz
cmt az & (cme) opertorral krdezhetjk le. Egy mutat ltal cmzett objektumot a mutat el rt
* (indirekcis) opertorral rhetnk el. Az indirekcis opertort hasznlva pldul egy int* p;
mutatn, a *p kifejezs a kd brmely pontjn egy int tpus rtket jelent, amelynek a cme ppen
a p-ben trolt cm.
int a= 5;
int *p;
p= &a;
*p= 2;
printf("%d", a);
A fenti kdrszlet hatsra a kpernyon az elvrt 5-s rtkkel szemben a 2 rtk fog megjelenni.
Ennek az az oka, hogy a p mutat vltozba beletettk az a vltoz cmt, gy a *p=2 rtkads ppen a p-ben tallhat cmen lvo adat rtkt fogja 2-re lltani. A p-ben lvo cmen azonban ppen
az a vltoz tallhat, hiszen az a cmkomponenst tettk bele a p-be, gy az rtkads az a vltozt
rja t 2-re. Ezek alapjn mutatknak rtkl adhatjuk cmkomponenssel rendelkezo vltozk cmt.
Ez azonban mg mindig nem oldja meg azt a problmt, hogy hogyan tudunk futs kzben, vltoz mretu memriaterleteket lefoglalni. Erre ad megoldst egy beptett, a stdlib.h header-ben
tallhat standard knyvtri fggvny, a malloc. A malloc fggvny specifikcija a kvetkezo:
void* malloc(int n);
Elemezzk a fenti kifejezst, bentrol kifel haladva: a sizeof opertor azt adja vissza, hogy az
operandusaknt kapott tpus hny bjton brzolhat. Ezt megszorozva 10-zel ppen 10 darab egsz
szm brzolshoz szksges bjtok szmt kapjuk. A malloc teht lefoglalja ezt kvetoen a 10
darab egsz brzolshoz szksges memriaterletet, majd visszaadja annak cmt void* tpusknt.
Ez teljes rtku cm, de nincs hozz tpus rendelve, azaz a specilis res (void) tpus van hozzrendelve. Mielott ezt rtkl adnnk a p mutatnak, explicit konverzival int* tpusv konvertljuk.
A p mutat ezt kvetoen egy olyan memriaterletre mutat, amely 10 darab egsz szm trolsra
alkalmas. Jegyezzk meg a fenti konstrukcit, amely a malloc fggvny hasznlatnak ltalnos
mdjt demonstrlja. Megjegyezzk, hogy a 10 szm helyett tetszoleges vltoz is hasznlhat. Egy
krds maradt mr csak: ha lefoglaltunk 10 egsz trolsra alkalmas memriaterletet, s tudjuk
annak cmt, hogyan rhetjk el az i-edik (0 i 9) egsz brzolsra alkalmas memriaterletet.
A vlasz a mutataritmetika. Mutatkhoz hozzadhatunk konstans rtkeket, ha a mutat tpusa
tipus, akkor a konstans i rtket hozzadva a p cm nem i-vel fog noni, teht nem i bjttal fog jobbra
mutatni, hanem i sizeof (tipus) bjttal, ami azt jelenti, hogy ha a mutathoz hozzadunk i-t, akkor
ppen az i-edik adat trolsra alkalmas terlet cmt kaphatjuk meg a lefoglalt memriaterleten
bell.
int *p;
p= (int*)malloc(sizeof(int)*10);
*(p+1)= 2;
printf("%d", *(p+1));
A fenti kd teht lefoglal egy 10 egsz trolsra alkalmas memriaterletet, majd a msodik helyre
berakja a 2 rtket, s ezt kvetoen ki is rja azt. Figyeljk meg, hogy a mutatk konstanssal trtno
66
Kovcs Gyrgy
nvelse utn ismt az indirekcis * opertort hasznltuk, hiszen azt tetszoleges cm elott hasznlhatjuk, hogy az ltala cmzett terletet elrjk.
Ha most sszehasonltjuk a p mutatnak trtno rtkads utn ltrejtt szerkezetet a memriban,
azt vehetjk szre, hogy az ppen megfelel az egy dimenzis tmbk szerkezetnek (lsd a tmbkrol szl fejezetet). Ezek alapjn aztn knnyu ltni, hogy a mutatk s a tmbk lnyegben
azonos szerkezetek a memriban. Ennek megfeleloen a C nyelv lehetosget is biztost arra, hogy
a mutatkat tmbknt kezeljk, azaz a fenti *(p+1) kifejezs mindkt helyen ekvivalens mdon
hasznlhat a p[1] kifejezssel. sszegezve mindezt teht, egy mutat amely egy n adat trolsra
alkalmas lefoglalt memriaterletre mutat, tekintheto egy n mretu tmbnek, s az *(p+i) kifejezs
ekvivalens a p[i] kifejezssel.
A dinamikusan (malloc fggvny hasznlatval lefoglalat) memriaterleteket azonban miutn
nincs r szksgnk, minden esetben fel kell szabadtanunk. A felszabadtsra a free fggvny
hasznlhat. A free fggvny egyetlen paramtere az a mutat, mely ltal cmzett memriaterletet
fel szeretnnk szabadtani, azaz visszaadni az opercis rendszernek tetszoleges hasznlatra. Az
elozo kdrszletben lefoglalt memriaterletet teht az albbi fggvnyhvssal szabadthatjuk fel:
free(p);
A krds, hogy a hp mutatbl hogyan rhetjk el az ltala cmzett struktra mezoit. A legkzenfekvobb megolds termszetesen a * opertor hasznlata. Mivel a *hp kifejezs minden esetben a h
objektumot jelenti, hasznlhatjuk a . minosto opertort, azaz a h vltoz mezoinek rtket adhatunk
az albbi utastsokkal:
(*hp).szul_ev= 1990;
strcpy((*hp).neptun_kod, "AAABBB");
printf("neptun kd: %s szletsi v: %d\n", (*hp).neptun_kod, (*hp).szul_ev);
A fenti kd jl szemllteti, hogy *hp minden esetben a hp mutat ltal cmzett objektumot jelenti,
gy ha az struktra, hasznlahatjuk akr a . minosto opertort is mezoinek elrsre. A C nyelv
lehetosget biztost a (*hp).szul_ev jellegu szerkezetek egyszerustsre
a -> opertor hasznlatval. A (*hp).szul_ev kifejezs teljesen ekvivalens a hp->szul_ev kifejezssel. Fontos azonban
megjegyeznnk, hogy a -> opertor csak s kizrlag akkor hasznlhat, ha a bal oldaln egy olyan
mutat ll, amely valamilyen struktrt cmez. A fenti kdrszlet teht ekvivalens az albbival:
hp->szul_ev= 1990;
strcpy(hp->neptun_kod, "AAABBB");
67
13.1. Megolds:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n;
int *p;
int i;
scanf("%d", &n);
p= (int*)malloc(sizeof(int)*n);
for ( i= 0; i < n; ++i )
scanf("%d", &(p[i]));
for ( i= n-1; i >= 0; --i )
printf("%d", p[i]);
free(p);
return 0;
}
Mivel a tmbk tekinthetok vltozk sorozatnak, a scanf fggvny paramterlistjn btran alkalmazhatjuk az & opertort a p[i], mint vltoz elott. Ekvivalens mdon, a scanf paramterlistjn
szerepelhetne a &(*(p+i)) kifejezs is. Vegyk szre, hogy az & s a * opertor egyms ellenttei,
teht kzvetlenl egyms utn alkalmazva o ket kioltjk egyms hatst, gy a scanf paramterlistjn
a korbbiakkal szintn ekvivalens mdon hasznlhatjuk a p+i kifejezst is, hiszen az szintn annak
a memriaterletnek a cmt adja, amelyre az i-edik egsz rtket be kell olvasni.
13.2. Feladat: rjon programot, amely beolvas egy n szmot, majd beolvas n darab lebegopontos
szmot, s ezt kvetoen kirja a szmok medinjt!
14. Egy irnyba lncolt lista
Az egy irnyba lncolt lista a legegyszerubb
dinamikus adatszerkezet, amellyel foglalkozunk. Visszatrve az elozo szakasz vgn lvo feladat megoldsra, vegyk szre, hogy br a tmbt dinamikusan hoztuk ltre, miutn az ltrejtt, annak mrete rgztett vlt, hiszen a tmb statikus adatszerkezet, gy legfeljebb annyi elemet tudunk trolni benne, amekkora terletet lefoglaltunk. A tmb
teht br dinamikusan hoztuk ltre, tovbbra is statikus adatszerkezet. Clunk azonban olyan adatszerkezet ltrehozsa, amelyben tetszoleges szm elemet trolhatunk, dinamikusan hozzadhatunk
elemeket nvelve az adatszerkezet mrett, s dinamikusan eltvoltva elemeket, cskkentve ezzel az
adatszerkezet mrett. Vegyk szre azonban, hogy dinamikus adatszerkezeteket nem trolhatunk
egy folytonos memriaterleten, hiszen a lefoglalt folytonos memriaterlet mrett nem tudjuk
hatkonyan nvelni vagy cskkenteni. Mindez azt jelenti, hogy a dinamikus adatszerkezet elemei
kln-kln, nllan helyezkednek el a memriban. Szksg van azonban arra, hogy egy elembol kiindulva be tudjuk jrni az adatszerkezetet, vgig tudjunk menni rajta, azaz az elemek kztt
legyen valamilyen kapcsolat. Erre kivl eszkzt nyjt a mutatk hasznlata. A legegyszerubb
esetben, azaz egyirnyba lncolt listnl minden egyes adatelemhez, amelyet a listban trolunk, hozzrendelnk egy mutatt, amely a valamilyen rtelemben vett "kvetkezo" elemre mutat. Mivel egy
mutatbl az elozo szakaszban trgyaltak alapjn el tudjuk rni a mutat ltal cmzett adatot, a mutatk hasznlatval az adatszerkezetetben troland elemeket lnyegben sszefuzzk,
s az elso,
kitntetett, ltalban fejnek nevezett elembol kiindulva az adatszerkezet bejrhat, azaz minden eleme elrheto. A lista vgt az utols elem NULL mutat rtke jelzi, hiszen az nem mutat tovbbi
elemre.
Mivel minden elemhez hozzrendelnk egy mutatt, sszetett, sajt tpust kell hasznlnunk. Az
albbiakban olyan listt hozunk ltre, amely egsz szmok trolsra lesz alkalmas. A sajt tpus,
68
Kovcs Gyrgy
rtelemszeruen
a struct lista tpus adat mezojben troljuk azt az adatrszt, amelyet dinamikus
adatszerkezetben szeretnnk kezelni, mg a kov mezo a kvetkezo ilyen tpus objektumra mutathat.
res lista ltrehozsa A tovbbi kdjainkban egy lncolt listt egyetlen vltoz reprezentl, mgpedig az elso elem mutatja, hiszen ezen mutatbl kiindulva a lista minden elemt elrhetjk. Az
albbi pldban teht kt klnbzo lncolt listt hozunk ltre, a s b nven:
struct lista* a= NULL;
struct lista* b= NULL;
A vltoz NULL rtkkel trtno inicializlsa lnyegben res lista ltrehozst jelenti. A tovbbiakban az egyirnyba lncolt listkat kezelo leggyakoribb fggvnyeket vesszk vgig.
14.1. Fggvnyekkel
Beszrs Adatszerkezetek esetn a legalapvetobb muvelet
Az ujelem fggvny felhasznlsval a lncolt lista elejre tttno beszrst megvalst fggvny
az albbi:
struct lista* elejere_beszur(int x, struct lista* fej)
{
struct lista* tmp;
tmp= ujelem(x);
tmp->kov= fej;
return tmp;
}
A lista vgre trtno beszrs sorn kt esetet klnbztethetnk meg. Az elso esetben, ha a lista
res lista, megvltozik a fej rtke, a msodik esetben nem. Ezen kt esetet meg kell klnbztetnnk:
69
gyeljnk arra, hogy a fej vltozt vissza kell adnunk, ezrt a lista vgre trtno pozcionlst
egy tmp segdvltoz segtsgvel oldjuk meg. A lista vge fel a tmp= tmp->kov iterlt alkalmazsval pozcionlhatunk, a lista utols elemt akkor rjk el, amikor a while ciklus felttele
igazz vlik, hiszen az utols elemre igaz csak, hogy a rkvetkezoje NULL.
A fenti kdot termszetesen while ciklus helyett for ciklussal is megvalsthatjuk:
struct lista* vegere_beszur(int x, struct lista* fej)
{
struct lista* tmp;
if ( fej == NULL )
return ujelem(x);
for ( tmp= fej; tmp->kov != NULL; tmp= tmp->kov );
tmp->kov= ujelem(x);
return fej;
}
A lista vgrol trtno trls sorn hrom esetet kell megklnbztetnnk: elso eset, amikor res
listbl trlnk, msodik eset, amikor egy elemet tartalmaz listbl s harmadik eset, amikor tbb,
mint egy elemet tartalmaz listbl trlnk.
70
Kovcs Gyrgy
struct lista* vegerol_torol(struct lisat* fej)
{
struct lista* tmp;
if ( fej == NULL )
return NULL;
if ( fej->kov == NULL )
{
free(fej);
return NULL;
}
tmp= fej;
while ( tmp->kov->kov != NULL )
tmp= tmp->kov;
free(tmp->kov);
tmp->kov= NULL;
return fej;
}
azt jelenti, hogy valamilyen mdon vgig szeretnnk menni az adatszerkezeten, s minden elemet elrni, feldolgozni. A feldolgozs jelentheti a legegyszerubb
esetben az
elem kirst a konzolra. Ezt egy nagyon egyszeru struktrj fggvnnyel valsthatjuk meg:
void bejar(struct lista* fej)
{
while ( fej )
{
printf("%d ", fej->adat);
fej= fej->kov;
}
}
A bejrs sorn a kirs, teht a printf fggvny helyett tetszoleges feldolgozsi lps szerepelhet.
Keress A keress sorn, hasonlan a tmbkben trtno keresshez, a keresett rtket (adatot)
tartalmaz listaelem cmt adjuk vissza, ha megtalljuk (hasonlan a tmbkben trtno keresshez,
ahol az indexet adtuk vissza), s NULL mutatt adunk vissza, ha nincs benne a keresett elem a listban.
A fggvny nagyon hasonl a bejrshoz, a feldolgozs itt egy egyszeru felttel ellenorzse:
struct lista* keres(int x, struct lista* fej)
{
while ( fej )
{
if ( fej->adat == x )
return fej;
}
return NULL;
}
71
tmp->adat= mire;
return fej;
}
Adott elem utn trtno beszrs A fggvnyben felhasznljuk a mr ltezo keres fggvnynket:
struct lista* elem_utan_beszur(int x, int ez_utan, struct lista* fej)
{
struct lista* tmp= keres(ez_utan, fej);
struct lista* tmp2;
if ( tmp == NULL )
return vegere_beszur(x, fej);
tmp2= ujelem(x);
tmp2->kov= tmp->kov;
tmp->kov= tmp2->kov;
return fej;
}
Adott elem trlse Mivel a lista kzepn tallhat elem trlse sorn az elemet megelozo elemnek
a kov mezojt kell mdostani, meg kell tallnunk az adott adat rtket megelozo listaelemet.
struct lista* adott_elem_torlese(int mit, struct lista* fej)
{
struct lista* tmp= fej;
struct lista* elozo= NULL;
while ( tmp && tmp->adat != mit )
{
elozo= tmp;
tmp= tmp->kov;
}
if ( tmp == NULL )
return fej;
if ( elozo == NULL )
fej= fej->kov;
else
elozo->kov= tmp->kov;
free(tmp);
return fej;
}
72
Kovcs Gyrgy
while ( fej )
{
tmp= fej->kov;
free(fej);
fej= tmp;
}
return NULL;
}
Plda Az eddig megrt fggvnyek mind arra ptenek, hogy a hvsuk utn a nekik tadott paramter
rtkl kapja a visszatrsi rtkket, azaz a fggvnyek hvsa az albbi sablon alapjn trtnik:
fej= fuggveny(fej);
Ezek alapjn ha a fggvnyeket egy forrskd elejre rjuk, az albbi foprogram lefordthat s mukdik:
elejere_beszur(2, a);
vegere_beszur(3, a);
vegere_beszur(3, b);
vegere_beszur(4, b);
elejerol_torol(a);
elem_utan_beszur(5, 4, b);
csere(3, 6, a);
bejar(a);
printf("\n");
bejar(b);
felszabadit(a);
felszabadit(b);
}
14.2. Eljrsokkal
A fggvnyek helyett eljrsok segtsgvel is megrhatjuk az egyes listakezelo muveleteket,
azonban ekkor, mivel a hvsi krnyezetben lvo fej vltoz megvltozik, nem elegendo a fej rtkt
tadni paramterknt, hiszen ekkor nem tudjuk megvltoztatni a hvsi krnyezetben a vltozt.
Megolsknt annak cmt kell tadnunk, a cm tadsa azonban ktszeres indirekcival trtnik,
azaz mutatra mutat mutatt kell tadnunk paramterknt, aminek kezelse kicsit krlmnyesebb,
azonban az eredmny mindenkppen elegnsabb s hatkonyabb is. Az albbiakban a lista elejre
trtno beszrst s a lista elejrol trtno trlst valstjuk meg eljrsok segtsgvel. A megoldsok sorn az algoritmus nem vltozik, csak a fej vltoz kezelse. A tovbbi algoritmusok trsa
analg mdon trtnhet.
73
Lista elejrol
trls
void elejerol_torol(struct lista** fejp)
{
struct lista* tmp;
if ( *fejp == NULL )
return;
tmp= (*fejp)->kov;
free(*fejp);
*fejp= tmp;
}
Knnyu ltni, hogy a fenti kdokban mindkt esetben csak a fej vltozt cserltk *fejp vltozra, hogy ugyanaz az informci jelenjen meg az adott helyen, ami a fggvnyekkel trtno megvalstsban, valamint a return utastsokat kell rtelemszeruen
mdostani, ugyanis a fggvnyek
hasznlatakor a return utasts utni visszatrsi rtk bekerl a hvsi krnyezet fej vltozjba a
fej= fuggveny(fej) jellegu hasznlat miatt. Namost ha nincs visszatrsi rtknk, akkor a fggvnyeknl megjeleno visszatrsi rtket egy egyszeru *fejp= visszateresi_ertek utastssal is elhelyezhetjk a hvsi krnyezet fej vltozjban, hiszen a fejp vltoz ppen annak cmt
tartalmazza. res lista ltrehozsa utn az eljrsokat az albbi mdon hasznlhatjuk:
struct lista* a= NULL;
elejere_beszur(3, &a);
elejere_beszur(4, &a);
elejerol_torol(&a);
74
Kovcs Gyrgy
return;
printf("%d ", fej->adat);
bejar_elejerol(fej->kov);
}
Lista vgrol
trtno trls
struct lista* vegerol_torol(struct lista* fej)
{
if ( fej == NULL )
return NULL
if ( fej->kov == NULL )
{
free(fej);
return NULL;
}
fej->kov= vegerol_torol(fej->kov);
return fej;
}
14.4. typedef
Egyes megvalstsokban kihasznljk a C nyelv azon lehetosgt, mellyel elnevezhetjk a struct lista
tpust egy rvidebb nvvel, a kvetkezo mdon, a typedef utasts felhasznlsval:
typedef struct lista
{
int adat;
struct lista* kov;
} LISTA;
Ezt kvetoen a LISTA tpust brhol hasznlhatjuk, ahol a struct lista tpust a korbbiakban,
teht ez csak egy rvidts, semmit sem vltoztat az algoritmusok mukdsn.
75
76
Kovcs Gyrgy
tmp->adat= x;
tmp->elozo= tmp->kovetkezo= NULL;
return tmp;
}
77
return a;
if ( a.veg == a.fej )
{
free(a.veg);
a.veg= a.fej= NULL;
return a;
}
a.veg= a.veg->elozo;
free(a.veg->kovetkezo;
a.veg->kovetkezo= NULL;
return a;
}
Bejrs A bejrs esetnkben trtnhet kt irnybl, az lista fejtol a vge fel s a vge felol a fej
fel haladva is.
void bejar_elejerol(struct klista a)
{
while ( a.fej )
{
printf("%d ", a.fej->adat);
a.fej= a.fej->kovetkezo;
}
}
gy, hogy az a formlis paramtert rtk szerinti paramtertadssal vettk t, felhasznlhatjuk annak
mezoit hiszen az rtkk megvltozsa nincs hatssal a hvsi krnyezetben lvo, a ktirny listt
reprezentl struct klista tpus vltozra. Termszetesen segdvltoz segtsgvel is megvalsthatjuk a bejrsokat.
void bejar_elejerol(struct klista a)
{
struct klistaelem* tmp= a.fej;
while ( tmp )
{
printf("%d ", tmp->adat);
tmp= tmp->kovetkezo;
}
}
78
Kovcs Gyrgy
a.fej= a.fej->kovetkezo;
}
return NULL;
}
Csere A keress fggvny segtsgvel aztn nagyon knnyen megrhatjuk a csere muveletet:
Beszrs adott elem utn Adott elem utn trtno beszrshoz szintn felhasznljuk az eddigi
fggvnyeinket:
struct klista beszur_elem_utan(int x, int ez_utan, struct klista a)
{
struct klistaelem* tmp= keres(ez_utan, a);
struct klistaelem* uj;
if ( tmp == NULL )
return a;
if ( tmp == a.veg )
return vegere_beszur(x, a);
uj= ujelem(x);
uj->elozo= tmp;
uj->kovetkezo= tmp->kovetkezo;
uj->kovetkezo->elozo= uj;
tmp->kovetkezo= uj;
return a;
}
Felszabadts A listt trlni megintcsak az egyirnyba lncolt listnl is alkalmazott stratgia szerint tudunk:
79
15.2. Eljrsok
Hasonlan az egyirnyba lncolt listk esethez, a ktirnyba lncolt listkat kezelo fggvnyek
helyett is rhatunk eljrsokat, ekkor azonban a struct klista vltoz cmt kell tvennnk paramterknt.
A lista elejre trtno beszrs esetn ez az albbi mdon alakul:
void elejere_beszur(int x, struct klista* a)
{
if ( a->fej == NULL )
a->fej= a->veg= ujelem(x);
else
{
a->fej->elozo= ujelem(x);
a->fej= a->fej->elozo;
}
}
Maga az algoritmus, teht az egymst kveto lpsek ebben az esetben sem vltoztak, arra azonban gyelnnk kell, hogy egyrszt most mutat paramtert kaptunk, gy rtelemszeruen
a mezoi
elrshez a -> opertort kell hasznlnunk, msrszt most a hvsi krnyezetben lvo vltozt kezeljk
kzvetlenl, gy nincs szksg visszatrsi rtkre, s ha szksges, segdvltozkat kell bevezetnnk.
16. ltalnos binris fa
A binris fk az egyirnyba lncolt lista ltalnostsai abban az rtelemben, hogy egy helyett ketto
rkvetkezoje van minden faelemnek. Ezeket a rkvetkezoket bal- s jobboldali rkvetkezoknek
hvjuk. Egy egszeket tartalmaz binris ft megvalst struktra az albbi:
struct faelem
{
int adat;
struct faelem* bal;
struct faelem* jobb;
};
80
Kovcs Gyrgy
A NULL mutat specifiklsval egy res ft hoztunk ltre. Ahhoz, hogy a fba elemeket tudjunk
beszrni, elsoknt megrjuk a szoksos ujelem fggvnyt, amely ltrehoz egy megfelelo struktrt
s inicializlja annak mezoit:
struct faelem* ujelem(int x)
{
struct faelem* tmp;
tmp= (struct faelem*)malloc(sizeof(struct faelem));
tmp->adat= x;
tmp->bal= tmp->jobb= NULL;
return tmp;
}
Az ltalnos binris fa felptst azonban nem vgezhetjk olyan ltalnosan, mint tettk azt a lncolt listk esetn, azaz nem tudunk olyan fggvnyt/eljrst rni, amely egy adott helyen bovti a ft,
a fnak ugyanis nem egy, vagy kt vge van, hanem ahogy no a fa, gy no azoknak a helyeknek a
szma, amelyet a fa "vgnek" nevezhetnnk. A fa bovtse ezrt csak akkor oldhat meg automatikusan, ha a bovts sorn bevezetnk valamilyen szablyt, amely szably aztn pontosan meghatrozza,
hogy egy adott elemet hov kell beszrni a fban. A kvetkezo szakaszban, a binris keresofk esetn
lthatunk pldt egy ilyen szablyra. Az albbiakban egy nhny elembol ll ft explicit mdon, az
ujelem fggvny segtsgvel ptnk fel. Az albbi kdrszletben az 1. brn lthat binris ft
ptjk fel.
81
Ami kzs a legklnbzobb binris fkban, az a lehetsges rekurzv bejrsok mdja. Rekurzv bejrsokkal mr tallkoztunk egyirnyba lncolt listknl, ahol megoldst talltunk arra, hogy megfelelo
rekurzival a lista elejrol a vge fel, s a lista vgrol az eleje fel haladva is ki tudjuk rni a lista
elemeit. Ami klnbsg volt a kt mdszer kztt, az az, hogy hov helyeztk el a feldolgozst s a
rekurzv hvst a kdban, egymshoz viszonytva. Mivel a binris fk esetn minden faelemnek egy
bal s egy jobb oldali leszrmazottja van, hasonl meggondolsbl hrom klnbzo mdon tudjuk
bejrni a binris ft rekurzvan:
preorder mdon: egy elem feldolgozst a leszrmazottai feldolgozsa elott vgezzk;
inorder mdon: egy elem feldolgozst a bal oldali leszrmazottjnak feldolgozsa utn, de a
jobb oldali leszrmazottjnak feldolgozsa elott vgezzk;
postorder mdon: egy elem feldolgozst a leszrmazottai feldolgozsa utn vgezzk.
Ezek alapjn az albbi eljrsokat rhatjuk meg arra az esetre, ha a binris fa feldolgozsa az elemeinek a kirst jelenti:
void preorder(struct faelem* gyoker)
{
if ( gyoker == NULL )
return;
printf("%d ", gyoker->adat);
preorder(gyoker->bal);
preorder(gyoker->jobb);
}
void inorder(struct faelem* gyoker)
{
if ( gyoker == NULL )
return;
inorder(gyoker->bal);
printf("%d ", gyoker->adat);
inorder(gyoker->jobb);
}
void postorder(struct faelem* gyoker)
{
if ( gyoker == NULL )
return;
postorder(gyoker->bal);
postorder(gyoker->jobb);
printf("%d ", gyoker->adat);
}
A hrom eljrs smja hasonl, rekurzvan hvja mindhrom eljrs sajt magt, a rekurzv hvst
az szaktja meg, ha a paramterknt kapott faelem, azaz a feldolgozand rszfa gykreleme NULL.
A pldban megadott binris fa bejrsakor a hrom klnbzo bejrssal hrom klnbzo sorrendet kapunk:
preorder: 5 2 1 6 3 0 1;
inorder: 1 2 6 3 5 0 1;
postorder: 1 3 6 2 1 0 5.
82
Kovcs Gyrgy
a levlelemek trlse,
mivel nincsenek leszrmazottjaik, egyszeruen
csak fel kell szabadtani o ket s a szlo elemk megfelelo
mutatjt NULL rtkre lltani. Ha egy olyan elemet szeretnnk trlni, amely nem levlelem, akkor
mivel a fban az elemek sorrendjt semmilyen szably nem kti, a legegyszerubb,
ha a trlendo elem
adat mezojt fellrjuk valamelyik levlelem adat mezojvel s aztn a levlelemet trljk az elozo
mondatban lert mdon.
Rszfa (vagy akr az egsz fa) trlst rekurzvan valsthatjuk meg, azonban gyelnnk kell
arra, hogy elobb mindig a leszrmazott elemeket kell trlnnk s utna trlhetjk csak az aktulis gykr elemet. A hrom rekurzv bejrsi md kzl ezt a stratgit ppen a postorder bejrs
valstja meg, azaz
struct faelem* felszabadit(struct faelem* gyoker)
{
if ( gyoker == NULL )
return NULL;
felszabadit(gyoker->bal);
felszabadit(gyoker->jobb);
free(gyoker);
return NULL;
}
A felszabadit fggvnye elso hvsa csak a baloldali rszft trli, a msodik hvs pedig az egsz
ft.
17. Binris keresofa
A binris keresofa teht egy specilis binris fa, specilis abban az rtelemben, hogy egy szablyt rendelnk hozz, s ez a szably egyrtelmuen
meghatrozza minden elem helyt a fban. A szably a
kvetkezo: minden elemre teljeslnie kell, hogy az aktulis elembol indul baloldali rszfban az aktulis elem adat mezojtol csak kisebb adat mezoju faelemek szerepelhetnek, a jobb oldali rszfban
pedig csak nagyobb adat mezoju faelemek. Knnyu ltni, hogy ez a szably egy rendezettsget visz
a fba s egy adott fa esetn egyrtelmuen
meghatrozza, hogy egy j elemet hov kell beszrnunk
a fba. Vegyk szre azt is, hogy egy binris keresofa minden elembol csak egyet tartalmazhat! Tekintsk az elozo szakaszban vizsglt binris ft, amelybe az elemek a 5 2 1 6 3 0 1 sorrendben
kerltek be. Ezen rkezsi sorrendbol a 2. brn lthat binris keresoft pthetjk fel a megadott
szably alapjn. Jegyezzk meg tovbb, hogy a fa fgg a brkezo elemek sorrendjbol, ugyanazon
elemekbol tbb olyan binris ft is fel lehet pteni, amelyre teljesl a binris keresofkat jellemzo
rendezettsgi szably. Egy binris keresofa megvalsthat s kezelheto az ltalnos binris fk esetn ltrehozott eszkzkkel (struktrkkal, eljrsokkal), egyedl a ft mdost fggvnyeket kell
gy megrni, hogy a mdosts utn is teljesljn a binris keresofkat jellemzo szably a fra. A
binris keresofba trtno beszrst megvalst szably teht a kvetkezo:
Ha a gykrelem res, akkor hozzunk ltre egy j elemet s adjuk vissza ennek mutatjt.
Ha a gykrelemben trolt adat kisebb, mint a beszrand adat, akkor a jobb oldali rszfba
kell beszrnunk azt ugyanezen szabllyal.
Ha a gykrelemben trolt adat nagyobb, mint a beszrand adat, akkor a bal oldali rszfba
kell beszrnunk azt ugyanezen szabllyal.
83
Knnyu ltni, hogy ha olyan elemet szeretnk beszrni, amely mr szerepel a fba (a pldban az 1-es
rtk), akkor az nem fog mg egyszer bekerlni, azaz a pldban felptett fa egy elemmel kevesebbet
tartalmaz, mint ahny elemre meghvtuk a beszur fggvnyt.
Jegyezzk meg azt is, hogy a binris keresofa inorder bejrsa ppen a benne trolt elemek nvekvo
sorrendben trtno kirst eredmnyezi, hiszen minden elem elott kirjuk a bal oldali rszfjnak elemeit, azaz a tole kisebb elemeket.
84
Kovcs Gyrgy
A keresst szintn rekurzvan clszeru megvalstani, hiszen ha keresnk egy elemet, potnosan
tudjuk, hogy hol kell lennie. Ha nincs ott, azaz NULL rtket tallunk a helyn, akkor NULL mutatval
trnk vissza, ellenekzo esetben az o t tartalmaz faelem cmvel:
struct faelem* keres(int x, struct faelem* gyoker)
{
if ( gyoker == NULL || gyoker->adat == x )
return gyoker;
if ( gyoker->adat < mit )
return keres(x, gyoker->jobb);
if ( gyoker->adat > mit )
return keres(x, gyoker->bal);
}
A binris fkhoz kapcsold utols algoritmusknt nzzk meg a trls menett, csak algoritmikusan:
Ha levlelemet akarunk trlni, azt egyszeruen
megtehetjk, az ltalnos binris fknl trgyalt
mdon, azaz felszabadtjuk az elemet, majd a szlo elem r mutat mutatjt NULL-ra lltjuk.
(3. bra)
Ha olyan elemet szeretnnk trlni, amelynek csak egy rkvetkezoje van, akkor a szlo elemnek a trlendo elemre mutat mutatjt fellrjuk a trlendo elem egyetlen rkvetkezojnek
mutatjval, majd felszabadtjuk a trlendo elemet. (4. bra)
Ha olyan elemet szeretnnk trlni, amelynek kt rkvetkezoje van, akkor a trlendo elemet
fellrjuk a baloldali rszfjnak legjobboldalibb elemvel, vagy a jobboldali rszfjnak legbaloldalibb elemvel (ugyanis ezekben az esetekben nem srl a rendezettsgi szably), majd
trljk azt az elemet, amelyikkel fellrtuk a trlendo elemet, az elso kt szably valamelyikvel. (5. bra)
85
bra 4: Egy leszrmazottal rendelkezo elem trlse (a pirossal jellt rtkeket trltk, a zlddel jellt
kapcsolatot frissen hoztuk ltre)
bra 5: Kt leszrmazottal rendelkezo elem trlse (a trlendo elem a gykerben lvo 5-s rtk, zld
jells azt jelenti, hogy csak mdostottuk a trlendo elem rtkt, a beldolali rszfa legjobboldalibb
elemre (3), majd fizikailag a baloldali rszfa legjobboldalibb elemt trltk (a pirossal jellt 3-as))
86
Kovcs Gyrgy
Irodalomjegyzk
[1] C ORMEN , T. H. AND L EISERSON , C. E. AND R IVEST, L. R. (1996). Algoritmusok Muszaki