mirror of
https://github.com/TMD44/elte-ik-pti-bsc-zarovizsga.git
synced 2025-08-11 21:39:05 +02:00
537 lines
33 KiB
TeX
537 lines
33 KiB
TeX
\documentclass[margin=0px]{article}
|
||
|
||
\usepackage{listings}
|
||
\usepackage[utf8]{inputenc}
|
||
\usepackage{graphicx}
|
||
\usepackage{float}
|
||
\usepackage[a4paper, margin=0.7in]{geometry}
|
||
\usepackage{amsthm}
|
||
\usepackage{amssymb}
|
||
\usepackage{amsmath}
|
||
\usepackage{fancyhdr}
|
||
\usepackage{pdfpages}
|
||
\usepackage{setspace}
|
||
|
||
\onehalfspacing
|
||
|
||
\newenvironment{tetel}[1]{\paragraph{#1 \\}}{}
|
||
\renewcommand{\figurename}{ábra}
|
||
\makeatletter
|
||
\renewcommand\paragraph{%
|
||
\@startsection{paragraph}{4}{0mm}%
|
||
{-\baselineskip}%
|
||
{.5\baselineskip}%
|
||
{\normalfont\normalsize\bfseries}}
|
||
\makeatother
|
||
|
||
\pagestyle{fancy}
|
||
\lhead{\it{PTI BSc Záróvizsga tételek}}
|
||
\rhead{7. Programozás}
|
||
|
||
\title{\textbf{{\Large ELTE IK - Programtervező Informatikus BSc} \vspace{0.2cm} \\ {\huge Záróvizsga tételek}} \vspace{0.3cm} \\ 7. Programozás}
|
||
\author{}
|
||
\date{}
|
||
|
||
\begin{document}
|
||
\maketitle
|
||
|
||
\begin{tetel}{Programozás}
|
||
A felsoroló fogalma. Nevezetes gyűjtemények (intervallum, tömb, sorozat, szekvenciális inputfájl) felsorolói. Felsorolóra megfogalmazott programozási tételek (összegzés, számlálás, maximum kiválasztás, feltételes maximumkeresés, lineáris keresés, kiválasztás). A visszavezetés módszere. Programozási tételekkel készült programok tesztelése.
|
||
\end{tetel}
|
||
|
||
\section{Egyszerű programozási feladat megoldásának lépései}
|
||
\subsection{Bevezetés}
|
||
Egy programozási feladat megoldása a kódoláson túl jó néhány tevékenységet tartalmaz.
|
||
Az első teendő a feladat pontos meghatározása, a specifikáció. Ez a feladat szöveges és formalizált, matematikai leírásán (a specifikáció ún. szűkebb értelmezésén) túl tartalmazza a megoldással szemben támasztott követelményeket, környezeti igényeket is (ami a specifikáció ún. tágabb értelmezése).
|
||
|
||
A specifikáció alapján meg lehet tervezni a programot, elkészülhet a megoldás algoritmusa és az algoritmus által használt adatok leírása. Az algoritmus és az adatszerkezet finomítása egymással párhuzamosan halad, egészen addig a szintig, amelyet a programozó ismeretei alapján már könnyen, hibamentesen képes kódolni. Gyakran előfordul, hogy a tervezés során derül fény a specifikáció hiányosságaira, így itt visszalépésekre számíthatunk.
|
||
|
||
Az algoritmusírás után következhet a kódolás. Ha a feladat kitűzője nem rögzítette, akkor ez előtt választhatunk a megoldáshoz programozási nyelvet. A kódolás eredménye a programozási nyelven leírt program.
|
||
|
||
A program első változatban általában sohasem hibátlan, a helyességéről csak akkor beszélhetünk, ha meggyőződtünk róla. A helyesség vizsgálatának egyik lehetséges módszere a tesztelés. Ennek során próbaadatokkal próbáljuk ki a programot, s az ezekre adott eredményből következtetünk a helyességre. (Ne legyenek illúzióink afelől, hogy teszteléssel eldönthető egy program helyessége. Hisz hogy valójában helyes-e a program – sajnos – nem következik abból, hogy nem találtunk hibát.)
|
||
|
||
Ha a tesztelés során hibajelenséggel találkozunk, akkor következhet a hibakeresés, a hibajelenséget okozó utasítás megtalálása, majd pedig a hibajavítás. A hiba kijavítása több fázisba is visszanyúlhat. Elképzelhető, hogy kódolási hibát kell javítanunk, de az is lehet, hogy a hibát már a tervezésnél követtük el. Javítás után újra tesztelni kell, hiszen – legyünk őszinték magunkhoz!– nem kizárt, hogy hibásan javítunk, illetőleg – enyhe optimizmussal állítjuk:– a javítás újabb hibákat fed fel, ...
|
||
|
||
E folyamat végeredménye a helyes program. Ezzel azonban még korántsem fejeződik be a programkészítés. Most következnek a minőségi követelmények. Egyrészt a hatékonyságot kell vizsgálnunk (végrehajtási idő, helyfoglalás), másrészt a kényelmes használhatóságot. Itt újra visszaléphetünk a kódolási, illetve a tervezési fázisba is. Ezzel elérkeztünk a jó programhoz.
|
||
|
||
\subsection{Specifikáció}
|
||
A programkészítés menetének első lépése a feladat meghatározása, precíz "újrafogalmazása". Milyen is legyen, mit várjunk el tőle? Nézzünk meg néhány – jónak tűnő – követelményt egyelőre címszavakban! (A továbbiakban a specifikáció szűkebb értelmezéséről lesz szó.) A specifikáció legyen:
|
||
|
||
\begin{itemize}
|
||
\item helyes, egyértelmű, pontos, teljes
|
||
\item rövid, tömör, ami legegyszerűbben úgy érhető el, hogy ismert formalizmusokra építjük
|
||
\item szemléletes, érthető (amit időnként nehezít a formalizáltság)
|
||
\end{itemize}
|
||
|
||
A specifikáció első közelítésben lehetne a feladatok szövege. Ez azonban több problémát vethet fel:
|
||
|
||
\begin{itemize}
|
||
\item mi alapján adjuk meg a megoldást
|
||
\item mit is kell pontosan megadni?
|
||
\end{itemize}
|
||
|
||
Például az a feladat, hogy adjuk meg N ember közül a legmagasabbat. A legmagasabb ember megadása mit jelent? Adjuk meg a sorszámát, vagy a nevét, vagy a személyi számát, vagy a magasságát, esetleg ezek közül mindegyiket?
|
||
Tanulságként megállapíthatjuk, hogy a specifikációnak tartalmaznia kell a bemenő és a kimenő adatok leírását.
|
||
|
||
\begin{verbatim}
|
||
Bemenet:
|
||
N : az emberek száma,
|
||
A : a magasságukat tartalmazó sorozat.
|
||
|
||
Kimenet:
|
||
MAX : a legmagasabb ember sorszáma.
|
||
\end{verbatim}
|
||
|
||
|
||
Tudjuk-e, hogy a bemenő, illetve a kimenő változók milyen értéket vehetnek fel? Például az emberek magasságát milyen mértékegységben kell megadni? Az eredményül kapott sorszám milyen érték lehet: 1-től sorszámozunk, vagy 0-tól? Megállapíthatjuk tehát, hogy a specifikációban a bemeneti és a kimeneti változók értékhalmazát is meg kell adnunk.
|
||
|
||
\begin{verbatim}
|
||
Bemenet:
|
||
N : az emberek száma, természetes szám;
|
||
A : a magasságukat tartalmazó sorozat, egész számok, amelyek a magasságot
|
||
centiméterben fejezik ki (a sorozatot 1-től N-ig indexeljük).
|
||
Kimenet:
|
||
MAX : a legmagasabb ember sorszáma, 1 és N közötti természetes szám.
|
||
\end{verbatim}
|
||
|
||
Most már a bemenő és a kimenő változók értékhalmazát pontosan meghatároztuk, csupán az a probléma, hogy a feladatban használt fogalmakat és az eredmények kiszámítási szabályát nem definiáltuk. A specifikációnak tehát tartalmaznia kell a feladatban használt fogalmak definícióját, valamint az eredmény kiszámítási szabályát. Itt lehetne megadni a bemenő adatokra vonatkozó összefüggéseket is. A bemenő, illetve a kimenő adatokra kirótt feltételeket nevezzük előfeltételnek, illetve utófeltételnek. Az előfeltétel nagyon sokszor egy azonosan igaz állítás, azaz a bemenő adatok értékhalmazát semmilyen "külön” feltétellel nem szorítjuk meg.
|
||
|
||
\begin{verbatim}
|
||
Bemenet:
|
||
N : az emberek száma, természetes szám,
|
||
A : a magasságukat tartalmazó sorozat, egész számok,
|
||
amelyek a magasságot centiméterben tartalmazzák (a sorozatot 1-tol N-ig indexeljük).
|
||
Kimenet:
|
||
MAX : a legmagasabb ember sorszáma, 1 és N közötti természetes szám.
|
||
|
||
Elofeltétel:
|
||
A[i]-k pozitívak.
|
||
|
||
Utófeltétel:
|
||
MAX olyan 1 és N közötti szám, amelyre A[MAX] nagyobb vagy egyenlo,
|
||
mint a sorozat bármely eleme (az 1. és az N. között).
|
||
\end{verbatim}
|
||
|
||
Újabb probléma merülhet fel bármelyik feladattal kapcsolatban: az eddigiek alapján a "várttól” lényegesen különböző – nyugodtan állíthatjuk: "banális” –, az elő- és utófeltételnek megfelelő megoldást is tudunk készíteni.
|
||
|
||
Itt persze arról a hallgatólagos (tehát még meg nem fogalmazott, ki nem mondott) feltételezésről van szó, hogy a bemeneti változók értéke nem változik meg. Ez sajnos nem feltétlenül igaz. A probléma megoldására kétféle utat követhetünk (a későbbiekben mindkettőt alkalmazni fogjuk):
|
||
|
||
\begin{itemize}
|
||
\item az utófeltételbe automatikusan beleértjük, hogy "és a bemeneti változók értéke nem változik meg”, s külön kiemeljük, ha mégsem így van;
|
||
\item az elő- és az utófeltételt a program paramétereire fogalmazzuk meg, amelyeket formailag megkülönböztetünk a program változóitól, és emiatt nem a paraméterek fognak változni, hanem a programbeli változók (ebben az esetben természetesen az elő- és az utófeltételben meg kell fogalmazni a paraméterek és a megfelelő programbeli változók értékének azonosságát).
|
||
\end{itemize}
|
||
|
||
A második megoldásból az következik, hogy meg kell különböztetnünk egymástól a feladat és a program elő–, illetve utófeltételét! Ez hosszadalmasabbá – bár precízebbé – teszi a feladat megfogalmazását, emiatt ritkábban fogjuk alkalmazni.
|
||
|
||
Előfordulhat, hogy a feladat megfogalmazása alapján nem lehet egyértelműen meghatározni az eredményt, ugyanis az utófeltételnek megfelelő több megoldás is létezik. Ez a jelenség a feladat ún. nemdeterminisztikussága. Ehhez a nemdeterminisztikus feladathoz tehát determinisztikus programot kell írnunk, aminek az utófeltétele már nem engedheti meg a nem egyértelműséget, a nemdeterminisztikusságot. E probléma miatt tehát mindenképpen meg kell különböztetnünk egymástól a feladat és a program elő–, illetve utófeltételét!
|
||
|
||
\begin{verbatim}
|
||
Bemenet:
|
||
N : az emberek száma, természetes szám,
|
||
A : a magasságukat tartalmazó sorozat, egész számok,
|
||
amelyek a magasságot centiméterben tartalmazzák (a sorozatot 1-tol N-ig indexeljük).
|
||
Kimenet:
|
||
MAX : a legmagasabb ember sorszáma, 1 és N közötti természetes szám.
|
||
|
||
Elofeltétel:
|
||
A[i]-k pozitívak.
|
||
|
||
Utófeltétel:
|
||
MAX olyan 1 és N közötti szám, amelyre A[MAX] nagyobb vagy egyenlo,
|
||
mint a sorozat bármely eleme (az 1. és az N. között).
|
||
|
||
Program utófeltétel:
|
||
MAX olyan 1 és N közötti szám, amelyre A[MAX] nagyobb vagy egyenlo,
|
||
mint a sorozat bármely eleme (az 1. és az N. között) és elotte
|
||
nincs vele egyenlo.
|
||
\end{verbatim}
|
||
|
||
Megállapíthatjuk ebből, hogy a program utófeltétele lehet szigorúbb, mint a feladaté, emellett az előfeltétele pedig lehet gyengébb.
|
||
|
||
Visszatekintve a specifikáció eddig "bejárt pályájára” egy szemléletes modellje körvonalazódik a feladatmegoldásnak. Nevezetesen: nyugodtan mondhatjuk azt, hogy a feladatot megoldó program egy olyan automatát határoz meg, amelynek pillanatnyi állapota a feladat paraméterei (a program változói) által "kifeszített” halmaz egy eleme. (E halmaz annyi dimenziós, ahány paraméterváltozója van a programnak; minden dimenzió egyik változó értékhalmaza. Tehát egy konkrét időpillanatban e "gép” állapota: a változóinak abban a pillanatban érvényes értékeinek együttese.) Ezt a halmazt nevezzük a program állapotterének. Amikor megfogalmazzuk az előfeltételt, akkor tulajdonképpen kihasítjuk ebből az állapottérből azt a részt (azt az altért), amelyből indítva elvárhatjuk az automatánktól (amit a megoldó program vezérel), hogy a helyes eredményt előállítja egy végállapotában. A végállapotot jelöltük ki az utófeltétellel.
|
||
|
||
Ezt a modellt elfogadva adódik még egy további megoldásra váró kérdés. Akkor ugyanis, amikor a programot írjuk, lépten-nyomon a részeredmények tárolására újabb és újabb változókat vezetünk be. Fölvetődik a kérdés: hogyan egyeztethető össze az imént elképzelt modellel? A válasz egyszerű: minden egyes újabb változó egy újabb dimenziót illeszt az eddig létrejött állapottérhez. Tehát a programozás folyamata – leegyszerűsítve a dolgot – nem áll másból, mint annak pontosításából, hogy hogyan is nézzen ki a megoldó automata állapottere (és persze: hogyan kell az egyik állapotból a másik állapotba jutnia). A feladatban szereplő paraméterek meghatározta "embrionális” állapotteret hívhatjuk paramétertérnek, ami csak altere a program valódi állapotterének. Ez is azt sugallja, hogy a feladat előfeltétele gyengébb (azaz az általa kijelölt állapothalmaz) lehet, mint a program előfeltétele.
|
||
|
||
Foglaljuk most össze, hogy melyek a specifikáció részei! Ezek az eddigiek, valamint a programra vonatkozó további megkötések lesznek.
|
||
|
||
\begin{enumerate}
|
||
\item A feladat specifikálása
|
||
\begin{itemize}
|
||
\item a feladat szövege,
|
||
\item a bemenő és a kimenő adatok elnevezése, értékhalmazának leírása,
|
||
\item a feladat szövegében használt fogalmak definíciói (a fogalmak fölhasználásával),
|
||
\item a bemenő adatokra felírt előfeltétel (a fogalmak fölhasználásával),
|
||
\item a kimenő adatokra felírt utófeltétel.
|
||
\end{itemize}
|
||
\item A program specifikálása
|
||
\begin{itemize}
|
||
\item a bemenő és a kimenő adatok elnevezése, értékhalmazának leírása,
|
||
\item (a feladat elő-, illetve utófeltételétől esetleg különböző) program elő- és utófeltétel,
|
||
\item a feladat megfogalmazásában használt fogalmak definíciói.
|
||
\end{itemize}
|
||
\end{enumerate}
|
||
|
||
\noindent Ezek az absztrakt specifikáció elemei. Az alábbiak másodlagos, mondhatjuk: technikai specifikáció részei:
|
||
|
||
\begin{itemize}
|
||
\item a program környezetének leírása (számítógép, memória- és perifériaigény, programozási nyelv, szükséges fájlok stb.),
|
||
\item a programmal szembeni egyéb követelmények (minőség, hatékonyság, hordozhatóság stb.).
|
||
\end{itemize}
|
||
|
||
\noindent A technikai specifikáció nélküli leírást a program szűkebb specifikációjának nevezik.\\
|
||
|
||
\noindent Progos specifikáció:\\\\
|
||
$A=(N : \mathbb{N}, A: \mathbb{N}^{1..N})$\\
|
||
$Ef=(\forall i \in {1..N} : A_{i}>0)$\\
|
||
$Uf=(Ef \land \forall i \in {1..N} : A_{MAX}>=A_{i} \land \forall j \in {1..MAX-1} : A_{i}<A_{MAX})$
|
||
|
||
\subsection{Tervezés}
|
||
|
||
A tervezés során algoritmusleíró eszközöket használunk, amelynek célja a feladatok megoldásának leírása programozási nyelvtől független nyelven. A programozási nyelvek ugyanis szigorú szintaxisúak, a tervezés szempontjából lényegtelen sallangokat tartalmaznak. A programozási nyelven történő tervezés esetén nehézzé válhat a program átírása más nyelvre, más gépre.
|
||
|
||
Többféle algoritmusleíró eszköz is létezik, mi tanulmányaink során a struktogramot alkalmaztuk.
|
||
|
||
A struktogram a programgráfot élek nélkül ábrázolja. Így egyetlen egy alapelem marad, a téglalap. Ezzel az alapelemmel építhetjük fel a szokásos strukturált alapszerkezeteket (és csak azokat).
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/stuki_alapszerk1}
|
||
\caption{A struktogram összetett alapszerkezetei.}
|
||
\label{fig:stuki_alapszerk1}
|
||
\end{figure}
|
||
|
||
Szekvenciánál a téglalapok egymás alatti sorrendje dönti el a végrehajtás sorrendjét. Az elágazásfeltétel igaz értéke esetén az i betűvel jelölt bal oldali téglalap utasítását kell végrehajtani, hamis értéke esetén pedig az n betűvel jelölt jobb oldali téglalapét. Ha az elágazás valamelyik ága üres, akkor a neki megfelelő téglalap is üres marad. A ciklus elöltesztelős, azaz a benne levő utasítást mindaddig végre kell hajtani, amíg a feltétel igaz.
|
||
|
||
Az utasítások helyén lehet egyetlen elemi utasítás, lehet a három algoritmikus szerkezet valamelyike, és lehet egy eljáráshívás. Ezt a leíróeszközt még többféle elemmel szokták bővíteni: az eljárásdefinícióval, a sokirányú elágazással, illetve a hátultesztelős ciklussal.
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/stuki_alapszerk2}
|
||
\caption{A struktogram további összetett alapszerkezetei.}
|
||
\label{fig:stuki_alapszerk2}
|
||
\end{figure}
|
||
|
||
\noindent Sokirányú elágazásnál azt az ágat kell végrehajtani, amelynek igaz értékű a feltétele (közülük minden esetben pontosan egy teljesülhet).\\
|
||
|
||
\noindent A lokális adatokat az eljárások téglalapjai mellett, az eljárásnév után sorolhatjuk fel.\\
|
||
|
||
\noindent Nézzük meg ezzel az eszközzel leírva a következő példát!\\
|
||
|
||
\noindent Feladat: N tanuló év végi átlagának ismeretében adjuk meg a jeles átlagú tanulók számát!
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.4\linewidth]{img/stuki_pelda}
|
||
\caption{A példafeladat megoldása struktogrammal.}
|
||
\label{fig:stuki_pelda}
|
||
\end{figure}
|
||
|
||
\subsection{Megvalósítás}
|
||
|
||
A.k.a. kódolás.
|
||
\subsection{Tesztelés}
|
||
A tesztelés célja, hogy minél több hibát megtaláljunk a programban. Ahhoz, hogy az összes hibát fölfedezzük, kézenfekvőnek tűnik a programot kipróbálni az összes lehetséges bemenő adattal. Ez azonban sajnos nem lehetséges.
|
||
|
||
\noindent Példaként tekintsük a következő - pszeudokóddal megadott - egyszerű programot:
|
||
|
||
\begin{verbatim}
|
||
Program:
|
||
Változó A,B:Egész
|
||
Be: A,B
|
||
Ki: A/B
|
||
Program vége.
|
||
\end{verbatim}
|
||
|
||
Mivel $2^{16}$ különböző értékű egész számot tudunk tárolni, ezért az összes lehetőség $2^{32}$, aminek a leírásához már 9 számjegyre van szükség. Ez rengeteg időt venne igénybe, így nem is járható út.
|
||
|
||
Ha ezt a programot olyan bemenő adatokkal próbáljuk ki, amelyben A=0 vagy B=1, akkor a program helyesen működik, a hibát nem tudjuk felfedezni. Ezután azt gondolhatnánk, hogy reménytelen helyzetbe kerültünk: hiszen minden lehetséges adattal nem tudjuk kipróbálni a programot; ha pedig kevesebbel próbáljuk ki, akkor lehet, hogy nem vesszük észre a hibákat. A helyzet azért nem ennyire rossz: célunk csak az lehet, hogy a tesztelést olyan módszerrel hajtsuk végre, amellyel a próbák száma erősen lecsökkenthető.\\
|
||
|
||
Tesztesetnek a be- és kimeneti adatok és feltételek együttes megadását nevezzük. Akkor tudunk a tesztelés eredményeiről bármit is mondani, ha van elképzelésünk arról, hogy adott bemenő adatra milyen eredményt várunk.\\
|
||
|
||
\noindent Fogalmazzuk meg a tesztelés alapelveit:
|
||
\begin{itemize}
|
||
\item A jó teszteset az, ami nagy valószínűséggel egy még felfedetlen hibát mutat ki a programban. Például két szám legnagyobb közös osztóját számoló programot az [5,5] adatpár után a [6,6]-tal teljesen felesleges kipróbálni (ugyanis igencsak rafinált, valószínűtlen elírás esetén viselkedhet a program [6,6]-ra másként, mint [5,5]-re).
|
||
|
||
\item A teszteset nemcsak bemenő adatokból, hanem a hozzájuk tartozó eredményekből is áll. Egyébként nem tudnánk a kapott eredmény helyes vagy hibás voltáról beszélni. A későbbi felhasználás miatt célszerű a teszteseteket is leírni a fejlesztői dokumentációban vagy egy önálló tesztelési jegyzőkönyvben.
|
||
|
||
\item A meg nem ismételhető tesztesetek kerülendők, feleslegesen megnövelik a program-tesztelés költségeit, idejét. Nem is beszélve arról a bosszúságról, amikor a programunk egy hibás futását nem tudjuk megismételni, és így a hiba is felfedetlen marad.
|
||
|
||
\item Teszteseteket mind az érvénytelen, mind az érvényes adatokra kell készíteni.
|
||
|
||
\item Minden tesztesetből a lehető legtöbb információt "ki kell bányászni”, azaz minden teszteset eredményét alaposan végig kell vizsgálni. Ezzel jelentősen csökkenthető a szükséges próbák száma.
|
||
|
||
\item Egy próba eredményeinek vizsgálata során egyaránt fontos megállapítani, hogy miért nem valósít meg a program valamilyen funkciót, amit elvárunk tőle, illetve hogy miért végez olyan tevékenységeket is, amelyeket nem feltételeztünk róla.
|
||
|
||
\item A program tesztelését csak a program írójától különböző személy képes hatékonyan elvégezni. Ennek oka, hogy a tesztelés nem "jóindulatú” tevékenység, saját munkájának vizsgálatához mindenki úgy áll hozzá, hogy önkéntelenül jónak feltételezi.
|
||
\end{itemize}
|
||
|
||
A programtesztelés módszereit két csoportba oszthatjuk aszerint, hogy a tesztelés során végrehajtjuk-e a programot, vagy nem. Ha csak a program kódját vizsgáljuk, akkor statikus (erről nem esik több szó), ha a programot végre is hajtjuk a tesztelés során, akkor dinamikus tesztelésről beszélünk.
|
||
|
||
\paragraph{Dinamikus tesztelési módszerek}
|
||
A dinamikus tesztelési módszerek alapelve az, hogy a programot működés közben vizsgáljuk. Teszteseteket kétféle módon tudunk választani. Egy lehetőség az ún. feketedoboz-módszer, más néven adatvezérelt tesztelés. E módszer alkalmazásakor a tesztelő nem veszi figyelembe a program belső szerkezetét, pontosabban nem azt tekinti elsődleges szempontnak, hanem a teszteseteket a feladat meghatározás alapján választja meg.
|
||
|
||
A cél természetesen a lehető leghatékonyabb tesztelés elvégzése, azaz az összes hiba megtalálása a programban. Ez ugyan elvileg lehetséges, kimerítő bemenet tesztelést kell végrehajtani, a programot ki kell próbálni az összes lehetséges bemenő adatra. Ezzel a módszerrel azonban, mint korábban láttuk, mennyiségi akadályba ütközhetünk.
|
||
|
||
Egy másik lehetőség a fehérdoboz-módszer (logika vezérelt tesztelés). Ebben a módszerben a tesztesetek megválasztásánál lehetőség van a program belső szerkezetének figyelembevételére is.
|
||
|
||
A cél a program minél alaposabb tesztelése, erre jó módszer a kimerítő út tesztelés. Ez azt jelenti, hogy a programban az összes lehetséges utat végigjárjuk, azaz annyi tesztesetet hozunk létre, hogy ezt elérhessük vele. Az a probléma, hogy még viszonylag kis programok esetén is igen nagy lehet a tesztelési utak száma. Gondoljunk a ciklusokra! Sőt ezzel a módszerrel a hiányzó utakat nem lehet felderíteni.
|
||
|
||
Mivel sem a fehérdoboz-módszerrel, sem a feketedoboz-módszerrel nem lehetséges a kimerítő tesztelés, el kell fogadnunk, hogy nem tudjuk egyetlen program hibamentességét sem szavatolni. A további cél ezek után az összes lehetséges teszteset halmazából a lehető leghatékonyabb teszteset-csoport kiválasztása lehet.
|
||
|
||
A tesztelés hatékonyságát kétféle jellemző határozza meg: a tesztelés költsége és a felfedett hibák aránya. A leghatékonyabb teszteset-csoport tehát minimális költséggel maximális számú hibát fed fel.
|
||
|
||
A feketedoboz- és fehérdoboz-teszteken kívül még érdemes megemlíteni olyan speciális teszteket, amikor nem a helyesség belátása a cél. Ilyen pl. a stresszteszt (nagy adatmennyiséget hogyan bír kezelni a program, jól skálázódik-e) vagy a hatékonysági teszt (végrehajtási idő tesztelése).
|
||
|
||
\section{Az adattípus fogalma}
|
||
|
||
\subsection{Alapfogalmak, jelölések}
|
||
|
||
\begin{itemize}
|
||
|
||
\item $A^{*}$ az A-beli véges sorozatok halmazát, $A^{\infty}$ az A-beli végtelen sorozatok halmazát jelöli.
|
||
A kettő uniója $A^{**} = A^{*} \cup A^{\infty}$ pedig az A-beli véges vagy végtelen sorozatok halmazát jelenti.
|
||
|
||
\item Legyen $R \subseteq A \times \mathbb{L}$ egy logikai reláció. Ekkor az R igazsághalmaza
|
||
$\lceil R \rceil ::= R^{-1}(\left\{{igaz}\right\}) $
|
||
|
||
\item Legyen I egy véges halmaz és legyenek $A_{i}, i \in I$ tetszőlege véges vagy megszámolható, nem üres halmazok.
|
||
Ekkor az $A = \underset{i \in I}{\times} A_{i}$ halmazt állapottérnek, az $A_{i}$ halmazokat pedig típusértékhalmazoknak nevezzük.
|
||
|
||
\item Feladat: feladatnak nevezünk egy $F \subseteq A \times A$ relációt.\\
|
||
A feladat fenti definíciója természetes módon adódik abból, hogy a feladatot egy
|
||
leképezésnek tekintjük az állapottéren, és az állapottér minden pontjára megmondjuk,
|
||
hova kell belőle eljutni, ha egyáltalán el kell jutni belőle valahova.
|
||
|
||
\item Program:\\
|
||
Programnak nevezzük az $S \subseteq A \times A^{**}$ relációt, ha
|
||
\begin{enumerate}
|
||
\item $\mathcal{D}_{S}=A$ (az állapottér minden pontjához rendel valamit, azaz a program minden pontban csinál valamit)
|
||
\item $\forall \alpha \in \mathcal{R}_{S} : \alpha = red(\alpha)$ (az állapot megváltozik, vagy ha mégsem, az az abnormális működés jele)
|
||
\item $\forall a \in A : \forall \alpha \in S(A) : |\alpha| \not = 0$ és $\alpha_{1}=a$
|
||
\end{enumerate}
|
||
\noindent A fenti definícióval a "működés” fogalmát akarjuk absztrakt módon megfogalmazni.
|
||
|
||
\end{itemize}
|
||
|
||
\subsection{Típusspecifikáció}
|
||
|
||
Először bevezetünk egy olyan fogalmat, amelyet arra használhatunk, hogy pontosan
|
||
leírjuk a követelményeinket egy típusértékhalmazzal és a rajta végezhető
|
||
műveletekkel szemben.\\
|
||
|
||
\noindent A $\mathcal{T_{S}}=(H,I_{S},\mathbb{F})$ hármast típusspecifikációnak nevezzük, ha
|
||
teljesülnek rá a következő feltételek:
|
||
|
||
\begin{enumerate}
|
||
\item H az alaphalmaz,
|
||
|
||
\item $I_{S} : H \to \mathbb{L} $ a specifikációs invariáns,
|
||
|
||
\item $T_{\mathcal{T}} = \left\{ {(\mathcal{T},x) | x \in \lceil I_{S}} \rceil\right\}$ a típusértékhalmaz,
|
||
|
||
\item $\mathbb{F} = \left\{ {F_{1},F_{2},...,F_{n}}\right\}$ a típusműveletek specifikációja, ahol\\
|
||
$\forall i \in [1..n]: F_{i} \subseteq A_{i} \times A_{i}$, $A_{i} = A_{i_{1}} \times ... \times A_{i_{n_{i}}}$ úgy,\\
|
||
hogy $\exists j \in [1..n_{i}]: A_{i_{j}} = T_{\mathcal{T}} $
|
||
\end{enumerate}
|
||
|
||
Az alaphalmaz és az invariáns tulajdonság segítségével azt fogalmazzuk meg,
|
||
hogy mi az a halmaz, $T_{\mathcal{T}}$, amelynek elemeivel foglalkozni akarunk, míg a feladatok
|
||
halmazával azt írjuk le, hogy ezekkel az elemekkel milyen műveletek végezhetők
|
||
el.
|
||
|
||
Az állapottér definíciójában szereplő típusértékhalmazok mind ilyen típusspecifikációban
|
||
vannak definiálva. Az állapottér egy komponensét egy program csak a típusműveleteken keresztül változtathatja meg.
|
||
\subsection{Típus}
|
||
|
||
Vizsgáljuk meg, hogy a típusspecifikációban leírt követelményeket hogyan valósítjuk
|
||
meg.\\
|
||
|
||
\noindent A $\mathcal{T}=(\rho,I,\mathbb{S})$ hármast típusnak nevezzük, ha
|
||
|
||
\begin{enumerate}
|
||
\item $\rho \subseteq E^{*} \times T$ a reprezentációs függvény (reláció),\\
|
||
T a típusértékhalmaz,\\
|
||
E az elemi típusértékhalmaz
|
||
\item $I : E^{*} \to \mathbb{L} $ típusinvariáns
|
||
\item $\mathbb{S} = \left\{ {S_{1},S_{2},...,S_{m}}\right\}$, ahol\\
|
||
$\forall i \in [1..m]: S_{i} \subseteq B_{i} \times B_{i}^{**}$ program, $B_{i} = B_{i_{1}} \times ... \times B_{i_{m_{i}}}$ úgy,\\
|
||
hogy $\exists j \in [1..m_{i}]: B_{i_{j}} = E^{*}$ és $\not \exists j \in [1..m_{i}]: B_{i_{j}} = T$
|
||
\end{enumerate}
|
||
|
||
A típus első két komponense az absztrakt típusértékek reprezentációját írja le, míg a programhalmaz a típusműveletek implementációját tartalmazza. Az elemi típusértékhalmaz lehet egy tetszőleges másik típus típusértékhalmaza vagy egy, valamilyen módon definiált legfeljebb megszámolható halmaz.
|
||
|
||
\subsection{Invariáns}
|
||
|
||
Az invariáns lényege, hogy ezt a tulajdonságot soha nem sérthetjük meg. Például halmaz típus esetén nem szabad, hogy megsérüljön
|
||
az az invariáns tulajdonság, hogy egy halmazban egy elem csak egyszer fordulhat elő.
|
||
|
||
\subsection{Reprezentáció}
|
||
|
||
Azt, hogy egy típust milyen típusok segítségével, milyen módszerrel, stb., valósítottunk meg, reprezentációnak nevezzük. Például
|
||
egy verem típust meg lehet valósítani tömb segítségével, de láncolt listával is.
|
||
|
||
A reprezentáció a típusspecifikáció típusértékhalmazának leképezése a konkrét típusban, amit a reprezentációs függvény ad meg.
|
||
|
||
\subsection{Implementáció}
|
||
|
||
Az implementáció a típusspecifikáció típusműveleteinek megvalósítása a konkrét típus programhalmaza által.
|
||
|
||
Az implementáció során a típus megvalósításakor a típusértékhalmaz megadását követően definiálni kell a típusműveleteket. Ahogyan a modellben is, a gyakorlatban is az állapottér változásait a program csak a típusműveleteken keresztül végezheti el.
|
||
|
||
\subsection{Emészthetőbb módon}
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/adattipus}
|
||
\caption{Adattípus}
|
||
\label{fig:adattipus}
|
||
\end{figure}
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/adattipus_pelda}
|
||
\caption{BigNumber példa}
|
||
\label{fig:adattipus_pelda}
|
||
\end{figure}
|
||
|
||
\section{A visszavezetés módszere}
|
||
|
||
A programozási feladatok megoldásához különböző programozási mintákat, ún. programozási tételeket használunk fel, ezekre vezetjük vissza
|
||
a megoldást.\\
|
||
|
||
\noindent Lépései:
|
||
\begin{enumerate}
|
||
\item Megsejtjük a feladatot megoldó programozási tételt.
|
||
\item Specifikáljuk a feladatot a programozási tétel jelöléseivel.
|
||
\item Megadjuk a programozási tétel és a feladat közötti eltéréseket:
|
||
\begin{itemize}
|
||
\item intervallum határok: konkrét érték vagy kifejezés (pl. $[1..\frac{n}{2}]$),
|
||
a típusuk a $\mathbb{Z}$ helyett lehet annak valamely része (pl. $\mathbb{N}$)
|
||
|
||
\item $\beta:[m..n] \to \mathbb{L}$ és/vagy $f:[m..n] \to H$ konkrét megfelelői
|
||
|
||
\item a H megfelelője a szükséges művelettel
|
||
\begin{itemize}
|
||
\item $(H,>)$ helyett pl. $(\mathbb{Z},>)$ vagy $(\mathbb{Z},<)$
|
||
\item $(H,+)$ helyett pl. $(\mathbb{Z},+)$ vagy $(\mathbb{R},*)$
|
||
\end{itemize}
|
||
\item a változók átnevezése
|
||
\end{itemize}
|
||
\item A különbségek figyelembe vételével a tétel algoritmusából elkészítjük a konkrét feladatot megoldó algoritmust.
|
||
\end{enumerate}
|
||
|
||
\section{Felsoroló, a felsoroló típus specifikációja}
|
||
|
||
A gyűjtemény (tároló, kollekció, iterált) egy olyan adat
|
||
(objektum), amely valamilyen elemek tárolására alkalmas.
|
||
\begin{itemize}
|
||
\item Ilyenek az összetett szerkezetű, de különösen az iterált szerkezetű
|
||
típusok értékei: halmaz, sorozat (verem, sor, fájl), fa, gráf
|
||
|
||
\item De vannak úgynevezett virtuális gyűjtemények is: pl. egész számok
|
||
egy intervallumának elemei, vagy egy természetes szám prím-osztói
|
||
\end{itemize}
|
||
|
||
\noindent Egy gyűjtemény feldolgozásán a benne levő elemek
|
||
feldolgozását értjük.
|
||
\begin{itemize}
|
||
\item Keressük a halmaz legnagyobb elemét!
|
||
\item Hány negatív szám van egy számsorozatban?
|
||
\item Válogassuk ki egy fa leveleiben elhelyezett értékeket!
|
||
\item Járjuk be az [m .. n] intervallum minden második elemét visszafelé!
|
||
\item Adjuk össze az n természetes szám prím-osztóit!
|
||
\end{itemize}
|
||
|
||
\noindent A feldolgozni kívánt elemek felsorolását (bejárását) az alábbi
|
||
műveletekkel szabványosítjuk:
|
||
\begin{itemize}
|
||
\item First() : Rááll a felsorolás első elemére, azaz elkezdi a felsorolást
|
||
\item Next() : Rááll az elkezdett felsorolás soron következő elemére
|
||
\item End() : Mutatja, ha a felsorolás végére értünk
|
||
\item Current() : Visszaadja a felsorolás aktuális elemét
|
||
\end{itemize}
|
||
|
||
Egy felsorolásnak különböző állapotai vannak (indulásra kész,
|
||
folyamatban van, befejeződött), és a műveletek csak bizonyos
|
||
állapotokban értelmezhetők (máshol a hatásuk nem definiált).
|
||
A feldolgozó algoritmus garantálja, hogy a felsoroló műveletek mindig
|
||
megfelelő állapotban kerüljenek végrehajtásra.
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.4\linewidth]{img/felsorolas_stuki}
|
||
\caption{A felsorolás algoritmusa}
|
||
\label{fig:felsorolas_stuki}
|
||
\end{figure}
|
||
|
||
A felsorolást sohasem a felsorolni kívánt gyűjtemény, hanem
|
||
egy külön felsoroló objektum végzi.
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_speci}
|
||
\caption{A felsoroló objektum és típusa}
|
||
\label{fig:felsorolas_stuki}
|
||
\end{figure}
|
||
|
||
\section{Felsorolóra megfogalmazott programozási tételek}
|
||
|
||
\includepdf[pages={1-2}]{progtetel_felsorolo.pdf}
|
||
|
||
\section{Nevezetes gyűjtemények felsorolói}
|
||
|
||
\subsection{Intervallum}
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_intervallum}
|
||
\caption{Intervallum felsorolója}
|
||
\label{fig:felsorolo_intervallum}
|
||
\end{figure}
|
||
|
||
\subsection{Tömb}
|
||
Itt két különböző tömbtípus felsorolóját mutatjuk be: az egydimenziós (vektor) és a kétdimenziós tömbét (mátrix).
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_vektor}
|
||
\caption{Vektor felsorolója}
|
||
\label{fig:felsorolo_vektor}
|
||
\end{figure}
|
||
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_matrix}
|
||
\caption{Mátrix sorfolytonos felsorolója}
|
||
\label{fig:felsorolo_matrix}
|
||
\end{figure}
|
||
|
||
Megjegyzés: a felsorolás történhet másképpen is, például vektor esetén végezhetjük a felsorolást visszafelé, a tömb végétől kezdve, vagy mátrixnál alkalmazhatunk pl. oszlopfolytonos bejárást.
|
||
|
||
\subsection{Sorozat}
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_sorozat}
|
||
\caption{Sorozat felsorolója}
|
||
\label{fig:felsorolo_sorozat}
|
||
\end{figure}
|
||
|
||
\subsection{Halmaz}
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_halmaz}
|
||
\caption{Halmaz felsorolója}
|
||
\label{fig:felsorolo_halmaz}
|
||
\end{figure}
|
||
|
||
\subsection{Szekvenciális inputfájl}
|
||
\begin{figure}[H]
|
||
\centering
|
||
\includegraphics[width=0.7\linewidth]{img/felsorolo_seqin}
|
||
\caption{Szekvenciális inputfájl felsorolója}
|
||
\label{fig:felsorolo_seqin}
|
||
\end{figure}
|
||
|
||
\section{Programozási tételekkel készült programok tesztelése}
|
||
TODO
|
||
|
||
\end{document} |