Anda di halaman 1dari 86

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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];

A tmb i. elemt szintn a szgletes zrjelek segtsgvel hivatkozhatjuk:


azonosito[i];

Egy tmbnek kezdortket kapcsoszrjelek kztt felsorolt kezdortk sorozattal adhatunk:


tipus azonosito[N]= {konst_kif1, konst_kif2, ..., konst_kifN};

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:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

#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;
}

Fontos megjegyeznnk, hogy a tmbk indexelse 0-val kezdodik!

F ONTOS

Tmbkkel kapcsolatban a kt legfontosabb algoritmuscsald a kereso s rendezo algoritmusok csaldja.


A tovbbiakban ezek nhny elemt vesszk sorra.
5.1. Teljes keress
Legyen adott t tmb s egy, a tmbben trolt rtkek tpusval megegyezo tpus k rtk. A keress
clja annak eldntse, hogy a k rtk szerepel-e a tmbben. Azon kvl, hogy szerepel-e, gyakran
hasznos informci mg az is, hogy hol szerepel a keresett elem a tmbben, vagyis mi az elem indexe. Mivel az eljrsorientlt programozs lnyege, hogy programunk viszonylag rvid, egyszeru
fggvnyekbol s eljrsokbl pljn fel, a tovbbiakban az egyes adatszerkezeteket kezelo algoritmusokat fggvnyek formjban rjuk meg. Ennek fnyben teht egy kereso algoritmus megvalstshoz olyan fggvnyt kell rnunk, amely paramterknt kap egy tmbt, valamint egy rtket,
s visszaadja ezen rtk indext ha az szerepel a tmbben, s valamilyen specilis rtket, ha nem szerepel a tmbben. Ez a specilis rtk tbbnyire -1, mivel a -1-et nem hasznljuk tmb indexelsre,
ha a fggvny visszatrse -1, abbl lehet tudni a hvsi krnyezetben, hogy a keresett rtk nincs
benne a tmbben.
Teljes keress esetn nincs semmilyen felttelezsnk a tmbrol, a teljes keress teht ltalnosan
hasznlhat, a tmb minden elemt sorra vesszk s megvizsgljuk, hogy megegyezik-e a keresett
rtkkel. Ha igen, visszaadjuk annak indext, ha nem, a kvetkezo elemet vizsgljuk, egszen addig,
amg el nem rtk a tmb vgt. Ha elrtk a tmb vgt, biztos, hogy a keresett elem nincs benne a
tmbben, ezrt a -1 rtket adjuk vissza. Az albbiakban egy egszeket tartalmaz tmbben trtno
teljes keresst implementlunk.
int teljesKereses(int t[], int n, int k)
{
int i;
for ( i= 0; i < n; ++i )
if ( t[i] == k )
return i;
return -1;
}

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;
}

A legkisebbErtek fggvny trzsben a min vltozban troljuk a felttelezett legkisebb rtket.


Feltve, hogy a tmb mrete legalbb 1, kezdeti felttelezsnk, hogy a legkisebb elem ppen a
tmb elso eleme. Ezt kvetoen a tmb tbbi elemt sorra sszehasonltjuk a felttelezett legkisebb
rtkkel, s ha kiderl, hogy a tmb valamely eleme kisebb, mint eddigi felttelezsnk (azaz teljesl
az if felttele), mdostjuk a felttelezsnket az jonnan tallt, felttelezett legkisebb rtkre. Vegyk szre, hogy a ciklus lefutsa utn a min vltoz biztosan a tmbben szereplo legkisebb rtket
fogja trolni! Nagyon fontos, hogy az inicializlst mindig a tmb valamely elemvel kell vgeznnk,
hiszen ha a min vltoz kezdortke pldul 10 lenne s a tmb csak 100-tl nagyobb rtkeket
trolna, akkor a visszatrsi rtk is 10 lenne (helytelenl), hiszen a tmb egyik elemre sem teljeslne, hogy kisebb, mint a min vltoz rtke.
Mdostsuk a fenti fggvnyt gy, hogy a legkisebb rtk helyt adja vissza!
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;
}

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:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}

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

5.2. Lineris keress


F ONTOS

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)

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

{
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;
}

5.3. Binris keress


F ONTOS

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;

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

}
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 )
{

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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

egy segdvltoz segtsgvel


oldhat meg.
A belso for-ciklus az azt megelozo min= i rtkadssal egy tmb legkisebb eleme helynek (indexnek) meghatrozsa. (Hasonltsuk ssze ezt a kdot a korbban megrt legkisebb helyet meghatroz
fggvny kdjval!) Figyeljk meg, hogy itt a minimum hely keresse nem a tmb elejrol indul,
hanem a tmb i. elemtol, amely egy klso ciklusban folyamatosan no.
Az klso ciklus elso lpsben teht i= 0 esetn a belso ciklus a teljes tmb legkisebb elemnek
helyt hatrozza meg, melynek indexe a min vltozba kerl. Ezt kvetoen hrom utastssal megcserljk a tmb elso, teht i=0 indexu,
s legkisebb, azaz min indexu elemt. A msodik lpsben
a legkisebb rtk keresse a tmbben mr i=1-tol indul, azaz az eredeti tmb msodik elemtol
kezdodoen keressk a tmb legkisebb elemt, amely gy az egsz tmb msodik legkisebb eleme
lesz. Ezen msodik legkisebb elemet aztn mr az i=1 indexu elemmel, azaz a teljes tmb msodik
elemvel cserljk meg. Ekkor a tmb elso kt eleme mr rendezett. Knnyu ltni, hogy a klso ciklus
folytatsval az egsz tmb rendezett vlik.
Az albbi pldban egy 5 elemu tmb rendezse sorn a tmbnek a klso ciklus lpsei kztti llapota lthat (flkvrrel szedtk a 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
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;
}
}

A fenti legkisebbErtekHelye fggvny elso paramtere tovbbra is a tmb, amelyben keresnk,


msodik paramtere a tmb mrete, harmadik paramtere pedig azon index, amelytol a keresst
kezdeni kell.
5.7. Feladat: Mdostsa gy a minimum kivlasztsos nvekvoen rendezo algoritmust, hogy az maximum kivlasztssal cskkeno sorrendbe rendezze a paramterknt kapott tmbt!
5.7. Megolds:
void maximumKivalasztasosCsokkenoRendezes(int t[], int n)
{
int max, i, j, tmp;
for ( i= 0; i < n; ++i )
{
max= i;
for ( j = i; j < n; ++j )
if ( t[j] > t[max] )
max= j;
tmp= t[max];
t[max]= 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;

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}
}

5.5. Bubork rendezs


A bubork rendezs clja ugyanaz, mint a szlsortk kivlasztsos rendezs, koncepcijban klnbzik csak:
Tegyk fel, hogy nvekvo sorrendben szeretnnk rendezni a tmbt.
Induljunk a tmb vgrol s hasonltsuk ssze a tmb utols elemt az azt megelozovel, ha az
utols elem (n.) kisebb, mint az azt megelozo (n-1.), akkor a rendezett tmbben biztos, hogy
az (n.) elemnek valahol az (n-1.) elem elott kell szerepelnie, ezrt cserljk meg o ket, hogy
egymshoz kpes legalbb j sorrendben legyenek. Ismteljk meg ezt a lpst az utols elotti
elemre s az azt megelozore, s gy tovbb, egszen a msodik elemig s az azt megelozo elso
elemig.
Az elozo muveletsor

eredmnyeknt a tmb legkisebb eleme biztosan a tmb elso helyn fog


szerepelni.
Ismteljk meg a fenti muveletsort,

ismt a tmb n. elemtol kezdve. Knnyu ltni, hogy ez a


