A kupac legrövidebb megragadása a következő:
A fentieket nevezzük összefoglalóan kupac-tulajdonságnak.
A következmények már előre sejtetik az alábbi műveletek némelyikének értelmét, majdani hasznát, sőt az ábrázolás „logikáját” is. A kupacot mint adatszerkezetet, típuskonstrukciós eszközt így definiáljuk:
ExportModul Kupac(Típus TElem): Eljárás Üres(Változó k:Kupac) Függvény ÜresE(Konstans k:Kupac):Logikai Első(Konstans k:Kupac):TElem Index(Konstans k:Kupac, e:TElem):Egész [„index” → tömbben ábrázolás] Eljárás Módosít(Változó k:Kupac, Konstans i:Egész, e:TElem) [i: „index” → tömbben ábrázolás] Felcsúsztat(Változó k:Kupac, Konstans i:Egész) [i: „index” → tömbben ábrázolás] Lecsúsztat(Változó k:Kupac, Konstans i:Egész) [i: „index” → tömbben ábrázolás] Függvény Kupacból(Változó k:Kupac):TElem Eljárás Kupacba(Változó k:Kupac, Konstans e:TElem) Függvény HibásE(Változó k:Kupac):Logikai Modul vége.
A Kupacból és a Kupacba műveletek a kupac-tulajdonságot megtartó műveletek. A Módosít viszont az érték helyben történő megváltoztatása révén elronthatja a rendezettséget, így negatívan hathat a kupac-tulajdonságra. Ennek visszaállítását célozzák a „csúsztató” műveletek.
Az elemek közvetlen elérését lehetővé tevő Index és Módosít művelet a tömbbel való rokonságot jelzi.
A kupac hatékony működésének feltétele egy speciális folytonos ábrázolás: egy speciális tömbre visszavezetés. A specialitást az elemek logikai egymásutánisága jelenti.
A bináris fákkal való szoros kapcsolat megengedi, hogy az alábbi nevű indexelő függvényeket, ill. rendezési függvényt használjuk. Ezek megkönnyítik a kupac bináris faként való kezelését! Alább vázoljuk egy lehetséges ábrázolását, egyelőre „hagyományosan”, rekordként, és az ábrázoláshoz igazítjuk annak kezelő műveleteit.
Konstans MaxN:Egész(???) Típus Kupac=Rekord( n:Egész, ke:Tömb(1..MaxN:TElem), hiba:Logikai ) [indexelő függvények:] Függvény BalGyerek(Konstans k:Kupac,i:Egész):Egész BalGyerek:=2*i Függvény vége. Függvény JobbGyerek(Konstans k:Kupac,i:Egész):Egész JobbGyerek:=2*i+1 Függvény vége. Függvény Szülő(Konstans k:Kupac,i:Egész):Egész Szülő:=i Div 2 Függvény vége. Függvény UtsóGyerek(Konstans k:Kupac):Egész UtsóGyerek:=k.n Függvény vége. [rendező függvény:] Függvény KisebbikGyereke(Konstans k:Kupac,s:Egész):Egész [Ef: 2≤2*s≤k.n, azaz 's' szülőnek van gyereke] Változó b,j:Egész b:=BalGyerek(k,s); j:=JobbGyerek(k,s) Ha j>UtsóGyerek(k) [jobboldali gyereke nincs] vagy k.ke(b)<TElemk.ke(j) [a baloldali kisebb] akkor KisebbikGyereke:=b különben KisebbikGyereke:=j Elágazás vége Függvény vége.
A fenti műveletek mindegyikéhez megfogalmazhatók előfeltételek, de mivel „belterjesek” (azaz nem exportáljuk) a helyes használatukban biztosak vagyunk, ezért nem ellenőrizzük teljesülésüket.
Térjünk vissza a kupac teljes megvalósításához! A kupac modulja az alábbi:
Modul Kupac(Típus TElem): Reprezentáció Konstans MaxN:Egész(???) Típus KupacElemek=Tömb(1..MaxN:TElem) Változó [ez az, amit feljebb Kupac típusként (rekordként) definiáltunk] n:Egész ke:KupacElemek hiba:Logikai Implementáció [segéd műveletek: --------------------------------------------------] Függvény BalGyerek(Konstans k:Kupac,i:Egész):Egész … [l. fentebb] Függvény JobbGyerek(Konstans k:Kupac,i:Egész):Egész … [l. fentebb] Függvény Szülő(Konstans k:Kupac,i:Egész):Egész … [l. fentebb] Függvény UtsóGyerek(Konstans k:Kupac):Egész … [l. fentebb] Függvény KisebbikGyereke(Konstans k:Kupac,s:Egész):Egész … [l. fentebb] [típus-műveletek: --------------------------------------------------] Eljárás Üres(Változó k:Kupac): n:=0; hiba:=Hamis Eljárás vége. Függvény ÜresE(Konstans k:Kupac):Logikai ÜresE:=n=0 Függvény vége. Függvény Első(Konstans k:Kupac):TElem [Ef: n>0] Első:=ke(1) Függvény vége. Függvény Index(Konstans k:Kupac,e:TElem):Egész [Uf: e∈ke → Index(k,e)=i ∧ ke(i)=e e∉ke → Index(k,e)=0] Változó i:Egész i:=1 Ciklus amíg i≤n és ke(i)≠e i:+1 Ciklus vége Ha i≤n akkor Index:=i különben Index:=0 Függvény vége. Eljárás Módosít(Változó k:Kupac, Konstans i:Egész,e:TElem): [Ef: n>0 ∧ i∈[1..n]] ke(i):=e Eljárás vége. …
Az alábbi műveletek elvégzésénél ügyelünk a kupac-tulajdonság fennmaradására!
… [kupac-tulajdonságot helyreállító eljárások: -----------------------] Eljárás Felcsúsztat(Változó k:Kupac, Konstans i:Egész): [Ef: n>0 ∧ i∈[1..n]] Ha i>1 [nem gyökérelem] akkor Ha ke(i)<ke(Szülő(k,i)) [nem teljesül II°] akkor Csere(ke(i),ke(Szülő(k,i)))[Csere(x,y) ≡ s:=x; x:=y; y:=s] Felcsúsztat(k,Szülő(k,i)) Elágazás vége Elágazás vége Eljárás vége. Eljárás Lecsúsztat(Változó k:Kupac, Konstans i:Egész): [Ef: n>0 ∧ i∈[1..n]] Változó g:Egész Ha BalGyerek(k,i)≤UtsóGyerek(k) [i.-nek van gyereke] akkor g:=KisebbikGyereke(k,i) Ha ke(i)>ke(g) [nem teljesül II°] akkor Csere(ke(i),ke(g)) Lecsúsztat(k,g) Elágazás vége Elágazás vége Eljárás vége. [kupac-tulajdonságot megtartó műveletek: ----------------------------] Függvény Kupacból(Változó k:Kupac):TElem [Ef: n>0] Kupacból:=ke(1) [az elsőt, a legkisebbet kivesszük] ke(1):=ke(n) [a szintfolytonosság megtartása érdekében: az utolsót előre tesszük] n:-1 [már eggyel kevesebb eleme van] [ha nem vált üressé a kupac, a rendezettség szempontjából esetleg rossz helyre került első elemet a helyére csúsztatjuk:] Ha n>0 akkor Lecsúsztat(k,1) Függvény vége. Eljárás Kupacba(Változó k:Kupac, Konstans e:TElem): [Ef: n<MaxN] n:+1 [eggyel több eleme lesz] ke(n):=e [a szintfolytonosság megtartása érdekében: a végére tesszük az új elemet] [a rendezettség szempontjából esetleg rossz helyre került utolsó elemet a helyére csúsztatjuk:] Felcsúsztat(k,n) [az új elemet a helyére tesszük] Eljárás vége. …
És végül:
… Függvény HibásE(Változó k:Kupac):Logikai HibásE:=hiba; hiba:=Hamis Függvény vége. Inicializálás n:=0; hiba:=Hamis Modul vége.
Készítse el a fenti modul Pascal object-alapú unitját, amelyben az elemtípus a String! Felhasználhatja az alábbi félig kész keretet: http://people.inf.elte.hu/szlavi/AlgAdat/1felev/Kupac/StrKupac_Unit_keret.pas . Szüksége lehet az Általános rutinokat tartalmazó inklúdra, töltse le'
Írjon hozzá egy próbaprogramot, amely legalább az alábbi szituációkban való helyes működését ellenőrzi:
Ilyesmire gondolhat: http://people.inf.elte.hu/szlavi/AlgAdat/1felev/Kupac/KupacProba.exe . Töltse le és futassa!
Fogalmazza meg, milyen célt szolgálnak a „csúsztató” műveletek!
Íme… Amikor egy elem értéke (a többiekhez „viszonyitott” rendezettsége) megváltozik, akkor kell alkalmazni a „csúsztató” eljárásokat, hogy a kupac-tulajdonság ismét helyre álljon!
Remélem, hiányérzete támadt! Ha Ön is úgy érzi, hogy a kupac „nyelvezetéből” hiányzik az alábbi: Függvény Érték(Konstans k:Kupac, i:Egész):TElem függvény, tegye bele a modulba és a megvalósított unitba is!
Készítse el a kupac unitjából –a szokásos módon– az inklúdálható class-alapú változatot (OKupac_Sablon.Inc)! Legyen az ábrázolásban szereplő tömb maximális méretét jelentő MaxN a kupac-sablon „import paramétere”! A próba programot is igazítsa hozzá (OKupac_Inc_Proba.pas)! Ne feledje: a kupacot létre is kell hozni a használat előtt (nem elég üressé tenni)!
Készítse el a kupac class-alapú változatot, amelyet a OKupac_Sablon_Unit.pas) unitba csomagol! Írjon egy próba programot is (OKupac_Sablon_Proba.pas)! Ne feledje: a kupacot létre is kell hozni a használat előtt (nem elég üressé tenni)! Felhasználhatja az alábbi félig kész keretet: http://people.inf.elte.hu/szlavi/AlgAdat/1felev/Kupac/OKupac_Sablon_Unit_keret.pas .
A kupacot hatékonyan fel lehet használni rendezésre.
Az algoritmust animálva töltse le: pdf, mp4!
Konstans MaxN:Egész(???) Típus TElemek=Tömb(1..MaxN:TElem) Eljárás Rendez(Változó X:TElemek, Konstans N:Egész): Változó K:Kupac(TElem) Üres(K) Ciklus i=1-től N-ig Kupacba(K,X(i)) Ciklus vége Ciklus i=1-től N-ig X(i):=Kupacból(K) Ciklus vége Eljárás vége.
… hallgassa és nézze a rendezési algoritmusokról a következő tanulságos kis videókat: 15 Sorting Algorithms in 6 Minutes, Visualization and Comparison of Sorting Algorithms.
ExportModul TPrSor(TElem): Eljárás Üres[legyen](Változó s:TPrSor) Függvény ÜresE(Konstans s:TPrSor):Logikai Eljárás Sorba(Változó s:TPrSor, Konstans e:TElem) Függvény Sorból(Változó s:TPrSor):TElem Első(Változó s:TPrSor):TElem Hossz(Konstans s:TPrSor):Egész TeleE(Konstans s:TPrSor):Logikai HibásE(Változó s:TPrSor):Logikai Modul vége.
ExportModul TElem: Eljárás Write(Konstans elő:Szöveg, e:TElem, utó:Szöveg) Read(Konstans kérdés:Szöveg, Változó e:TElem) Operátor KisebbE(Konstans e1,e2:TElem):Logikai Másként e1<e2 Modul vége.