Programozás alapjai II. (8. ea) C++ Kiegészítő anyag: speciális adatszerkezetek Szeberényi Imre BME IIT <szebi@iit.bme.hu> Speciális adatszerkezetek A helyes adatábrázolás választása, a helyes adatszerkezet megtalálása igen fontos tervezési és implementációs kérdés. Ügyetlen tárolással teljesen tönkretehetjük az amúgy gondos tervezés eredményét is. Különböző szempontokat kell figyelembe venni: modell, sebesség, méret M Ű E G Y T E M 1 7 8 2 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -1- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -2- Tömbök Ha a méret és a dimenziószám ismert, nincs gond. Ha a dimenziószám változik, akkor nem oldható meg nyelvi eszközzel tárolás sor-, vagy oszlopfolytonosan l memóriaterület dinamikus foglalása kiszámítandó az elem címe az indexkifejezés alapján (legutolsó index fut a leggyorsabban) C-ben az index 0-tól n-1-ig megy, de nem minden nyelven van így. C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -3- I-1,0,0 I-1,J-1,0 Tömbök/2 j 0,J-1,0 i 0,0,0 I-1,0,K-1 k 0,0,K-1 0,J-1,K-1 M[I][J][K] méretű 3D mátrix[i][j][k] elemének címe= J*K*i+K*j+k+bázis C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -4- N dimenziós tömb Legyen Li egy N dimenziós tömb i. dimenziójának minimális indexe, Ui pedig a maximális indexe. A tömb i1, i2, i3, i4,..in indexű elemének címe: S2*S3*... *Sn*(i1-L1) + S3*...Sn*(i2-L2) +... + (in-ln) + bázis ahol: Si = Ui Li + 1 Nagyméretű ritka tömbök Nagyméretű ritka (sok azonos elem) mátrixok tárolásánál fontos lehet a helytakarékos megoldás. Ha a nem nulla elemek száma ismert, akkor statikus táblákkal viszonylag egyszerű a megoldás Az adat mellett tároljuk a sor- és oszlopindexet is. C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -5- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -6-1
Sor: Érték: Nagyméretű ritka tömbök/2 0 1 2 3 4 0 12 14 1 2 26 40 3 OszlElső: 4 17 31 5 9 85 4 0 2 5 4 0 2 5 17 12 26 9 31 14 40 85 0 1 2 3 4 5 6 7 8 0 1 4 5 7 8 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -7-0 1 2 3 4 0 12 14 1 2 26 40 3 4 17 31 5 9 85 Nagyméretű ritka tömbök/3 Sor: Ertek: OszlElso: 0 1 4 5 7 8 4 0 2 5 4 0 2 6 17 12 26 9 31 14 40 85 int elem(int i, int j) // pl: 2,3 for (k = OszlElso[j]; k < OszlElso[j+1]; k++) if (Sor[k] == i) return(ertek[k]); return(0); C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -8- Nagyméretű ritka tömb listával Nagyméretű tömb ortogonális listával Statikus tábla helyett körkörösen láncolt ortogonális lista. (fésű) Minden listaelemben tárolni kell az elem indexét, és az adatot. A nulla, vagy más ismétlődő adatot nem tároljuk. Minden sorhoz és oszlophoz van egy fej (strázsa), amit a speciális index jelöl. 0 0 0 1 0 2 0 3 1 0 2 0 3 0 1 1 8 3 1 4 2 3 9 0 4 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -9- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -10- Sorok és vermek Sor: FIFO (First-In-First-Out) Verem: LIFO (Last-In-First-Out) megvalósítás tömbbel, vagy listával Sorok felhasználása Természetes eszköz a várakozó sorok megvalósításához. Természetes eszköz a puffereléshez (termelő-fogyasztó sebességkülönbség kiegyenlítése) C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -11- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -12-2
Verem felhasználása Viselkedés miatt (dinamikusan növekszik ill. csökken, LIFO) Tipikus megvalósítása az eljáráshívásnak és a paraméterátadásnak. Rekurzió megvalósításának segédeszköze. Lokális változók tárolása. Postfix kifejezések kiértékelése. Visszalépéses (backtrack) algoritmusok segédeszköze. Hash függvény Egy fix hosszúságú kivonatot készít, ami jellemző az adatra. h = H(z). tulajdonságai: egyirányú y h-hoz nehéz találni olyan z z'-t amire h=h(z') H-hoz nehéz találni olyan z z'-t amire H(z)=H(z') Felhasználása: Index leképezése egy véges tartományra. (pl. indexelés stringgel) C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -13- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -14- Hash tábla Olyan tároló, amelyben hash függvény segítségével tárolunk. A tárolás alapját képező kulcsot (sokszor magát a tárolandó adatot) hash függvény segítségével kivonatoljuk. Az így kapott érték alapján tárolunk, de felkészülünk az esetleges ütközésekre is. Példa H-ra: m - leképezési [ m( mod 1) ] H ( z) = zθ, ahol : θ = céltartomány 5 1 2 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -15- z H ütközés Ht: Hash tábla/2 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -16- Hash ütközések feloldása Lineráis kereséssel A bemutatott megoldás logikus lenne, de nem ez a szokásos. A táblában keresnek egy újabb szabad helyet. Pl. lineáris kereséssel próbálnak a következő elemekből választani. Hátrány, hogy csoportok alakulnak ki (clustering) Ezért gyakoribb a többszörös hash használata int Proba(int s, Key k) int i = s; do if (Ht[i] == k) return(i); i = (i + 1) % m; while (i!= s); return(-1); Spec. kulcs int Tarol(Key k) int h = Hash(k); int i = Proba(h, Ures); if (i < 0) return(0); Ht[i] = k; return(1); (); Key Keres(Key k) int h = Hash(k); int i = Proba(h, k); if (i < 0) return(ures); return(ht[i]); C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -17- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -18-3
Többszörös hash A Proba ciklusában d=+1 helyett d = Hash2-t használunk. Pl: Hash2-ben a θ helyett 1-θ-t használunk. int Proba(int s, Key k) int i = s; int td = Hash2(k); do if (Ht[i] == k) return(i); i = (i + d) % m; while (i!= s); return(-1); Listák Egyszeresen láncolt Többszörösen láncolt Körkörösen láncolt Rendezett Rendezetlen Fésűs (ortogonális) C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -19- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -20- Duplán láncolt adatszerkezet Fésűs lista KEZD1 NULL KEZD2 NIL C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -21- TK TK NEV,ATL TK TK TK TK NEV,ATL TK C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -22- Fa szerkezetek Bináris fa Rendezett, 1 db kulcs 2 pointer Halom (kupac) speciális bináris fa tömbbel is szokás ábrázolniá N-fa N-1 db kulcs, N db pointer ha k < k1 -> p0 ha ki < k < ki+1 -> pi ha kn-1 < k -> pn-1 k k1, k2, k3 p0 p1 p2 p3 Bináris fa bejárása ism. Ha a fa_nem_üres Akkor kiírjuk_a_bal_részfát kiírjuk_az_elemet kiírjuk_a_jobb_részfátk jobb rés Vege 3 2 5 15 6 20 31 22 91 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -23- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -24-4
Kupac (heap) Süllyeszt a 1 a i <= a 2i ha i < n/2 a i <= a 2i+1 ha i < n/2 a 1 =10 a i <= a 2i ha i < n/2 a i <= a 2i+1 ha i < n/2 a 2 a 3 a 2 =8 a 3 =11 a 4 a 5 a 6 a 7 a 4 =19 a 5 =15 a 6 =12 a 7 =18 a 8 a 9 a 8 =88 a 9 =35 A kisebb ágon haladunk, addig, amíg cserélni tudunk. C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -25- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -26- Rendezés algoritmusa Készítsünk kupacot a tetején lesz a legkisebb elem Levesszük a legfelsőt és elsüllyesztjük a -t,, így újból kupachoz jutunk aminek a tetején a ismét legkisebb elem van. Kérdések Hogyan készítünk kupacot? a n/2+1... a n biztosan kupac, ezért ebben elsüllyesztjük az a n/2 -t, majd az a n/2-1 -t, és így tovább. Hogyan ábrázoljuk? tömbben: elem index = tömb index 1 2 3 4 5 6 7 C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -27- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -28- Kérdések (2) B-tree Mit használjunk helyett? Legyen ez a tömb legutolsó eleme! Ezzel kicseréljük a legelső elemet így a kupac mérete eggyel csökken, ugyanakkor a maradék továbbra is kupacot alkot. legkisebb csere B-fa (B-tree) kiegyensúlyozott olyan N-fa, amelynek minden csomópontjából legalább N/2 és legfeljebb N ág indul. (gyökér kivételével) kulcsok száma: k = n-1 C példa: http://www.iit.bme.hu/~szebi/prog2/bfa.c k1, k2, k3 p0 p1 p2 p3 maradék kupac C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -29- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -30-5
B-tree példa (N=5) B-tree példa/2 55 20 ide jönne, de elérte a maximális számot (N=5-höz max. 4 kulcs tartozik) új kulcs jött fel 20, 40 kettéhasadt 10,12 30,35,40,50 55 10,12 30,35 50, 55 A levelek azonos szinten maradtak. C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -31- C++ programozási nyelv BME-IIT Sz.I. 2011.04.05. -32-6