tmb msodik legkisebb elemt a mdosik helyre fogja juttatni.
Ismteljk meg a fenti muveletsort

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

minden alkalommal a tmb utols elemnl


kezdjk, azonban nem kell mindig a tmb elso elemig elmenni vele, hiszen a tmb elejn lvo mr
rendezett elemek sorrendje mr nem vltozhat, nem teljeslhet az "i. kisebb, mint az i-1." felttel.
A bubork rendezs C kdja (gyeljnk arra, hogy a tmb elso elemnek indexe 0, a tmb utols
elemnek indexe n-1):

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;
}
}

5.10. Feladat: Mdostsa a nvekvo bubork rendezst cskkeno bubork rendezsre!


5.10. Megolds:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

15

void csokkenoBuborekRendezes(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;
}
}

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

elvgzse utn az aktualis vltoz rtke ppen egyel


tbb lesz, mint ahny tmb elem kisebb volt a kijellt x elemnl.
Ekkor ha a tmb utols elemt (x) megcserljk az aktualis vltozban trolt indexu elemmel,
akkor ppen teljeslni fog, hogy az x elemtol balra lvo elemek minde kisebbek, mint x, a tole
jobbra lvo elemek mind nagyobbak, mint x.
Ezt kvetoen vgezzk el az eddigi lpseket (belertve ezt is) az x-et megelozo rsztmbre s
az x-et kveto rsztmbre, ha az tbb, mint 1 elembol ll.
Knnyu ltni, hogy a fenti algoritmus vgrehajtsa utn a tmb rendezett vlik.
A gyorsrendezst C-ben kt fggvnyben valstjuk meg, ez ugyanis elegnsabb s rvidebb, mintha
egy fggvnyt hasznlnk:
int particionalas(int t[], int kezdet, int veg, int kijelolt)
{
int aktualis, tmp, i;
int x= t[kijelolt];
t[kijelolt]= t[veg-1];
t[veg-1]= x;
aktualis= kezdet;
for ( i= kezdet; i < veg-1; ++i )
if ( t[i] < x )
{
tmp= t[i];
t[i]= t[aktualis];
t[aktualis]= tmp;
++aktualis;
}
t[veg-1]= t[aktualis];
t[aktualis]= x;
return aktualis;
}
void gyorsRendezesKezdetEsVeg(int t[], int kezdet, int veg)
{
int aktualis;
if ( veg > kezdet )
{
aktualis= particionalas(t, kezdet, veg, (kezdet + veg)/2);
gyorsRendezesKezdetEsVeg(t, kezdet, aktualis);
gyorsRendezesKezdetEsVeg(t, aktualis + 1, veg);
}
}

A particionalas fggvny vgzi az tmb elemeinek kt csoportra bontst. A fggvny vgn


a kijelolt vltozban trolt indexu elemtol balra a tole kisebb elemek, jobbra a tole nagyobb elemek szerpelnek majd a tmbben. Visszatrsi rtke kijelolt indexu elem j helynek indexe a
tmbben. A gyorsRendezesKezdetEsVeg fggvnyt rekurzvnak nevezzk, hiszen nmagt hvja
klnbzo paramterekkel. Abban az esetben, ha a rendezendo rsztmb utols elemnek indexe
nagyobb, mint az elso elemnek indexe, azaz a rsztmb legalbb egy elemu (a veg vltoz mindig a
rsztmb (utols elemnek indexe + 1) rtket tartalmaz), akkor vgrehajtjuk a particionlst, melynek

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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,

a rendezs vget rt)

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;
}

A foprogramban (main fggvnyben) az i vltozt elobb ciklusvltozknt hasznljuk, majd az i


vltozba olvassuk be azokat az rtkeket, amelyeket aztn a tmbben keresnk. A program kimenete
a begpelt bemenet esetn:
adjon
3 2 5
adjon
10
nincs
adjon
7
benne
adjon
-1

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.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

19

A halmazt magt egy tmbbel fogjuk reprezentlni, a halmazhoz kapcsold muveleteket

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

kifejezsben az I annak a halmaznak az indiktorfggvnyt jelli, amely a 0-tl nagyobb s 10-tl


kisebb, 3-mal oszthat szmokat tartalmazza. A fenti kifejezs szerint gy x rtke ezen halmaz elemeinek sszege. Hasonlan folytonos esetben a
(2)

y=

x2 I{i0i<1}

