Információs Technológia Sor és verem adatszerkezet Fodor Attila Pannon Egyetem Műszaki Informatikai Kar Villamosmérnöki és Információs Rendszerek Tanszék foa@almos.vein.hu 2009. november 19.
Alapötlet Sor adatszerkezet Sor adatszerkezet Az egymás után beírt adatokat a beírás sorrendjében vehetjük ki FIFO - First In First Out Például: Eszközök közötti átvitel biztosítása Az érkező adatok feldolgozási sorrendje fontos, de azokat bizonyos esetekben nem tudnánk folyamatosan feldolgozni ezért eltároljuk Billentyűzet kezelése, I/O műveletek (File kezelés/file rendszer), Memória kezelés Értelmezhető utasítások IN Egy elemet betesz a sorba Ha megtelt a sor hibaüzenetet kell adni OUT Kiveszi a sor következő elemét Ha a sor üres akkor hibaüzenet, vagy olyan adatot adunk vissza ami nem fordulhat elő egyébként (pl.: NULL) EMPTY - Leelenőrzi, hogy tartalmaz-e adatot a sor FULL - Leelenőrzi, hogy megtelt-e a sor Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 2 / 41
Sor megvalósítása Sor adatszerkezet Sor adatszerkezet Statikus adatokkal Egy 1 dimenziós tömb Adatok tárolása Index (szám érték) Következő üres elemre mutat Sor elejére mutat Pointerekkel Egy 1 dimenziós mutatótömbbel Adatokra mutató mutatók tárolása Mutatók Következő üres elemre mutat Sor elejére mutat Speciálisan kezelt láncolt listával Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 3 / 41
FIFO megvalósítása Sor adatszerkezet Sor adatszerkezet megvalósítása Adatszerkezet az adatok eltárolására #define MAX_MEMBER 10 typedef struct int First, Last; int v[max_member]; FIFO_TYPE; FIFO adatszerkezet inicializálása void FIFO_init(FIFO_TYPE *fifo) fifo->first = 0; fifo->last = 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 4 / 41
FIFO megvalósítása Sor adatszerkezet Sor adatszerkezet megvalósítása Új adat sorba való berakása int FIFO_in(FIFO_TYPE *fifo, int data) if (fifo->last == MAX_MEMBER) return 1; fifo->v[fifo->last] = data; fifo->last++; return 0; Adat sorból való kivétele int FIFO_out(FIFO_TYPE *fifo, int *data) if (fifo->first == fifo->last) return 1; *data = fifo->v[fifo->first]; fifo->first++; return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 5 / 41
FIFO megvalósítása Sor adatszerkezet Sor adatszerkezet megvalósítása Sor első tagjának megtekintése int FIFO_lookfirst(FIFO_TYPE *fifo, int *data) if (fifo->first == fifo->last) return 1; *data = fifo->v[fifo->first]; return 0; Sor ürességének tesztelése int FIFO_empty(FIFO_TYPE *fifo) return (fifo->last == fifo->first)?1:0; Megtelt-e a sor int FIFO_full(FIFO_TYPE *fifo) return (fifo->last == MAX_MEMBER)?1:0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 6 / 41
FIFO használata Sor adatszerkezet Sor adatszerkezet megvalósítása Adatszerkezet függvényeinek meghívása FIFO_TYPE fifo; int i, j; FIFO_init(&fifo); for(i=0; i<15; i++) FIFO_in(&fifo, i); for(i=0; i<15; i++) if (!FIFO_out(&fifo, &j)) printf("%d ", j); Futás eredménye 0 1 2 3 4 5 6 7 8 9 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 7 / 41
FIFO használata Sor adatszerkezet Sor adatszerkezet megvalósítása Adatszerkezet függvényeinek meghívása FIFO_TYPE fifo; int i, j; FIFO_init(&fifo); for(i=0; i<5; i++) FIFO_in(&fifo, i); for(i=0; i<15; i++) if (!FIFO_out(&fifo, &j)) printf("%d ", j); for(i=0; i<15; i++) FIFO_in(&fifo, i); for(i=0; i<15; i++) if (!FIFO_out(&fifo, &j)) printf("%d ", j); Futás eredménye 0 1 2 3 4 0 1 2 3 4 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 8 / 41
Sor adatszerkezet FIFO használata (problémák) Sor adatszerkezet megvalósítása Probléma a sor ilyen kezelésénél Sok adat ki és berakása esetén: A sor elején üresek a tömb mezői Ha a sor végére érünk nem tudunk további adatot berakni Megoldás Ha nincsen adat a sorban, akkor visszaáll a 0 értékre Nem biztos, hogy kiürül a sor Ez csak félmegoldás Az adatszerkezet ciklikus módon történő kezelése Ha a végére értünk a tömbnek, akkor azt az elejétől kezdjük feltölteni. Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 9 / 41
Sor adatszerkezet FIFO megvalósítása (ciklikus módon) Sor adatszerkezet megvalósítása ciklikus módon Adatszerkezet az adatok eltárolására typedef struct int First, Last, N; int v[max_member]; cfifo_type; FIFO adatszerkezet inicializálása void cfifo_init(cfifo_type *fifo) fifo->first = 0; fifo->last = 0; fifo->n = 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 10 / 41
Sor adatszerkezet FIFO megvalósítása (ciklikus módon) Sor adatszerkezet megvalósítása ciklikus módon Új adat sorba való berakása int cfifo_in(cfifo_type *fifo, int data) if (fifo->n == MAX_MEMBER) return 1; if (fifo->last == MAX_MEMBER-1) fifo->v[fifo->last] = data; fifo->last = 0; else fifo->v[fifo->last] = data; fifo->last++; fifo->n++; return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 11 / 41
Sor adatszerkezet FIFO megvalósítása (ciklikus módon) Sor adatszerkezet megvalósítása ciklikus módon Adat sorból való kivétele int cfifo_out(cfifo_type *fifo, int *data) if (fifo->n == 0) return 1; *data = fifo->v[fifo->first]; if (fifo->first == MAX_MEMBER-1) fifo->first=0; else fifo->first++; fifo->n--; return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 12 / 41
Sor adatszerkezet FIFO megvalósítása (ciklikus módon) Sor első tagjának megtekintése int cfifo_lookfirst(cfifo_type *fifo, int *data) if (!fifo->n) return 1; *data = fifo->v[fifo->first]; return 0; Sor ürességének tesztelése int cfifo_empty(cfifo_type *fifo) return fifo->n?1:0; Megtelt-e a sor int cfifo_full(cfifo_type *fifo) return (fifo->n == MAX_MEMBER)?1:0; Sor adatszerkezet megvalósítása ciklikus módon Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 13 / 41
Sor adatszerkezet Ciklikus módon kezelt FIFO használata Sor adatszerkezet megvalósítása ciklikus módon Adatszerkezet függvényeinek meghívása int i, j; cfifo_type cfifo; cfifo_init(&cfifo); for(i=0; i<5; i++) cfifo_in(&cfifo, i); for(i=0; i<15; i++) if (!cfifo_out(&cfifo, &j)) printf("%d ", j); for(i=0; i<15; i++) cfifo_in(&cfifo, i); for(i=0; i<15; i++) if (!cfifo_out(&cfifo, &j)) printf("%d ", j); Futás eredménye 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 14 / 41
Sor adatszerkezet Sor adatszerkezet megvalósítására használható struktúrák Sor adatszerkezet megvalósítására használható struktúrák Az adatok helyet adatokra mutató mutató alkalmazása (tömbbe szervezve) typedef struct int First, Last, N; void *v[max_member]; cfifo_type_pointer; Az adatok helyet adatokra mutató mutató alkalmazása (tömbbe szervezve) Index helyett mutató alkalmazása (kezdő és a vég elemre mutat) typedef struct void *First, *Last; unsigned long int N; void *v[max_member]; cfifo_type_pointer2; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 15 / 41
Sor adatszerkezet FIFO megvalósítása (láncolt listával) Sor adatszerkezet megvalósítása láncolt listával Kettő megvalósítási filozófia 1. Filozófia A lista végére rakjuk az új adatot A lista elejéröl vesszük ki az adatot 2. Filozófia A lista elejére rakjuk az új adatot A lista végéről vesszük ki az adatot Lista adattag struct lista_elem void *adat; struct lista_elem *kov; ; lista_elem *kezd; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 16 / 41
Sor adatszerkezet FIFO megvalósítása (láncolt listával - 1.) A lista végére rakjuk az új adatot Sor adatszerkezet megvalósítása láncolt listával lista_elem* beszur_vege(lista_elem **kezd, int ujadat) lista_elem *uj, *akt; if (*kezd == NULL) *kezd = (lista_elem*) malloc(sizeof(lista_elem)); if (*kezd == NULL) return NULL; (*kezd)->adat = ujadat; (*kezd)->kov = NULL; return *kezd; else akt = *kezd; while (akt->kov!= NULL) akt = akt->kov; uj = (lista_elem*) malloc(sizeof(lista_elem)); if (uj == NULL) return NULL; akt->kov = uj; uj->kov = NULL; uj->adat = ujadat; return uj; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 17 / 41
Sor adatszerkezet FIFO megvalósítása (láncolt listával - 1.) Sor adatszerkezet megvalósítása láncolt listával A lista elejéről vesszük ki az adatot int torol_eleje(lista_elem **kezd, int *adat) lista_elem *del; if (*kezd == NULL) return -1; else del = *kezd; *kezd = (*kezd)->kov; *adat = del->adat; free(del); return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 18 / 41
Sor adatszerkezet Sor adatszerkezet megvalósítása láncolt listával Láncolt listával (1. filozófia) felépített FIFO használata Adatszerkezet függvényeinek meghívása lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) beszur_vege(&kezd, i); for(i=0; i<20; i++) if (!torol_eleje(&kezd, &j)) printf("%d ", j); Futás eredménye 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 19 / 41
Sor adatszerkezet FIFO megvalósítása (láncolt listával - 2.) Sor adatszerkezet megvalósítása láncolt listával A lista elejére szurjuk be az új adatot lista_elem* beszur_eleje(lista_elem **kezd, int ujadat) lista_elem *uj; if (*kezd == NULL) *kezd = (lista_elem*) malloc(sizeof(lista_elem)); if (*kezd == NULL) return NULL; (*kezd)->adat = ujadat; (*kezd)->kov = NULL; else uj = (lista_elem*) malloc(sizeof(lista_elem)); if (uj == NULL) return NULL; uj->kov = *kezd; *kezd = uj; uj->adat = ujadat; return uj; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 20 / 41
Sor adatszerkezet FIFO megvalósítása (láncolt listával - 2.) A lista végéről vesszük ki az adatot Sor adatszerkezet megvalósítása láncolt listával int torol_vege(lista_elem **kezd, int *adat) lista_elem *del, *ujveg; if (*kezd == NULL) return -1; else del = *kezd; ujveg = NULL; while (del->kov!= NULL) ujveg = del; del = del->kov; if (ujveg!= NULL) ujveg->kov = NULL; else *kezd = NULL; *adat = del->adat; free(del); return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 21 / 41
Sor adatszerkezet Sor adatszerkezet megvalósítása láncolt listával Láncolt listával (2. filozófia) felépített FIFO használata Adatszerkezet függvényeinek meghívása lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) beszur_eleje(&kezd, i); for(i=0; i<20; i++) if (!torol_vege(&kezd, &j)) printf("%d ", j); Futás eredménye 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 22 / 41
Sor adatszerkezet Láncolt listával felépített FIFO Sor adatszerkezet megvalósítása láncolt listával Kettő megvalósítási filozófia 1. Filozófia A lista végére rakjuk az új adatot A lista elejéröl vesszük ki az adatot 2. Filozófia A lista elejére rakjuk az új adatot A lista végéről vesszük ki az adatot Példa #ifdef LISTA_FILOZOFIA_1 #define LISTABA beszur_vege #define LISTABOL torol_eleje #else #define LISTABA beszur_eleje #define LISTABOL torol_vege #endif lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) LISTABA(&kezd, i); for(i=0; i<20; i++) if (!LISTABOL(&kezd, &j)) printf("%d ", j); Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 23 / 41
Alapötlet Verem adatszerkezet Verem adatszerkezet Az egymás után beírt adatokat fordított sorrendben vehetjük ki A veremből mindig az utoljára bevitt adatot vehetjük ki először LIFO - Last In First Out Stack Alkalmazása például: Programokban a függvények meghívásakor Operációs rendszer, hardware Megszakítások (INT), eljárás hívás (CALL) Értelmezhető utasítások PUSH Egy elemet betesz a verembe Ha megtelt hibaüzenetet kell adni POP Kiveszi az utolsónak berakott elemet Ha a üres a verem akkor hibaüzenet, vagy olyan adatot adunk vissza ami nem fordulhat elő egyébként (pl.: NULL) EMPTY - Leelenőrzi, hogy tartalmaz-e adatot a verem FULL - Leelenőrzi, hogy megtelt-e a verem Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 24 / 41
Verem megvalósítása Verem adatszerkezet Verem adatszerkezet Statikus adatokkal Egy 1 dimenziós tömb Adatok tárolása Indexek (szám érték) Következő üres elemre mutat Pointerekkel Egy 1 dimenziós mutatótömbbel Adatokra mutató mutatók tárolása Mutatók Következő üres elemre mutat Speciálisan kezelt láncolt listával Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 25 / 41
LIFO megvalósítása Verem adatszerkezet Verem adatszerkezet Adatszerkezet az adatok eltárolására #define MAX_MEMBER 10 typedef struct int top; int v[max_member]; LIFO_TYPE; LIFO adatszerkezet inicializálása void LIFO_init(LIFO_TYPE *lifo) lifo->top = 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 26 / 41
LIFO megvalósítása Verem adatszerkezet Verem adatszerkezet PUSH - Új adat verembe való berakása int LIFO_push(LIFO_TYPE *lifo, int data) if (lifo->top == MAX_MEMBER) return 1; lifo->v[lifo->top] = data; lifo->top++; return 0; POP - Adat veremből való kivétele int LIFO_pop(LIFO_TYPE *lifo, int *data) if (!lifo->top) return 1; *data = lifo->v[lifo->top-1]; lifo->top--; return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 27 / 41
LIFO megvalósítása Verem adatszerkezet Verem adatszerkezet Verem felső tagjának megtekintése int LIFO_lookfirst(LIFO_TYPE *lifo, int *data) if (!lifo->top) return 1; *data = lifo->v[lifo->top-1]; return 0; Verem ürességének tesztelése int LIFO_empty(LIFO_TYPE *lifo) return (lifo->top==0)?1:0; Megtelt-e a verem int LIFO_full(LIFO_TYPE *lifo) return (lifo->top == MAX_MEMBER)?1:0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 28 / 41
LIFO megvalósítása Verem adatszerkezet Verem adatszerkezet Adatszerkezet függvényeinek meghívása int i, j; LIFO_TYPE lifo; LIFO_init(&lifo); for(i=0; i<15; i++) LIFO_push(&lifo, i); for(i=0; i<15; i++) if (!LIFO_pop(&lifo, &j)) printf("%d ", j); Futás eredménye 9 8 7 6 5 4 3 2 1 0 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 29 / 41
Verem adatszerkezet LIFO megvalósítása (láncolt listával) Verem adatszerkezet megvalósítása láncolt listával Kettő megvalósítási filozófia 1. Filozófia A lista elejére rakjuk az új adatot A lista elejéről vesszük ki az adatot 2. Filozófia A lista végére rakjuk az új adatot A lista végéről vesszük ki az adatot Lista adattag struct lista_elem void *adat; struct lista_elem *kov; ; lista_elem *kezd; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 30 / 41
Verem adatszerkezet LIFO megvalósítása (láncolt listával - 1.) Verem adatszerkezet megvalósítása láncolt listával A lista elejére rakjuk be az új adatot lista_elem* beszur_eleje(lista_elem **kezd, int ujadat) lista_elem *uj; if (*kezd == NULL) *kezd = (lista_elem*) malloc(sizeof(lista_elem)); if (*kezd == NULL) return NULL; (*kezd)->adat = ujadat; (*kezd)->kov = NULL; else uj = (lista_elem*) malloc(sizeof(lista_elem)); if (uj == NULL) return NULL; uj->kov = *kezd; *kezd = uj; uj->adat = ujadat; return uj; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 31 / 41
Verem adatszerkezet LIFO megvalósítása (láncolt listával - 1.) Verem adatszerkezet megvalósítása láncolt listával A lista elejéről vesszük ki az adatot int torol_eleje(lista_elem **kezd, int *adat) lista_elem *del; if (*kezd == NULL) return -1; else del = *kezd; *kezd = (*kezd)->kov; *adat = del->adat; free(del); return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 32 / 41
Verem adatszerkezet Verem adatszerkezet megvalósítása láncolt listával Láncolt listával (1. filozófia) felépített LIFO használata Adatszerkezet függvényeinek meghívása lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) beszur_eleje(&kezd, i); for(i=0; i<20; i++) if (!torol_eleje(&kezd, &j)) printf("%d ", j); Futás eredménye 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 33 / 41
Verem adatszerkezet Verem adatszerkezet megvalósítása láncolt listával Láncolt listával (1. filozófia) felépített LIFO használata Adatszerkezet függvényeinek meghívása #define PUSH #define POP beszur_eleje torol_eleje lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) PUSH(&kezd, i); for(i=0; i<20; i++) if (!POP(&kezd, &j)) printf("%d ", j); Futás eredménye 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 34 / 41
Verem adatszerkezet LIFO megvalósítása (láncolt listával - 2.) A lista végére rakjuk az új adatot Verem adatszerkezet megvalósítása láncolt listával lista_elem* beszur_vege(lista_elem **kezd, int ujadat) lista_elem *uj, *akt; if (*kezd == NULL) *kezd = (lista_elem*) malloc(sizeof(lista_elem)); if (*kezd == NULL) return NULL; (*kezd)->adat = ujadat; (*kezd)->kov = NULL; return *kezd; else akt = *kezd; while (akt->kov!= NULL) akt = akt->kov; uj = (lista_elem*) malloc(sizeof(lista_elem)); if (uj == NULL) return NULL; akt->kov = uj; uj->kov = NULL; uj->adat = ujadat; return uj; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 35 / 41
Verem adatszerkezet LIFO megvalósítása (láncolt listával - 2.) A lista végéről vesszük ki az adatot Verem adatszerkezet megvalósítása láncolt listával int torol_vege(lista_elem **kezd, int *adat) lista_elem *del, *ujveg; if (*kezd == NULL) return -1; else del = *kezd; ujveg = NULL; while (del->kov!= NULL) ujveg = del; del = del->kov; if (ujveg!= NULL) ujveg->kov = NULL; else *kezd = NULL; *adat = del->adat; free(del); return 0; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 36 / 41
Verem adatszerkezet Verem adatszerkezet megvalósítása láncolt listával Láncolt listával (2. filozófia) felépített LIFO használata Adatszerkezet függvényeinek meghívása lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) beszur_vege(&kezd, i); for(i=0; i<20; i++) if (!torol_vege(&kezd, &j)) printf("%d ", j); Futás eredménye 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Nem praktikus a használata (listán végig kell menni) Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 37 / 41
Verem adatszerkezet Láncolt listával felépített verem Verem adatszerkezet megvalósítása láncolt listával Kettő megvalósítási filozófia 1. Filozófia A lista elejére rakjuk az új adatot A lista elejéről vesszük ki az adatot 2. Filozófia A lista végére rakjuk az új adatot A lista végéről vesszük ki az adatot Példa #ifdef LISTA_FILOZOFIA_1 #define Push beszur_eleje #define Pop torol_eleje #else #define Push beszur_vege #define Pop torol_vege #endif lista_elem *kezd; kezd = NULL; for(i=0; i<15; i++) Push(&kezd, i); for(i=0; i<20; i++) if (!Pop(&kezd, &j)) printf("%d ", j); Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 38 / 41
Lineáris keresés Kereső algoritmusok Velétlenszerűen elhelyezkedő adatokban Első adattól indul a keresés Végignézi az összes adatot int lin_keres(int v[], int n, int mit) int i; for(i=0; (i<n)&& (v[i]!= mit); i++ ); if (i == n) return -1; if (v[i]!= mit) return -1; return i; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 39 / 41
Lineáris keresés Kereső algoritmusok Rendezett adatokban Első adattól indul a keresés Végignézi az összes adatot, ameddig azok kisebbek, mint a keresendő int lin_keres(int v[], int n, int mit) int i; for(i=0; (i<n)&& (v[i] < mit); i++ ); if (i == n) return -1; if (v[i]!= mit) return -1; return i; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 40 / 41
Bináris keresés Kereső algoritmusok Rendezett adatokban Folyamatosan felezi az intervallumot, melyben keres Végignézi az összes adatot, ameddig azok kisebbek, mint a keresendő A keresés az elemszammal log 2 N kapcsolatban van int bin_keres(int v[], int Also, int Felso, int mit) int Kozepso; Kozepso = int ((Also+Felso)/2); while ((Also <= Felso) && (v[kozepso]!= mit)) if (v[kozepso] > mit) Felso = Kozepso-1; else Also = Kozepso+1; Kozepso = int ((Also+Felso)/2); if (v[kozepso] == mit) return Kozepso; else return -1; Fodor A. (Pannon Egyetem) Információs technológia 2009. november 19. 41 / 41