Files
2022-01-07 19:57:57 +01:00

633 lines
36 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[12pt,margin=0px]{article}
\usepackage[a4paper, margin=1in]{geometry}
\usepackage[normalem]{ulem}
\usepackage[table,xcdraw]{xcolor}
\usepackage[thinlines]{easytable}
\usepackage[utf8]{inputenc}
\usepackage[hungarian]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage{enumitem}
\usepackage{fancyhdr}
\usepackage{float}
\usepackage{graphicx}
\usepackage{hhline}
\usepackage{listings}
\usepackage{makecell}
\usepackage{multirow}
\usepackage{pdfpages}
\usepackage{subcaption}
\usepackage{xcolor}
\usepackage{verbatim}
\usepackage{dashrule}
\definecolor{mygray}{rgb}{0.15, 0.15, 0.15}
\setlist[itemize,1]{label=$\bullet$}
\setlist[itemize,2]{label=$\circ$}
\setlist[itemize,3]{label=$\centerdot$}
\setlist[itemize,4]{label=$\cdot$}
\pagestyle{fancy}
\newcommand\blfootnote[1]{%
\begingroup
\renewcommand\thefootnote{}\footnote{#1}%
\addtocounter{footnote}{-1}%
\endgroup
}
\renewcommand{\figurename}{ábra}
\newenvironment{tetel}[1]{\paragraph{#1 \\}}{}
\renewcommand{\baselinestretch}{1.15}
\newcommand{\N}{\mathbb{N}}
\newcommand{\Z}{\mathbb{Z}}
\newcommand{\R}{\mathbb{R}}
\newcommand{\Q}{\mathbb{Q}}
\newcommand{\C}{\mathbb{C}}
\makeatletter
\renewcommand\paragraph{%
\@startsection{paragraph}{4}{0mm}%
{-\baselineskip}%
{.5\baselineskip}%
{\normalfont\normalsize\bfseries}}
\makeatother
% A dokument itt kezdődik
\useunder{\uline}{\ul}{}
\fancyhead{}
\cfoot{7. tétel | \thepage. oldal}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0.4pt}
\begin{document}
\thispagestyle{fancy}
\hyphenation{oddword}
\uchyph=0
{\Large\bfseries\noindent 7. Programozás} \\
\section*{Egyszerű programozási feladat megoldásának lépései}
\subsection*{Bevezetés}
Egy programozási feladat megoldása nem csupán a kódolásból áll. Tartalmaz még jó néhány egyéb tevékenységet.\\
\noindent Az első teendő a feladat pontos meghatározása, a \emph{specifikáció}, ami tartalmazza:
\begin{itemize}
\item[-] A feladat szöveges és formalizált, matematikai leírását (a specifikáció ún. szűkebb értelmezésén)
\item[-] A megoldással szemben támasztott követelményeket, környezeti igényeket (ami a specifikáció ún. tágabb értelmezése).
\end{itemize}
\noindent A specifikáció alapján meg lehet tervezni a programot, ahol elkészülhet
\begin{itemize}
\item[-] a \emph{megoldás algoritmusa}, és az
\item[-] algoritmus által használt \emph{adatok leírása}.
\end{itemize}
\noindent 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.\\
\noindent Az algoritmusírás után következhet a \emph{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.\\
\noindent 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 \emph{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.\\
\emph{Megyjegyzés: (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.)}\\
\noindent Ha a tesztelés során hibajelenséggel találkozunk, akkor következhet a \emph{hibakeresés}, a hibajelenséget okozó utasítás megtalálása, majd pedig a \emph{hibajavítás}.\\
\noindent 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.\\
\noindent 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.\\
\noindent 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. Vizsgálnunk kell
\begin{itemize}
\item[-] a hatékonyságot (végrehajtási idő, helyfoglalás), másrészt
\item[-] a kényelmes felhasználhatóságot (felhasználó barát működés).
\end{itemize}
\noindent 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éhány jónak tűnő követelmény 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
\subitem (ez legegyszerűbben úgy érhető el, hogy ismert formalizmusokra építjük)
\item[-] szemléletes, érthető
\subitem (amit időnként nehezít a formalizáltság)
\end{itemize}
\noindent 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}
\noindent 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ítható, hogy a specifikációnak \emph{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}
\noindent Tudjuk-e, hogy a bemenő, illetve a kimenő változók milyen értéket vehetnek fel?
\begin{itemize}
\item[-] Például az emberek magasságát milyen mértékegységben kell megadni?
\item[-] Az eredményül kapott sorszám milyen érték lehet: 1-től sorszámozunk, vagy 0-tól?
\end{itemize}
\noindent Megállapíthatjuk tehát, hogy a specifikációnak \emph{tartalmaznia kell a bemeneti és a kimeneti változók értékhalmazá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 fejezik ki (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.
\end{verbatim}
\noindent 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.\\
\noindent A specifikációnak tehát \emph{tartalmaznia kell a feladatban használt fogalmak definícióját}, valamint az \emph{eredmény kiszámítási szabályát}.\\
\noindent Itt lehetne megadni a bemenő adatokra vonatkozó összefüggéseket is. A \emph{bemenő}, illetve a \emph{kimenő} adatokra kirótt feltételeket nevezzük \emph{előfeltétel}nek, illetve \emph{utófeltétel}nek. 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}
\noindent Ú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.\\
\noindent 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.\\
\noindent A probléma megoldására kétféle utat követhetünk:
\begin{itemize}
\item az utófeltételbe automatikusan beleértjük, hogy "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}
\noindent 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.\\
\noindent 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 \emph{feladat ún. nemdeterminisztikussága}. \\
\noindent 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.
\newpage
\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}
\noindent Megállapíthatjuk ebből, hogy \emph{a program utófeltétele lehet szigorúbb, mint a feladaté}, emellett \emph{az előfeltétele pedig lehet gyengébb}.\\
\noindent 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.\\
\noindent 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.\\
\noindent 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 Az elöbbi feladat progos specifikációja:\\\\
$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} \geq A_{i}\ \land\ \forall j \in \{1, ... ,MAX-1\}\ :\ A_{j} < 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.\\
\noindent A \textbf{struktogram} a programgráfot élek nélkül ábrázolja. Így egyetlen egy alapelem marad, a \emph{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}
\noindent \emph{Szekvenciánál} a téglalapok egymás alatti sorrendje dönti el a végrehajtás sorrendjét.\\
\noindent Az \emph{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. \\
\noindent A \emph{ciklus} elöltesztelős, azaz a benne levő utasítást mindaddig végre kell hajtani, amíg a feltétel igaz.\\
\noindent 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.\\
\noindent Ezt a leíróeszközt még többféle elemmel szokták bővíteni:
\begin{itemize}
\item Eljárásdefinícióval
\item Sokirányú elágazással
\item Hátultesztelős ciklussal
\end{itemize}
\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.3\linewidth]{img/stuki_pelda}
\caption{A példafeladat megoldása struktogrammal.}
\label{fig:stuki_pelda}
\end{figure}
\subsection*{Megvalósítás}
A program elkészítése a kiválasztott programozási nyelve(ke)n, azaz a kódolás.
\newpage
\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 általában 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}
\noindent 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.\\
\noindent 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ő.\\
\noindent 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}
\noindent 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 \emph{statikus} (erről nem esik több szó), ha a programot végre is hajtjuk a tesztelés során, akkor \emph{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. \\
\noindent Egy lehetőség az ún. \textbf{feketedoboz-módszer}, más néven adatvezérelt tesztelés.\\
A 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.\\
\noindent 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.\\
\noindent Egy másik lehetőség a \textbf{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.\\
\noindent 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.\\
\noindent 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.\\
\noindent 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.\\
\noindent 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 Legyen\\
$\begin{array}{r|l}
A^{*} & A\text{-beli \emph{véges} sorozatok halmaza} \\
A^{\infty} & A\text{-beli \emph{végtelen} sorozatok halmaza} \\
A^{*} \cup A^{\infty} = A^{**} & A\text{-beli \emph{véges vagy végtelen} sorozatok halmaza} \\
\end{array}$
\item Legyen $R \subseteq A \times \mathbb{L}$ egy logikai reláció.\\
Ekkor az $R$ \emph{\textbf{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őleges véges vagy megszámolható, nem üres halmazok.\\
Ekkor az
\begin{itemize}
\item $A = \underset{i \in I}{\times} A_{i}$ halmazt \emph{\textbf{állapottér}}nek, az
\item $A_{i}$ halmazokat pedig \emph{\textbf{típus-érték halmaz}}oknak nevezzük.
\end{itemize}
\item Az $F \subseteq A \times A$ relációt \emph{\textbf{feladat}}nak nevezünk.\\
{\footnotesize 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 Az $S \subseteq A \times A^{**}$ relációt \emph{\textbf{program}}nak nevezzük, ha
\begin{enumerate}
\item $\mathcal{D}_{S}=A$\\
{\footnotesize (az állapottér minden pontjához rendel valamit = a program minden pontban csinál valamit)}
\item $\forall \alpha \in \mathcal{R}_{S} : \alpha = red(\alpha)$\\
red: Egy $A^{**}$-beli sorozat redukáltja. Azonos elemek helyettesítése egy elemmel (distinct).
{\footnotesize(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}
\end{itemize}
\noindent A fenti definícióval a "működés” fogalmát akarjuk absztrakt módon megfogalmazni.
\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 \emph{\textbf{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 \emph{specifikációs invariáns},
\item $T_{\mathcal{T}} = \left\{ {(\mathcal{T},x) | x \in \lceil I_{S}} \rceil\right\}$ a \emph{típusértékhalmaz},
\item $\mathbb{F} = \left\{ {F_{1},F_{2},...,F_{n}}\right\}$ a \emph{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}
\noindent 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.\\
\noindent 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.
\newpage
\subsection*{Típus}
\noindent 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 \emph{\textbf{típus}}nak 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}
\noindent 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.\\
\noindent 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.\\
\noindent 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.75\linewidth]{img/adattipus}
\caption{Adattípus}
\label{fig:adattipus}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.75\linewidth]{img/adattipus_pelda}
\caption{BigNumber példa}
\label{fig:adattipus_pelda}
\end{figure}
\newpage
\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 A visszavezetés 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.
{\color{mygray}
\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}
\noindent Egy felsorolásnak különböző állapotai vannak
\begin{itemize}
\item indulásra kész
\item folyamatban van
\item befejeződött\\
\end{itemize}
\noindent A műveletek csak bizonyos állapotokban értelmezhetők (máshol a hatásuk nem definiált). \\
\noindent 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.3\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}
A következő szakaszban találhatóak a felsorolókra megfogalmazott programozási tételek progos definíciója, valamint stuktorgramja.
\includepdf[pages={1-2}]{progtetel_felsorolo.pdf}
\section*{Nevezetes gyűjtemények felsorolói}
\subsection*{Intervallum}
\begin{figure}[H]
\centering
\includegraphics[width=0.75\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}
\noindent \emph{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}
\end{document}