kifejezs szerint y rtke az x^2 fggvny integrlja a [0,1[ halmazon.


Termszetesen csak a diszkrt esettel foglalkozunk, teht vges szmossg halmazokkal. Vegyk
szre, hogy a korbbi diszkrt kifejezsben az indiktor fggvny felttele kt rszbol ll. Az elso
rsze egy intervallumot definil, mg a msodik rsze egy oszthatsgi felttelt fogalmaz meg. Az
intervallum kiemelheto a felttelbol:
(3)

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

Egy halmazhoz mindenekelott


rgztennk kell az alaphalmazt, azaz azt a maximlis elemszmot, amelyet kezelni fogunk. A tovbbiakban egy halmazt az N elemu alaphalmaznak megfelelo
N elemu tmb fog reprezentlni. Egy N elemu tmbbel a legknnyebben a [0,N-1] egszeket tartalmaz alaphalmaz reprezentlhat, ugyanis ha az alaphalmaz egy olyan A rszhalmazt szeretnnk
reprezentlni, amely az i [0, N 1] rtket tartalmazza, akkor a tmb i. elemt, mint az alaphalmazon rtelmezett indiktorfggvny rtkt az i helyen, 1-re lltjuk.
Halmaz ltrehozsa. Legyen teht az alaphalmaz az N = 10 elemu,
egszeket tartalmaz [0, N 1]
intervallum. Ekkor egy res halmazt (amely teht az alaphalmaznak kell, hogy rszhalmaza legyen),
az albbi mdon hozhatunk ltre.
int A[10]= {0};

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.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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

rtke is 1. Mindez azt jelenti, hogy ha az A vagy B tmb i. eleme 1,


akkor a C tmb i. eleme is 1 lesz.
Halmazok klnbsge. Az albbiakban az C = A/B klnbsget valstjuk meg az elozoekhez
hasonl paramterezsu eljrssal, azaz azon elemek lesznek benne a C halmazban (azoknak lesz 1
rtke a C tmbben), amelyek az A halmazban benne vannak, de a B halmazban nincsenek benne.
void kulonbseg(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 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

szerepeljen a logikai kifejezs helyett, de az


eljrsok mukdse

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.

A msodik ciklus minden esetben az "alaprtelmezssel" tlti fel az


eredmnytmbt, azaz metszet esetn termszetesen az eredmny halmazba nem kerlnek be azok
az elemek, amelyek csak az egyik halmazban vannak benne, uni esetn ha benne vannak a nagyobb
halmazban, akkor bekerlnek az eredmnyhalmazba is, klnbsg esetn hasonlan.
6.3. Feladat: rjon fggvnyt, amely kiszmtja a paramterknt kapott kt darab, azonos mretu halmaz szimmetrikus differencijt!

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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.4. Megolds: A fenti egyszerubb


pldk alapjn:
1 - (1 - A[i]*(A[i] - B[i]))*(1 - B[i]*(B[i] - A[i]));

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

int main(int argc, char** argv)


{
int a[5], b[5], c[5];
int i;
printf("kerem az elso halmaz indikator fuggvenyet:\n");
for ( i= 0; i < 5; ++i )
scanf("%d", &(a[i]));
printf("kerem az masodik halmaz indikator fuggvenyet:\n");
for ( i= 0; i < 5; ++i )
scanf("%d", &(b[i]));
metszet(a, b, c, 5);
printf("a halmazok metszetenek szamossaga: %d\n", szamossag(c,5));
unio(a, b, c, 5);
printf("a halmazok 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 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

sok szerepelhet. Multihalmazok brzolsa hasonlan trtnik a halmazokhoz:


kijellnk egy alaphalmazt, pldinkban a termszetes szmok halmazt egy bizonyos N szmig,
a halmazokhoz hasonlan egy N elemu alaphalmazon rtelmezett multihalmazt egy N elemu
egsz szmokbl ll tmbbel reprezentlunk,
a tmb egyes elemei azonban nem logikai rtkek lesznek, hanem az i. indexu elem rtke azt
adja meg, hnyszor szerepel az i szm a multihalmazban.
Lssuk a korbban vizsglt algoritmusok hogyan alakulnak.
Ltrehozs. A multihalmazokat a halmazokhoz hasonlan teht tmbkkel reprezentljuk, a klnbsg azonban, hogy ezen tmbk tetszoleges nem-negatv szmot tartalmazhatnak. Az albbi pldban
azon [0, 4] alaphalmazon rtelmezett multihalmazt hozzuk ltre, amely 3 darab 1-es elemet tartalmaz:
int multihalmaz[5]= {0, 3, 0, 0, 0};

A halmazhoz egy i elemet a


++multihalmaz[i];

muvelettel

adhatunk hozz, s a j szmot a

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

25

if ( multihalmaz[j] > 0 )
--multihalmaz[j];

utastssal vehetjk ki a halmazbl.


Tartalmazs vizsglat. Olyan eljrst szeretnnk rni, amely logikailag igaz rtket ad vissza, ha
a paramterknt kapott rtk benne van a szintn paramterknt kapott multihalmazban s hamis
rtket ad vissza, ha nincs benne:
int eleme(int A[], int n, int k)
{
return A[k] > 0;
}

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.

Vegyk szre, hogy a return utasts utn szereplo


logikai kifejezs teljesen ekvivalens azzal, ha csak A[k]-t runk a return utasts utn.
Uni. Termszetesen az uni kpzsnl egyszeruen

ssze kell adnunk a megfelelo elemeket. Az


albbi eljrsban az A s B azon multihalmazokat reprezentl tmbk, amelyek unijt szeretnnk
kpezni, a fggvny lefutsa utn C tartalmazza majd az unit, n pedig a multihalmazok kzs
mrete:
void unio(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] + B[i];
}

Metszet. Az albbi fggvny paramterezse az unio fggvnyhez hasonl. A metszetkpzs


rtelemszeruen
trtnik: a metszet halmazban az i elem annyiszor fog elofordulni, ahnyszor A-ban
s B-ben is elofordul, azaz az A[i] s B[i] kzl a kisebb rtk kell hogy kerljn C[i]-be.
void metszet(int A[], int B[], int C[], int n)
{
int i;
for ( i= 0; i < n; ++i )
C[i]= A[i] < B[i] ? A[i] : B[i];
}

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

Szmossg. Egy multihalmaz szmossgt a halmaz szmossghoz hasonlan mrhetjk:


int szamossag(int A[], int n)
{
int i, sum= 0;
for ( i= 0; i < n; ++i )
sum+= A[i];
return sum;
}

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)
{

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

27

return 0 <= k && k < n && A[k];


}

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

kerem az masodik multihalmaz elemeit fuggvenyet:


4 4 3 0 0
a multihalmazok metszetenek szamossaga:
5
a multihalmazok uniojanak szamossaga:
20

8. Kt- s tbbdimenzis tmb


Korbban megismertk a tmb adatszerkezetet, ami knnyen lthat, hogy ppen a matematikai
vektor koncepci megfeleloje. Most megnzzk, hogy tmb segtsgvel hogyan hozhatunk ltre
olyan adatszerkezetet, amely a ktdimenzis mtrix vagy brmilyen tbbdimenzis adatszerkezet
megfeleloje lehet.
Kt vagy tbbdimenzis tmbk trolsi mdjnak magyarzatt s paramterknt trtno tadsnak lehetosgeit lsd a Magasszintu programozsi nyelvek 1 - gyakorlati jegyzet megfelelo szakaszaiban.
Az albbiakban rgztett mretu kt- s tbbdimenzis tmbket vizsglunk.
Rgztett N M mretu,
tipus tpus s azonosito nevu ktdimenzis tmbt az albbi mdon
hozhatunk ltre:
tipus azonosito[N][M];

A ktdimenzis tmb szemlletesen egydimenzis tmbk tmbje, gy kezdortket az egydimenzis


tmbk esethez hasonlan adhatunk neki, azonban gyelnnk kell r, hogy a tmb elemei szintn
tmbk legyenek:
tipus azonosito[N][M]= {{konstKif1, konstKif2, konstKifM}, ..., {konstKif1, konstKif2,
konstKifM}};

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");
}

A fenti kdrszlet lefutsnak eredmnye:


1 2
2 3
3 4

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 )

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

29

{
for ( j= 0; j < 3; ++j )
{
for ( k= 0; k < 4; ++k )
printf("%d ", t[i][j][k]);
printf("\n");
}
printf("\n");
}

A fenti kdrszlet kimenete:


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

A kt- illetve tbbdimenzis adatszerkezetek funkcijukat tekitve vagy egy matematikai konstrukci megvalsulsai (pl. mtrix), vagy egyszeruen

trol (container) adatszerkezetek, azaz egyetlen


cljuk, hogy kt-, hrom, stb. indextol fggo adatokat tudjunk trolni bennk. Mivel utbbi esetben az adatok erosen fggenek az indexektol, gy kevs olyan algoritmus van, amely tnylegesen
ilyen tbbdimenzis adatszerkezeteken hajtana vgre muveleteket,

hiszen brmilyen algoritmus, ami


megvltoztatja az elemek helyt, stb., elrontja az indexektol val fggosget. Az egyetlen algoritmus,
amit itt megvizsglunk, a sor-oszlop kompozcis mtrixszorzs. Az albbiakban rgztett mretu
ktdimenzis tmbkre ksztjk el a mtrix szorz eljrst. Feltettk, hogy X, Y s Z globlis konstansok:
const int X= 3;
const int Y= 4;
const int Z= 5;
void matrixSzorzas(float a[X][Y], float b[Y][Z], float c[X][Z])
{
int i, j, k;
float sum;
for ( i= 0; i < X; ++i )
{
for ( j= 0; j < Z; ++j )
{
sum= 0;
for ( k= 0; k < Y; ++k )
sum+= a[i][k]*b[k][j];
c[i][j]= sum;
}
}
}

A fenti pldban az a s b mtrixok szorzatt szmtjuk ki a c mtrixba.


Kt s tbbdimenzis tmbk ltrehozsnak fenti mdja azzal az elonnyel jr, hogy nem kell a tbbdimenzis tmbk mreteit tadni paramterknt (termszetesen a fenti megkzelts egydimenzis
tmbk esetn is hasznlhat). Htrnya azonban, hogy a fenti fggvny csak a rgztett X=3, Y=4 s
Z=5 mretu tmbk esetn fog mukdni,

azaz csak akkor hasznlhatjuk klnbzo mretu mtrixok


szorzsra a fenti fggvnyt, ha a mtrixok szorzsa elott megvltoztatjuk az X, Y s Z vltoz rtkt
a kdban, majd jra lefordtjuk azt. Ez azonban a legtbb esetben ellent mond az eljrsorientlt programozs szemlletnek, azaz annak, hogy egy fggvny minl ltalnosabban valstson meg egy
funkcit.
Ahhoz, hogy az eljrsunk tetszoleges mretu mtrixok esetn is mukdjn,

a ktdimenzis tmbket

F ONTOS

30

Kovcs Gyrgy

egydimenzis tmbknt kell brzolnunk. Az egydimenzis tmbknt trtno brzols trtnhet


sor- vagy oszlopfolytonosan. A sorfolytonos brzols azt jelenti, hogy az M N mretu kt dimenzis tmb elemeit egy M N mretu egydimenzis tmbben troljuk, gy, hogy a sorai egymst
kvetik az egydimenzis tmbben. Oszlopfolytonos trols esetn az egydimenzis tmb mrete
szintn M N , azonban az eredeti ktdimenzis tmb oszlopai kvetik egymst az egydimenzis
tmbben.
A gyakorlatban ltalban a sorfolytonos brzolst alkalmazzk.
Adott egy S O mretu ktdimenzis tmb (S - sorok szma, O - oszlopok szma) sorfolytonosan
brzolva egy S O mretu egydimenzis tmbben. Az a krds, hogy hogyan rhetjk el a ktdimenzis tmb s, o indexu elemt (s - sorindex, o - oszlopindex) az egydimenzis tmbben, azaz
sorfolytonos brzolsnl mi lesz a ktdimenzis tmb s, o indexu elemnek sorfolytonos indexe? A
vlaszt egy nagyon egyszeru formulban kapjuk meg:
egydimenzios_index= s * O + o

A fenti nagyon egyszeru gondolat s formula segtsgvel mr tadhatunk paramterknt tetszoleges


mretu ktdimenzis tmbt egydimenzis tmbknt s a sorfolytonos brzolsban az s, o indexu
elemet a fenti formula segtsgvel rhetjk el. A korbbi pldban ltrehozott ktdimenzis tmbt
az albbi mdon valsthatjuk meg sorfolytonos brzolssal, kezdortkadssal:
int t[6]= {1, 2, 2, 3, 3, 4};

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;
}
}
}

Knnyu ltni, hogy az eljrs mukdse

teljesen megegyezik a korbbi matrixSzorzas eljrs


mukdsvel,

a klnbsg csak a paramterezsben valamint az elemek elrsben jelenik meg.


8.1. Feladat: rjon eljrst, amely paramterknt kap egy egszeket tartalmaz, sorfolytonosan brzolt ktdimenis tmbt valamint annak mreteit s kirja az elemeit a kpernyore mtrixos alakban!
8.1. Megolds:
void matrixAlak(int t[], int sorok, int oszlopok)
{
int i, j;
for ( i= 0; i < sorok; ++i )
{
for ( j= 0; j < oszlopok; ++j )

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

31

printf("%d ", t[i * oszlopok + j]);


printf("\n");
}
}

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,

ltrehozunk mg egy 4 s egy 9 mretu tmbt az eredmnyek trolsra.


8.0.1. forrskd: matrix.c
#include <stdio.h>
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;
}
}
}
void matrixAlak(float t[], int sorok, int oszlopok)
{
int i, j;
for ( i= 0; i < sorok; ++i )
{
for ( j= 0; j < oszlopok; ++j )
printf("%.1f ", t[i * oszlopok + j]);
printf("\n");
}
}
int main(int argc, char** argv)
{
float a[6];
float b[6];
float c[9];
float d[4];
int i, j;
for ( i= 0; i < 2; ++i )
{
printf("Kerem az a matrix 3 elemu %d. sorat:\n", i);
scanf("%f%f%f", &(a[i*3 + 0]), &(a[i*3 + 1]), &(a[i*3 + 2]));
}
for ( i= 0; i < 3; ++i )
{
printf("Kerem a b matrix 2 elemu %d. sorat:\n", i);
scanf("%f%f", &(b[i*2 + 0]), &(b[i*2 + 1]));
}

32

Kovcs Gyrgy

printf("a beolvasott a matrix:\n");


matrixAlak(a, 2, 3);
printf("a beolvasott b matrix:\n");
matrixAlak(b, 3, 2);
matrixSzorzas(a, 2, 3, b, 3, 2, c);
printf("a*b:\n");
matrixAlak(c, 2, 2);
matrixSzorzas(b, 3, 2, a, 2, 3, d);
printf("b*a:\n");
matrixAlak(d, 3, 3);
return 0;
}

A program futsnak egy lehetsges kimenete (a lthat begpelt szmok esetn):


Kerem az a matrix 3 elemu 0. sorat:
1 2 3
Kerem az a matrix 3 elemu 1. sorat:
2 3 4
Kerem a b matrix 2 elemu 0. sorat:
1 2
Kerem a b matrix 2 elemu 1. sorat:
2 3
Kerem a b matrix 2 elemu 2. sorat:
3 4
a beolvasott a matrix:
1.0 2.0 3.0
2.0 3.0 4.0
a beolvasott b matrix:
1.0 2.0
2.0 3.0
3.0 4.0
a*b:
14.0 20.0
20.0 29.0
b*a:
5.0 8.0 11.0
8.0 13.0 18.0
11.0 18.0 25.0

9. Ritkamtrix

F ONTOS

A gyakorlatban mrsi eredmnyekbol szrmaz adatokat nagyon gyakran nagymretu mtrixok


formjban kapjuk meg. Ezen mtrixok azonban ritkk, abban az rtelemben, hogy valamely rtkbol nagyon sok van a mtrixban, a tbbi rtkbol azonban kevs. Azt az elemet, amelyikbol nagyon
sok van gyakori elemnek nevezzk. A gyakori elem ltalban a 0. Knnyu beltni, hogy ilyen esetben felesleges az egsz mtrixot trolni, elegendo csak azokat az elemeket s koordintikat trolnunk, amelyek rtke nem egyenlo a gyakori elemmel. Ennek megfeleloen a fenti rtelemben ritka
mtrixoknak tbb klnbzo hatkony s helytakarkos reprezentcijt is kidolgoztk, ezek kzl
a hrom soros s ngy soros reprezentcit vizsgljuk meg.

9.1. Hrom soros reprezentci


Legyen egy a reprezentland mtrix mrete M N , a gyakori elem elofordulsainak szma k. Ekkor
a hrom soros reprezentci egy olyan hrom, M N k elemu sorbl ll szerkezet, amelyben az elso
sor, msodik sor s harmadik sor i elemei rendre az i. nem gyakori elem sorindext, oszlopindext s

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

rtkt tartalmazzk. Tekintsk az albbi mtrixot:

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;
}

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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

A ngysoros reprezentci pedig:

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");
}
}

A megoldshoz felhasznltuk a korbban megrt elem fggvnyt.


9.4. Feladat: rjon foprogramot, amely beolvas egy 5 sorbl s 4 oszlopbl ll ktdimenzis tmbt
soronknt, amelyrol tudjuk, hogy a gyakori elem a 0, s a nem-gyakori elemek szma legfeljebb 10.
A program elkszti a mtrix hromsoros reprezentcijt a felepit fggvnnyel, majd a kimenetre
rja azt, s ezt kvetoen a hromsoros reprezentci alapjn a kiir fggvnnyel a kimenetre rja az
eredeti mtrixot is!
9.4. Megolds:
9.2.1. forrskd: ritkamatrix.c
#include <stdio.h>
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;
}
int elem(int sor3[], int oszlop3[], int ertek3[], int meret, int gyakoriElem, int s, int
o)
{
int i;
for ( i= 0; i < meret; ++i )
if ( sor3[i] == s && oszlop3[i] == o )
return ertek3[i];
return gyakoriElem;
}
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");
}
}

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

37

int main(int argc, char** argv)


{
int t[20];
int sor3[10];
int oszlop3[10];
int ertek3[10];
int meret;
int i;
for ( i= 0; i < 5; ++i )
{
printf("Kerem az t matrix 4 elemu %d. sorat:\n", i);
scanf("%d%d%d%d", &(t[i*4 + 0]), &(t[i*4 + 1]), &(t[i*4 + 2]), &(t[i*4 + 3]));
}
meret= felepit3sor(t, 5, 4, 0, sor3, oszlop3, ertek3);
printf("sor\t");
for ( i= 0; i < meret; ++i )
printf("%d ", sor3[i]);
printf("\noszlop\t");
for ( i= 0; i < meret; ++i )
printf("%d ", oszlop3[i]);
printf("\nertek\t");
for ( i= 0; i < meret; ++i )
printf("%d ", ertek3[i]);
printf("\n");
kiir(sor3, oszlop3, ertek3, meret, 0, 5, 4);
return 0;
}

A program kimenete a begpelt sorok esetn:


Kerem az t matrix
0 0 0 1
Kerem az t matrix
2 0 0 0
Kerem az t matrix
0 0 -1 0
Kerem az t matrix
0 0 0 0
Kerem az t matrix
0 0 1 0
sor
0 1 2 4
oszlop 3 0 2 2
ertek
1 2 -1 1
0 0 0 1
2 0 0 0
0 0 -1 0
0 0 0 0
0 0 1 0

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

teljesl? A vlasz termszetesen az, hogy legfeljebb


(12)

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

A sor adatszerkezet az egyik leggyakrabban hasznlt adatszerkezet, amely az albbi muveletekkel

rendelkezik:

res sor ltrehozsa,


sor ressgnek vizsglata,
elem hozzadsa a sorhoz (PUT),
elso elem elrse (TOP),
elem eltvoltsa (GET),
(a GET muvelet

egyben TOP muvelet

is lehet, azaz visszaadhatja az ppen eltvoltott elemet).

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

fogjuk megvalstani. A megvalsts sorn megint csak


tmbt hasznlunk, gy br elmletben egy sor tetszoleges sok elemet tartalmazhat, a gyakorlatban a
sor maximlis elemszmt korltozni fogja a megvalstshoz hasznlt tmb mrete.

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

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

39

az elemeket tmbben trolja, a tmb mrete megadja a maximlis elemszmot,


a sor elemnek indext a tmbben egy veg vltozban tartjuk nyilvn,
a sor elso eleme mindig a tmb elso eleme,
ha eltvoltunk egy elemet a sor elejrol, azaz "kivesszk" a sorbl az elso elemet, a sor tbbi
elemt egyel elorbb cssztatjuk a sorban.

A tovbbiakban egy egszeket tartalmaz sort s annak muveleteit

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;

Most a sor, a veg s a kezdet vltozk reprezentljk szmunkra a sor adatszerkezetet.


res sor vizsglata. Mivel ebben az esetben a sor kezdete is vndorol, a sor utols elemnek indexbol nem tudjuk megmondani, hogy res-e a sor. Ha azonban a sor utols elemnek indexe kisebb,
mint a sor elso elemnek indexe, akkor rtelemszeruen

az indextartomny egy res intervallumot


definil a tmbben, azaz a tmbben brzolt sor res:
int uresSor()
{
return kezdet > veg;
}

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

Elso elem elrse. (TOP)


alapjn trtnik:

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

10.3. Ciklikus sor

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

sorn az indexvltozk "krbejrst" a maradkos oszts muvelettel

valstjuk meg azaz az indexvltozk nvelse utn mindig


maradkosan osztjuk azokat a tmb mretvel. Abbl kifolylag, hogy a veg vltozban trolt index a maradkos oszts miatt a kezdet vltoz el kerlhet, elollhat az a kellemetlen helyzet, hogy
a veg vltoz rtke ppen egyel kevesebb, mint a kezdet rtke. Ekkor nem tudjuk eldnteni,
hogy a sor res-e, vagy tele van-e. Hogy megoldst talljunk erre, bevezetnk egy jabb vltozt,
amelyben azt fogjuk szmolni, hogy hny elem van a sorban. Ez a szmls egyszeruen

azt jelenti,
hogy minden get muveletnl

kivonunk egyet a vltoz rtkbol s minden put muvelet

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;

Az elozoek alapjn teht van egy j vltoznk, az elemSzam.


res sor vizsglata. Akkor lesz res a sor, ha a veg vltoz rtke az inicializlsnak megfelelo -1
rtk, vagy ha a kezdet s veg vltoz rtke megegyezik, azaz
int uresSor()
{
return elemSzam == 0;
}

Elso elem elrse. (TOP) A top muvelet

szintn nagyon egyszeruen


valsthat meg, az eddigiekhez
hasonl mdon a kezdet vltoz ltal indexelt tmb elem.
int top()
{
return sor[kezdet];
}

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
{

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

43

printf("A sor tele van!\n");


}
}

j elem eltvoltsa. (GET) j elem eltvoltst nagyon egyszeruen


tehetjk meg: ha nem res a
sor, akkor egyszeruen
nveljk a kezdet vltoz rtkt:
int get()
{
if ( elemSzam > 0 )
{
kezdet= (kezdet + 1) % N;
--elemSzam;
}
else
{
printf("A sor res!\n");
return -1;
}
return sor[(kezdet-1)%N];
}

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___

A kvetkezo pldaprogramban a rgztett sorokon keresztl szemlltetjk a sorok hasznlatnak


menett. Egsz szmokat olvasok be a bemenetrol egszen a -1 rtkig, s berakom o ket egy sorba,
egyedl a put muveletet

hasznlva. Ezt kvetoen egy ciklusban a top, get s uresSor fggvnyek


segtsgvel kirom a sor tartalmt s ki is rtem azt.
10.4.1. forrskd: sor.c
#include <stdio.h>
const int N= 20;
int sor[20];
int veg= -1;

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;
}

A plda bemenet s kimenet:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet


kerek
2
kerek
4
kerek
3
kerek
6
kerek
-1
a sor
2 4 3

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

sorn azonban bekerltek a tmbkbe s fellrsig ottmaradnak.


10.3. Feladat: rjon programot, amely vgrehajtja az elozo feladatban lert muveletsort

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,

egy for-ciklusban kirjuk a sor tmb tartalmt. A for-ciklusban figyeljk, hogy az

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;
}

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

47

A program kimenete futtats utn:


_3 4 .4 0

11. Verem
A verem a sorhoz hasonl nagyon egyszeru adatszerkezet. Legfontosabb muveletei:

verem ressgnek ellenorzse,


verem felso elemnek elrse (TOP),
j elem hozzadsa a veremhez (PUSH),
felso elem eltvoltsa (POP),
(a POP muvelet

magban foglalhatja a TOP muveletet

is, azaz visszaadhatja a verem legfelso


elemt).

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;

Egy res verem tetejnek indexe teht -1.


ressg ellenorzse.

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];
}

Lthat, hogy a top muvelet

egy egyszeru tmb elem elrs, ahogy a sorok esetn is.

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");
}

Felso elem eltvoltsa. (POP) A pop muveletben

egyszeruen

csak cskkentjk a teteje vltoz


rtkt, abban az esetben, ha az nem -1, teht nem res a verem.
int pop()
{
if ( teteje != -1 )
--teteje;
return verem[teteje+1];
}

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;

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}

A plda bemenet s kimenet:


kerek egy szamot:
2
kerek egy szamot:
4
kerek egy szamot:
3
kerek egy szamot:
6
kerek egy szamot:
-1
a verem elemei:

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.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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:

struct pont2D p= {1, 2};

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;
}

Az eddig bemutatott algoritmusok rtelmt sokan megkrdojelezhetik, hiszen mire hasznlhat az


a gyakorlatban, hogy egsz szmokat tartalmaz tmbkben keresnk, vagy egsz szmokat tartalmaz tmbket rendeznk, egsz szmokat rakunk sor s verem adatszerkezetbe, stb. A korbbi algoritmusok demonstrlsra az egszeket tartalmaz tmbk voltak a legkzenfekvobbek. A tovbbiakban megnzzk, hogy hogyan rhatunk tnylegesen hasznlhat programokat, illetve hogyan
implementlhatjuk az eddigi algoritmusainkat elegnsabban a rekordok felhasznlsval.
12.1. Keress
12.5. Feladat: rjon fggvnyt, amely paramterknt kapja struct hallgato tpus objektumok
tmbjt valamint egy neptun kdot (sztringknt), s teljes keresst megvalstva visszaadja azon
tmb elem indext, amely a paramterknt kapott neptun-kd hallgathoz tartozik, ha nincs benne
a tmbben, 1-et ad vissza.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}

12.7. Feladat: Az eljrsorientlt szemllet gyakorlsaknt emeljk ki a h tmb feltltst s a kirst


egy-egy eljrsba!
12.7. Megolds:
12.1.2. forrskd: hallgatokereses2.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;
}
void feltolt(struct hallgato t[], int n)
{
int i;
for ( i= 0; i < n; ++i )
scanf("%s %d", t[i].neptunkod, &(t[i].szul_ev));
}
void kiir(struct hallgato t[], int n, char nk[])
{
int x;
x= teljesKereses(t, n, nk);
if ( x == -1 )
printf("ismeretlen hallgato\n");
else
printf("%d\n", t[x].szul_ev);
}
int main(int argc, char** argv)
{
struct hallgato h[5];
char tmp[7];
feltolt(h, 5);
while ( 1 )
{
printf("kerek egy neptunkodot:\n");
scanf("%s", tmp);
if ( strcmp(tmp, "vege") == 0 )
break;
kiir(h, 5, tmp);
}
return 0;

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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
}

Lthat, hogy a foprogram az elso megoldshoz kpest meglehetosen leegyszerusdtt,

a beszdes
fggvny s eljrsnevekbol knnyen kitallhat rnzsre a program mukdse,

a fggvnyek s
eljrsok szintn egyszeruek,

egy-egy nhny lpses feladatot valstanak meg. Megjegyezzk, hogy


a msodik megolds ltalnosabb a paramterezheto fggvnyek s eljrsok miatt.
12.2. Rendezs
12.9. Feladat: rjon eljrst, amely egy struct hallgato tpus elemekbol ll tmbt szletsi v
szerint rendez. A rendezs a minimum kivlasztsos nvekvo rendezs legyen!
12.9. Megolds:
void rendezSzulEv(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 )
min= j;
tmp= t[min];
t[min]= t[i];
t[i]= tmp;
}
}

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;
}
}

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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 )
{

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

59

printf("adjon meg egy neptun-kodot es szuletesi evet:\n");


scanf("%s %d", t[i].neptunkod, &(t[i].szul_ev));
}
rendezSzulEv(t, 5);
printf("szuletesi ev szerint rendezve:\n");
kiir(t, 5);
rendezNK(t, 5);
printf("neptun-kod szerint rendezve:\n");
kiir(t, 5);
rendezSzulEvNK(t, 5);
printf("szuletesi ev es neptun-kod szerint rendezve:\n");
kiir(t, 5);
return 0;
}

A program futsnak egy lehetsges ki s bemenete:


djon meg egy neptun-kodot es szuletesi evet:
asdfas 1991
adjon meg egy neptun-kodot es szuletesi evet:
ababab 1991
adjon meg egy neptun-kodot es szuletesi evet:
aaabbb 1991
adjon meg egy neptun-kodot es szuletesi evet:
cddefg 1990
adjon meg egy neptun-kodot es szuletesi evet:
alaman 1991
szuletesi ev szerint rendezve:
cddefg 1990
ababab 1991
aaabbb 1991
asdfas 1991
alaman 1991
neptun-kod szerint rendezve:
aaabbb 1991
ababab 1991
alaman 1991
asdfas 1991
cddefg 1990
szuletesi ev es neptun-kod szerint rendezve:
cddefg 1990
ababab 1991
alaman 1991
asdfas 1991
aaabbb 1991

12.3. Ritka mtrix


A ritka mtrix brzolsnak hrom s ngy soros megvalstsa meglehetosen knyelmetlen volt,
ugyanis a hrom s ngy sort egy-egy tmbben tartottuk nyilvn. Rekordok alkalmazsval sokkal
elegnsabb megoldst kaphatunk, ugyanis a hrom, illetve ngy sor sszetartoz (egy oszlopban
lvo) adatait sszefoghatjuk egy sajt rekord tpusba, s ezt kvetoen a hrom soros reprezentci
mr egy tmbbel megadhat.
12.14. Feladat: Hozzon ltre rekord tpust, amely a hromsoros reprezentci sszetartoz adatainak
sszefogsra alkalmas!
12.14. Megolds:
struct sor3
{
int sor, oszlop, ertek;
};

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;
};

Az res sort ltrehoz fggvny:


struct sor ujSor()
{
struct sor t;
t.vege= -1;
return t;
}

A sor ressgt ellenorzo fggvny:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

61

int uresSor(struct sor s)


{
return s.vege == -1;
}

A sorba trtno beszrst megvalst fggvny:


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;
}

A sor elso elemnek elrst megvalst fggvny:


int top(struct sor s)
{
return s.t[0];
}

A sor elso elemt eltvolt fggvny:


struct sor get(struct sor s)
{
if ( s.vege == -1 )
printf("a sor res\n");
else
--s.vege;
return s;
}

A sor tartalmt kir eljrs:


void kiir(struct sor s)
{
int i;
for ( i= 0; i <= s.vege; ++i )
printf("%d ", s.t[i]);
printf("\n");
}

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;

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}

A program kimenete a megfelelo bemenet esetn:


put a 2
put a 3
put a 4
get a
put b 1
put b 2
get a
vege
az a sor tartalma:
2
a b sor tartalma:
1 2

Termszetesen a struktrk felhasznlsval sorokban is trolhatunk tetszoleges sszetettsgu sajt


tpusokat, teht az elozo pldkhoz hasonlan akr hallgatk adatait is.
12.18. Feladat: Ksztse el a vndorl sor, a ciklikus sor s a verem adatszerkezeteket a rgztett
sorhoz hasonl, az adatszerkezetet struktrval reprezentl megkzeltssel!

64

Kovcs Gyrgy

13. Dinamikus memriakezels

F ONTOS

Eddigi programjainknak s adatszerkezeteinknek kzs htrnya, hogy megvalstsukhoz tmbt


hasznltunk, tmbbol indultunk ki, a tmbk pedig definci szerint statikus adatszerkezetek ami
azt jelenti, hogy mretk rgztett, meg nem vltoztathat, gy ez a mret felso hatrt szab minden
eddigi adatszerkezet maximlis elemszmnak.
Vegyk szre tovbb, hogy a kvetkezo problmt eddigi eszkzeinkkel nem tudjuk megoldani:
rjon programot, amely a bemenetrol beolvas egy egsz szmot (n), majd n darab egsz szmot s
fordtott sorrendben kirja azokat.
Azrt nem tudjuk ezt megoldani eddigi eszkzeinkkel, mert ahhoz hogy fordtott sorrendben ki
tudjuk rni az elemeket, trolnunk kell azokat, MINDET, azonban gy, hogy nem tudjuk, az n maximlis mrett, nem mondhatjuk azt, hogy egy N mretu tmb elg lesz, mert n = N + 1 elemet mr
rgtn nem tudunk trolni. Az lenne a j, ha a program futsa kzben tudnnk meghatrozni azt,
hogy pontosan mekkora memriaterletekkel, tmbkkel szeretnnk dolgozni. Amikor a memriban
lvo adatszerkezetek mrett dinamikus kezeljk, dinamikus memriakezelsnek nevezzk. A dinamikus memriakezels elso lpseknt a mutatk hasznlatval/jelentosgvel/lehetosgeivel kell
tisztban lennnk.
A mutat olyan vltoz, amely memriacmet tartalmazhat. Jegyezzk meg, hogy egy memriacmmel nmagban semmit sem tudunk kezdeni. Ahogy azt programozs gyakorlaton tanulta mindenki, ahhoz, hogy egy, a memriban lvo adattal dolgozni tudjunk, a cmn kvl tudnunk kell
azt is, hogy pontosan hny bjton van brzolva az adat s azt is, hogy pontosan milyen brzolssal. Azonban az brzols s a trolsra hasznlt bjtok szma a tpusokhoz van rendelve, gy teht
mutatk hasznlata esetn tudnunk kell annak az adatnak a tpust, amelyet brzolni szeretnnk.
Mindezt sszefoglalva, mutatkat az albbi deklarcis utastssal hozhatunk ltre:
tipus * azonosito;

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

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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);

A malloc fggvny mukdse

a kvetkezo: paramterknt kapja a lefoglaland memriaterlet


mrett bjtokban, s visszatrsi rtkknt visszaadja egy n mretu memriaterlet cmt, ha sikerl
lefoglalnia, vagy a NULL mutatt, ha nem sikerl a memriafoglals. Lssuk, a gyakorlatban hogyan
hasznlhat a fggvny pldul 10 darab egsz (int) rtk trolsra alkalmas memriaterletet:
int *p;
p= (int*)malloc(sizeof(int)*10);

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);

Lssuk, hogyan hasznlhatjuk a mutatkat, akkor, ha a mutatk struktrkat cmeznek. Tekintsk


az albbi kdrszletet:
struct hallgato
{
char neptun_kod[7];
int szul_ev;
};
struct hallgato h;
struct hallgato* hp;
hp= &h;

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");

A tovbbiakban a -> opertort hasznljuk ahol lehetsges.


Lssuk hogyan oldhatjuk meg most azt a feladatot, amelyet a szakasz elejn mg nem tudtunk
megoldani!
13.1. Feladat: rjon programot, amely a bemenetrol beolvas egy egsz szmot (n), majd n darab egsz
szmot s fordtott sorrendben kirja azokat.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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

amely egy-egy nll szerkezetet reprezentl a memriban, az albbi lesz:


struct lista
{
int adat;
struct lista* kov;
};

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

a beszrs. Mivel a lncolt lista egy


szekvencilis adatszerkezet, azaz van elso s utols elem, valamint minden elemnek van rkvetkezoje.
Ezek alapjn tbb klnbzo helyre is elvgezhetjk a beszrst. Az eljrsorientlt programozs jegyben azonban a beszrst vgzo fggvnyek kzs rszt, azaz egy-egy j terlet lefoglalst s
inicializlst vgzo muveleteket

kiemeljk az ujelem fggvnybe, amely visszatrsi rtke egy


jonnan lefoglalt, a listba trtno befuzsre

kszen ll objektum cme.


struct lista* ujelem(int x)
{
struct lista* tmp;
tmp= (struct lista*)malloc(sizeof(struct lista));
tmp->adat= x;
tmp->kov= NULL;
return tmp;
}

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:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

69

struct lista* vegere_beszur(int x, struct lista* fej)


{
struct lista* tmp;
if ( fej == NULL )
return ujelem(x);
tmp= fej;
while ( tmp->kov != NULL )
tmp= tmp->kov;
tmp->kov= ujelem(x);
return fej;
}

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;
}

Vegyk szre, hogy a fenti megoldsban a for ciklus magja res.


Trls A listbl trtno trlst megvalst fggvnyekbol is kettot valstunk most meg, a lista
elejrol s vgrol trtno trlst. Amikor a lista elejrol trlnk, kt esetet kell megklnbztetnnk,
azt, amikor res listbl szeretnnk trlni, s azt, amikor legalbb egy elemet tartalmaz listbl
trlnk. Ne felejtsk el, hogy nem elegendo egy elemet kifuzni

a listbl azt fel is kell szabadtani a


free fggvnnyel:
struct lista* elejerol_torol(struct lista* fej)
{
struct lista* tmp;
if ( fej == NULL )
return NULL;
tmp= fej->kov;
free(fej);
return tmp;
}

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;
}

Bejrs A bejrs muvelet

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;
}

Csere A csere fggvnyhez felhasznljuk a keres fggvnyt:


struct lista* csere(int mit, int mire, struct lista* fej)
{
struct lista* tmp= keres(mit, fej);
if ( tmp == NULL )
return fej;

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}

Lista trlse A lista trlse muvelet

a lista minden elemnek felszabadtst jelenti. gyeljnk kell


azonban arra, hogy miutn egy elemet felszabadtottunk, a mezoit mr nem rhetjk el, ezrt egy
elem felszabadtsa elott el kell trolnunk egy segdvltozban az o t kveto elem mutatjt, hogy
tovbblphessnk majd s azt is felszabadthassuk:
struct lista* felszabadit(struct lista* fej)
{
struct lista* tmp;

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:

int main(int argc, char** argv)


{
struct lista* a= NULL;
struct lista* b= NULL;
a=
a=
b=
b=
a=
b=
a=

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);
}

A fenti kd futsa utn az albbi kimenetet lthatjuk:


6
3 4 5

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.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

73

Lista elejre beszrs


void elejere_beszur(int x, struct lista** fejp)
{
struct lista* tmp;
tmp= ujelem(x);
tmp->kov= *fejp;
*fejp= tmp;
}

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);

14.1. Feladat: rjuk t a tbbi lista kezelo fggvnyt is eljrsra!


14.3. Rekurzi
Rekurzinak azt nevezzk, amikor egy fggvny vagy eljrs nmagt hvja meg. Rekurzi hasznlatval nagyon sok problmt elegnsan s rviden oldhatunk meg, azonban nem mindig a leghatkonyabb
megkzelts. Leggyakrabban bejrsoknl s adatszerkezetekben trtno pozcionlsnl hasznljk
a rekurzit. Lssuk, nhny fggvny rekurzv megvalstst.
Bejrs Elsoknt nzzk, hogyan rhatjuk ki a lista elemeit a trols sorrendjben, rekurzvan.
void bejar_elejerol(struct lista* fej)
{
if ( fej == NULL )

74

Kovcs Gyrgy
return;
printf("%d ", fej->adat);
bejar_elejerol(fej->kov);
}

A lista elemeinek kirsa fordtott sorrendben:


void bejar_vegerol(struct lista* fej)
{
if ( fej == NULL )
return;
bejar_vegerol(fej->kov);
printf("%d ", fej->adat);
}

Lista vgre trtno beszrs


struct lista* vegere_beszur(int x, struct lista* fej)
{
if ( fej == NULL )
return ujelem(x);
fej->kov= vegere_beszur(x, fej->kov);
return fej;
}

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.

A lista elejre trtno


beszrst az albbi mdon valsthatjuk meg a fenti sajt tpus defincival:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

75

LISTA* elejere_beszur(int x, LISTA* fej)


{
LISTA* tmp;
tmp= ujelem(x);
tmp->kov= fej;
return tmp;
}

15. Ktirnyba lncolt lista


A ktirnyba lncolt listt gy lehet elkpzelni, mint egy egyirnyba lncolt listt, amit "htulrl
visszafel IS felfuznk",

azaz minden elem tartalmaz egy mutatt az o t megelozore is. A listt az


elso s utols elemnek mutatjval reprezentljuk, s ennek az az elonye, hogy a lista vgre trtno
beszrsnl nincs szksg arra, hogy jra s jra a lista vgre kelljen pozicionlni. Ebben az esetben
a listt teht az elso s utols elemnek mutatja reprezentlja, ami azt jelenti, hogy az elegancia s
hatkonysg rdekben ssze kell fognunk ezen kt vltozt egy jabb struktrba. Teht szemben az
egyirnyba lncolt listknl, ahol egy listaelem tpus mutat reprezentlta a listt, itt most egy olyan
struktra reprezentlja azt, amely kt mezot tartalmaz, az egyik mezo a lista elso elemt, a msik
mezo a lista utols elemt cmzi. Emellett persze szksg van a szoksos, listaelemeket reprezentl
struktrra is, hiszen ebben troljuk az adatokat. A ktirnyba lncolt lista kezelshez teht kt
struktrt hozunk ltre:
struct klistaelem
{
int adat;
struct klistaelem* elozo;
struct klistaelem* kovetkezo;
};
struct klista
{
struct klistaelem* fej;
struct klistaelem* veg;
}

Lterhozs Ezek alapjn res listt gy hozhatunk ltre, hogy egyszeruen


deklarlunk egy struct klista
tpus vltozt, s belltjuk annak mezoit NULL rtkekre, hiszen nincs sem fej, sem veg eleme egy
res listnak:
struct klista a= {NULL, NULL};

A fenti a vltoz reprezentl egy ktirnyba lncolt listt.


15.1. Fggvnyek
Beszrs A ktirnyba lncolt listba trtno beszrst is tbb mdon valsthatjuk meg, az albbiakban a lista elejre s vgre trtno beszrst vgzo fggvnyeket rjuk meg. Termszetesen az
ujelem fggvny megrsval kezdnk.
struct klistaelem* ujelem(int x)
{
struct klistaelem* tmp= (struct klistaelem*)malloc(sizeof(struct klistaelem));

76

Kovcs Gyrgy
tmp->adat= x;
tmp->elozo= tmp->kovetkezo= NULL;
return tmp;
}

struct klista 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;
}
return a;
}

struct klista vegere_beszur(int x, struct klista a)


{
if ( a.veg == NULL )
a.veg= a.fej= ujelem(x);
else
{
a.veg->kovetkezo= ujelem(x);
a.veg= a.veg->kovetkezo;
}
return a;
}

Nagyban megknnyti a lista vgein operl fggvnyek mukdst,

hogy a veg s fej mezoknek


ksznhetoen a ktirnyba lncolt lista szimmetrikus, gy szimmetriai okokbl ha megrtunk egy fggvnyt a lista egyik vgre, azt nagyon knnyen trhatjuk egyszeru szimmetrikus mezonv helyettestssel gy, hogy a lista msik vgn operljon.
Trls
struct klista elejerol_torol(struct klista a)
{
if ( a.fej == NULL )
return a;
if ( a.fej == a.veg )
{
free(a.fej);
a.fej= a.veg= NULL;
return a;
}
a.fej= a.fej->kovetkezo;
free(a.fej->elozo);
a.fej->elozo= NULL;
return a;
}

struct klista vegerol_torol(struct klista a)


{
if ( a.veg == NULL )

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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;
}
}

void bejar_vegerol(struct klista a)


{
while ( a.veg )
{
printf("%d ", a.veg->adat);
a.veg= a.veg->elozo;
}
}

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;
}
}

Keress A keress muvelet

az egyirnyba lncolt listhoz hasonlan a bejrs vzn plhet fel:


struct klistaelem* keres(int x, struct klista a)
{
while ( a.fej )
{
if ( a.fej->adat == x )
return a.fej;

78

Kovcs Gyrgy
a.fej= a.fej->kovetkezo;
}
return NULL;
}

Csere A keress fggvny segtsgvel aztn nagyon knnyen megrhatjuk a csere muveletet:

void csere(int mit, int mire, struct klista a)


{
struct klistaelem* tmp= keres(mit, a);
if ( tmp != NULL )
tmp->adat= mire;
}

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;
}

Adott elem trlse


struct klista elem_torles(int mit, struct klista a)
{
struct klistelem* tmp= keres(mit, a);
if ( tmp == NULL )
return a;
if ( tmp == a.veg )
return elejerol_torol(a);
if ( tmp == a.fej )
return vegerol_torol(a);
tmp->elozo->kovetkezo= tmp->kovetkezo;
tmp->kovetkezo->elozo= tmp->elozo;
free(tmp);
return a;
}

Felszabadts A listt trlni megintcsak az egyirnyba lncolt listnl is alkalmazott stratgia szerint tudunk:

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

79

struct klista felszabadit(struct klista a)


{
struct klistaelem* tmp;
while ( a.fej )
{
tmp= a.fej->kovetkezo;
free(a.fej);
a.fej= a.fej->kovetkezo;
}
a.fej= a.veg= NULL;
return a;
}

Plda Az eddig megrt fggvnyeket teht az albbi mdon hasznlhatjuk:


struct klista a= {NULL, NULL};
a= elejere_beszur(4, a);
a= vegerol_torol(a);
bejar_elejerol(a);

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;
};

A ft egyetlen mutat reprezentlja, amely a fa gykr elemre mutat:

80

Kovcs Gyrgy

bra 1: ltalnos binris fa

struct faelem* gyoker= NULL;

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.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

81

struct faelem* gyoker= NULL;


gyoker= ujelem(5);
gyoker->bal= ujelem(2);
gyoker->bal->bal= ujelem(1);
gyoker->bal->jobb= ujelem(6);
gyoker->bal->jobb->jobb= ujelem(3);
gyoker->jobb= ujelem(0);
gyoker->jobb->jobb= ujelem(1);

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

Egy elem trlsnek menett elg algoritmikusan ismerni: a legegyszerubb

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 korbban felptett fa esetn az utbb megrt 4 fggvnyt az albbi mdon hasznlhatjuk:


preorder(gyoker);
inorder(gyoker);
postorder(gyoker);
gyoker->bal= felszabadit(gyoker->bal);
gyoker= felszabadit(gyoker);

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.

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

83

bra 2: Binris keresofa

Az algoritmus megvalstsa rekurzival:


struct faelem* beszur(int x, struct faelem* gyoker)
{
if ( gyoker == NULL )
return ujelem(x);
if ( gyoker->adat > x )
gyoker->bal= beszur(x, gyoker->bal);
if ( gyoker->adat < x )
gyoker->jobb= beszur(x, gyoker->jobb);
return gyoker;
}

A beszur fggvny felhasznlsval teht a beszrand 5 2 1 6 3 0 1 szmsorbl ppen a 2.


brn lthat ft pthetjk fel:
struct faelem* gyoker;
gyoker= beszur(5, gyoker);
gyoker= beszur(2, gyoker);
gyoker= beszur(1, gyoker);
gyoker= beszur(6, gyoker);
gyoker= beszur(3, gyoker);
gyoker= beszur(0, gyoker);
gyoker= beszur(1, gyoker);

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

bra 3: Levlelem trlse (a pirossal jellt rtkeket trltk)

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)

Adatszerkezetek s algoritmusok - gyakorlati jegyzet

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

Knyvkiad, Budapest, HU, ISBN: 963 16 3029 3.

Anda mungkin juga menyukai