autori: Tomislav Hoško, dipl.ing. dr.sc. Miroslav Slamić urednik: dr.sc. Miroslav Slamić naslov: Strukture podataka i algoritmi stručni recezent: dr.sc. Miroslav Slamić lektorica: Ankica Tomić grafički urednik: Krešimir Pletikosa, ACE nakladnik: Algebra d.o.o., 2009. za nakladnika: mr.sc. Mislav Balković mjesto i godina izdavanja: Zagreb, 2009 Sva prava pridržana. Niti jedan dio ove knjige ne smije se reproducirati ili prenositi u bilo kojem obliku, niti na koji način. Zabranjeno je svako kopiranje, citiranje te upotreba knjige u javnim i privatnim edukacijskim organizacijama u svrhu organiziranih školovanja, a bez pisanog odobrenja nositelja autorskih prava. Copyright © Algebra d.o.o. CIP zapis dostupan u računalnom katalogu Nacionalne i sveučilišne knjižnice u Zagrebu pod brojem 710180 ISBN 978-953-7390-49-5 Sadržaj: 1. Poglavlje: ..... UVOD ..................................................................................................................................................................... 3 1.1 Uvod ................................................................................................................................................................................ 4 1.2 Temeljni pojmovi .............................................................................................................................................................. 4 1.3 GraĎevni elementi strukture podataka .............................................................................................................................. 5 2. Poglavlje: ..... ALGORITMI I SLOŽENOST ................................................................................................................................... 7 2.1 Algoritmi ........................................................................................................................................................................... 8 2.1.1 Povijest algoritma ........................................................................................................................................................ 8 2.1.2 Definicija...................................................................................................................................................................... 9 2.1.3 Primjeri algoritama ...................................................................................................................................................... 9 2.1.4 Zapisivanje algoritama u pseudokodu i C++ kodu ...................................................................................................... 10 2.1.5 NP - teški problemi .................................................................................................................................................... 12 2.1.6 Učinkovitost algoritma ............................................................................................................................................... 12 2.2 Sloţenost algoritama ...................................................................................................................................................... 13 2.2.1 Uvod.......................................................................................................................................................................... 13 2.2.2 Analiza algoritma ....................................................................................................................................................... 13 2.2.3 Veliko O .................................................................................................................................................................... 14 2.2.4 Veliko omega ............................................................................................................................................................ 18 2.2.5 Veliko theta ............................................................................................................................................................... 19 2.2.6 Zaključak ................................................................................................................................................................... 19 3. Poglavlje: ..... Rekurzija ............................................................................................................................................................. 20 3.1 Uvod .............................................................................................................................................................................. 21 3.2 Temeljna ideja rekurzije.................................................................................................................................................. 21 3.2.1 Glavne karakteristike i implementacija ....................................................................................................................... 22 3.2.2 Korištenje rekurzije .................................................................................................................................................... 23 3.2.3 Jednostavni primjer konstrukcije rekurzivnog algoritma ............................................................................................. 24 3.2.4 Sloţenost rekurzije .................................................................................................................................................... 24 3.2.5 Poznatiji rekurzivni algoritmi ...................................................................................................................................... 25 4. Poglavlje: ..... Jednostavne strukture podataka ....................................................................................................................... 29 4.1 Uvod .............................................................................................................................................................................. 30 4.2 Liste ............................................................................................................................................................................... 30 4.2.1 Lista kao apstraktni tip podataka ............................................................................................................................... 30 4.2.2 Implementacija liste pomoću polja ............................................................................................................................. 31 4.2.3 Implementacija liste pomoću pokazivača ................................................................................................................... 38 4.2.4 Dvostruko povezana lista........................................................................................................................................... 43 4.3 Stog ............................................................................................................................................................................... 46 4.3.1 Stog kao apstraktni tip podataka................................................................................................................................ 47 4.3.2 Implementacija stoga pomoću polja ........................................................................................................................... 47 4.3.3 Implementacija stoga pokazivačima .......................................................................................................................... 49 4.4 Red ................................................................................................................................................................................ 53 4.4.1 Red kao apstraktni tip podataka ................................................................................................................................ 54 4.4.2 Implementacija reda cirkularnim poljem ..................................................................................................................... 54 4.4.3 Implementacija reda pokazivačima ............................................................................................................................ 61 5. Poglavlje: ..... Složene strukture podataka ............................................................................................................................... 65 5.1 Stabla............................................................................................................................................................................. 66 5.1.1 Obilazak stabla .......................................................................................................................................................... 70 5.2 Binarno stablo ................................................................................................................................................................ 88 5.2.1 Binarno stablo kao apstraktni tip podataka ................................................................................................................ 90 5.2.2 Implementacija binarnog stabla pomoću polja ........................................................................................................... 90 5.2.3 Implementacija binarnog stabla pomoću pokazivača ................................................................................................. 95 5.3 Hrpa (heap) .................................................................................................................................................................... 98 5.3.1 Prioritetni red ............................................................................................................................................................. 98 5.3.2 Implementacija prioritetnog reda hrpom ................................................................................................................... 100 6. Poglavlje: ..... Algoritmi za pretraživanje ................................................................................................................................ 107 6.1 Uvod ............................................................................................................................................................................ 108 6.2 Linearno ili slijedno traţenje ......................................................................................................................................... 108 6.3 Binarno traţenje ........................................................................................................................................................... 109 7. Poglavlje: ..... Algoritmi za sortiranje ...................................................................................................................................... 113 7.1 Uvod ............................................................................................................................................................................ 114 7.2 Sortiranje izborom elementa (selection sort) ................................................................................................................. 115 7.3 Sortiranje zamjenom susjednih elemenata (bubble sort)............................................................................................... 117 7.4 Sortiranje umetanjem (insertion sort) ............................................................................................................................ 122 7.5 Sortiranje hrpom (heap sort) ......................................................................................................................................... 123 7.6 Shell sort ...................................................................................................................................................................... 125 7.7 Rekurzivni algoritmi ...................................................................................................................................................... 130 7.7.1 Merge sort ............................................................................................................................................................... 130 7.7.2 Quick sort ................................................................................................................................................................ 133 8. Poglavlje: ..... Tehnike adresiranja .......................................................................................................................................... 137 8.1 Uvod ............................................................................................................................................................................ 138 8.2 Tablice s direktnim adresiranjem .................................................................................................................................. 138 8.3 8.3.1 8.3.2 8.4 8.4.1 8.4.2 8.4.3 8.5 8.5.1 8.5.2 8.5.3 8.6 Hash tablice ................................................................................................................................................................. 139 Uklanjanje kolizija ulančavanjem ............................................................................................................................. 140 Uklanjanje kolizija korištenjem preljevnih područja................................................................................................... 141 Hash funkcije................................................................................................................................................................ 141 Metoda dijeljenja ..................................................................................................................................................... 142 Metoda mnoţenja .................................................................................................................................................... 142 Metoda univerzalnog hashiranja .............................................................................................................................. 143 Otvoreno adresiranje .................................................................................................................................................... 143 Linearno isprobavanje ............................................................................................................................................. 145 Kvadratno isprobavanje ........................................................................................................................................... 146 Dvostruko hashiranje ............................................................................................................................................... 147 Primjena hash funkcija u kriptografiji ............................................................................................................................ 148 8. Poglavlje: Tehnike adresiranja U ovom poglavlju naučiti ćete: Brzo pronalaţenje podataka po zadanom ključu Kako se realiziraju hash tablice OdreĎivanje adresa za zadane ulazne ključeve Str.138§ 8.1 §8. POGLAVLJE: TEHNIKE ADRESIRANJA Uvod Puno je različitih aplikacija koje zahtijevaju dinamičke strukture koje podrţavaju samo tzv. rječničke operacije, kao što su INSERT, SEARCH i DELETE. Na taj način, primjerice, prevoditelji za programske jezike odrţavaju simboličke tablice u kojima su ključevi elemenata stringovi koji odgovaraju ključnim riječima programskog jezika. Cijeli postupak adresiranja temelji se na tzv. ključevima koji predstavljaju poziciju našeg elementa u tablici. Jedna od učinkovitih struktura za implementaciju rječnika su hash (raspršene) tablice. Traţenje elementa u hash tablici moţe zahtijevati najviše O(n) vremena koliko treba za traţenje elementa u povezanoj listi. Po odreĎenim pretpostavkama moguće je ostvariti traţenje u hash tablici s očekivanim vremenom O(1). Moţemo reći da je hash tablica generalizacija jednostavnog polja. Direktno adresiranje unutar jednostavnog polja moţe nam osigurati učinkovito pronalaţenje odgovarajuće pozicije u polju za O(1) vremena. Spomenuto direktno adresiranje posebno je primjenjivo kada moţemo rezervirati toliki prostor za polje da za svaki ključ imamo jednu poziciju. MeĎutim, kada je broj stvarno pohranjenih ključeva relativno manji od ukupnog broja mogućih ključeva, hash tablice učinkovitija su alternativa za polja s direktnim adresiranjem, jer hash tablice tipično koriste veličinu polja proporcionalnu broju stvarno spremljenih ključeva. Umjesto da se ključevi kao indeksi polja koriste direktno, indeksi polja izračunavaju se iz ključa. 8.2 Tablice s direktnim adresiranjem Direktno adresiranje predstavlja jednostavnu tehniku koja dobro radi kada je skup ključeva S razumno malen. Uzmimo da aplikacija treba dinamički skup u kojem svaki element ima ključ koji je nastao iz skupa S = {0,1,….,m-1}, gdje m nije prevelik. Osim toga, pretpostavlja se da dva elementa nemaju isti ključ. Za prikaz takvog dinamičkog skupa koristimo polje ili tablicu s direktnim adresiranjem T[0..m-1], u kojoj svaka pozicija ili pretinac odgovaraju ključu iz skupa S. Na slici je ilustriran takav slučaj, ali podaci nisu direktno u tablici, već imamo tzv. satelitske podatke s ključem. Ako u skupu nema elementa s ključem k, tada je T[k]= NIL = Ø . T S (skup svih ključeva) . . .. . . . . . . 0 1 0 / 1 ključ 2 2 3 3 9 6 4 / 7 2 3 / 5 4 5 8 K (stvarni ključevi) / 6 / 7 8 / tel: 01 2222 182, e-mail: [email protected] satelitski podatak 5 8 9 §www.racunarstvo.hr§ Str.139§ §STRUKTURE PODATAKA I ALGORITMI Tzv. rječničke operacije su trivijalne: DIRECT-ADRESS-SEARCH(T,k) return T[k] DIRECT-ADRESS-INSERT(T,x) T[krey[k]] ← x DIRECT-ADRESS-DELETE(T,x) T[krey[k]] ← NIL Traţenje u tablici s direktnim adresiranjem Ubacivanje u tablicu s direktnim adresiranjem Brisanje iz tablice s direktnim adresiranjem Svaka od ovih operacija je brza i zahtijeva samo O(1) vremena. Za neke aplikacije elementi u dinamičkom skupu mogu biti pohranjeni u direktno adresiranoj tablici direktno, a ne preko satelitskih podataka. To je bolje nego da pospremamo ključ elementa i satelitski podatak s informacijom do kojeg pristupamo preko pokazivača. Na taj način moţemo element pospremiti direktno u pretinac i tako uštedjeti na prostoru. 8.3 Hash tablice U radu s direktnim adresiranjem mogu se javiti poteškoće, i to više njih. Primjerice, ako je skup S mogućih ključeva velik, tada pospremanje tablice T veličine |S| moţe biti nepraktično ili čak nemoguće zbog memorijskih ograničenja računala. Kako skup K ključeva koji su stvarno pospremljeni moţe biti relativno malen u odnosu na skup svih ključeva S, tada imamo previše neiskorištenog, a rezerviranog prostora unutar tablice T. Kada je skup K pohranjenih ključeva u rječniku puno manji od skupa S svih mogućih ključeva, tada hash ili raspršene tablice zahtijevaju puno manje prostora za pohranu od tablica s direktnim adresiranjem. Posebno, zahtjevi za pohranu mogu se reducirati na red ϴ(|K|), iako traţenje elementa u hash tablici i dalje zahtijeva samo O(1) vremena. Kod direktnog adresiranja element s ključem k pospremljen je u pretinac k. Kod hash tablica taj element je pospremljen u pretinac h(k), pri čemu se hash funkcija h koristi za računanje pretinca iz ključa k. U ovom slučaju funkcija h mapira cjelokupni prostor S ključeva na skup pretinaca iz hash tablice T[0 .. m-1], što se moţe zapisati i na sljedeći način: h: S → {0, 1, …., m-1} Tada kaţemo da se element s ključem k hashira na slot h(k) ili često da je h(k) hash vrijednost ključa k. Osnovna ideja je prikazana na sljedećoj slici. Zagreb – Ilica 242 §Visoka škola za primijenjeno računarstvo § Str.140§ §8. POGLAVLJE: TEHNIKE ADRESIRANJA T / 0 / S (skup svih ključeva) h(k1) .. . . . k1 k4 h(k4) k5 / k3 k2 h(k2) = h(k5) K (stvarni ključevi) / / h(k3) / m-1 Jedini problem koji se pojavljuje kod ovako dobre ideje za realizaciju hash tablice mogućnost je da dva ključa nakon primjene hash funkcije mogu zauzimati isti pretinac, tj. dolazi do kolizije. Sva sreća, razvijene su jako dobre tehnike za rješavanje konflikata izazvanih kolizijama. Naravno, idealno bi bilo izbjegavati kolizije. To moţemo pokušati postići izborom dobre hash funkcije h. Jedna od ideja moţe biti da h bude “slučajna“, pa da ili izbjegnemo koliziju ili njihov broj bitno smanjimo. U nastavku ćemo objasniti nekoliko učinkovitih tehnika za rješavanje problema kolizija. 8.3.1 Uklanjanje kolizija ulančavanjem Kod ulančavanja sve elemente koji se hashiraju na isti pretinac stavljamo u povezanu listu, kako to prikazuje slika u nastavku. U tom slučaju pretinac j sadrţi pokazivač na glavu liste svih pospremljenih elemenata koji se hashiraju na pretinac j. Ako takvih elementa nema, pretinac j sadrţi NIL. T / / S (skup svih ključeva) .. . . . . . . k1 k4 k2 k6 k5 k7 k3 k4 k5 k2 / k7 / / k8 K (stvarni ključevi) k1 k3 / / / k8 k6 / / tel: 01 2222 182, e-mail: [email protected] §www.racunarstvo.hr§ Str.141§ §STRUKTURE PODATAKA I ALGORITMI Operacije nad hash tablicom T, kod koje se kolizije rješavaju ulančavanjem, jednostavne su za implementaciju i glase: CHAINED – HASH - SEARCH(T,k) Traţenje elementa s ključem k u listi T[h(k)] Ubacivanje elementa x na početak liste T[h(key[x])] Brisanje elementa x iz liste T[h(key[x])] CHAINED - HASH - INSERT(T,x) CHAINED - HASH - DELETE(T,x) Najgori slučaj za vrijeme ubacivanja je O(1). Za pretraţivanje, najgori slučaj vremena izvoĎenja proporcionalan je duljini liste, tj. O(n) ako lista sadrţi n elemenata. Da bismo u praksi izbjegli da nam liste budu predugačke, izborom hash funkcije moţemo ostvariti jednostavno uniformno (jednoliko) hashiranje, tj. da svaki pretinac ima pribliţno isti broj elemenata u listi. 8.3.2 Uklanjanje kolizija korištenjem preljevnih područja Jedan od načina rješavanja kolizija je korištenje preljevnog područja. Uz primarno područje hash tablica sadrţi i dodatno preljevno područje koje je u pravilu znatno manje od primarnog. Naravno, izbor tih dvaju područja mora biti što bliţi optimalnom, s jedne strane da moţemo riješiti sve moguće kolizije i s druge strane da nam veličina ukupno rezerviranog prostora ne naraste previše. Kada dodajemo novi element i on doĎe u koliziju zbog zauzetog pretinca, tada ključ spremamo u prvo slobodno mjesto u preljevnom području (na slici vidimo primjer kada je ključ j u prvom pokušaju došao u koliziju s ključem k, jer je h(k) = h(j), te je stoga ključ j pospremljen u prvi slobodni pretinac u preljevnom području). Ako je pretinac u preljevnom području već zauzet, idemo na sljedeći dok ne naĎemo slobodni pretinac. Moguća su i rješenja s višestrukim preljevnim područjima ili uvoĎenjem potpuno drugog mehanizma za upravljanje preljevnim područjem, no to izlazi iz okvira ove skripte. k 0 h(k) j k o Primarno područje 0 h(i) i o 0 i j 0 8.4 o Preljevno područje Hash funkcije Razmotrit ćemo osnovna pitanja realizacije dobrih hash funkcija i prikazati tri načina njihova kreiranja: hashiranje dijeljenjem hashiranje mnoţenjem univerzalno hashiranje Zagreb – Ilica 242 §Visoka škola za primijenjeno računarstvo § Str.142§ §8. POGLAVLJE: TEHNIKE ADRESIRANJA Dobra hash funkcija prije svega treba udovoljiti kriteriju jednostavnog uniformnog hashiranja. U tom slučaju svaki ključ ima jednaku vjerojatnost da će se hashirati na bilo koji od m pretinaca. Pretpostavimo da je svaki ključ proizašao nezavisno iz skupa S, sukladno nekoj funkciji vjerojatnosti P, gdje je P(k) vjerojatnost pojave ključa k. Teorijski je ovaj problem teško riješiti jer vrlo rijetko poznajemo funkciju distribucije P. Stoga češće pribjegavamo heurističkim tehnikama kreiranja hash funkcija koje u statističkome smislu funkcioniraju dobro. Druga vaţna stvar za kreiranje hash funkcija jest pretpostavka da je skup S ključeva iz skupa N={0, 1, 2, …} prirodnih brojeva. Ako ključ nije prirodan broj, moramo pronaći način kako ga interpretirati kao prirodni broj. Primjerice, ključ koji je string moţe se interpretirati kao cjelobrojni broj. String AB je sastavljen od cjelobrojnih vrijednosti (65, 66) na temelju ASCII skupa znakova. 8.4.1 Metoda dijeljenja Kod metode dijeljenja za kreiranje hash funkcije, mapiramo ključ k u jedan od m pretinaca uzimanjem ostatka dijeljenja ključa k s m. U tom slučaju hash funkcija glasi: h(k) = k mod m Npr., ako hash tablica ima m=15 pretinaca i ključ je k=66, tada je h(k) = 6. Kako ova metoda zahtijeva samo jednu operaciju dijeljenja, moţemo reći da je ona zaista brza. Potrebno je posvetiti paţnju izboru broja m koji ne bi trebao biti potencija broja 2, jer ako je m=2p, tada h(k) poprima samo p najniţih bitova ključa k. Naime, bolje je da hash funkcija ovisi o svim bitovima ključa. TakoĎer, treba izbjegavati da m bude potencija broja 10 ako aplikacija radi s decimalnim brojevima kao ključevima, jer se tada moţe dogoditi da hash funkcija ne ovisi o svim decimalnim znamenkama ključa. Najbolje je za vrijednost m birati prost ili prim broj koji nije preblizu stvarnoj potenciji broja 2. Na primjer, pretpostavimo da ţelimo alocirati hash tablicu, kod koje se kolizija rješava ulančavanjem, da bismo čuvali n = 2000 stringova znakova, pri čemu je jedan znak 8 bita (1 byte). Ako pretpostavim da ne trebamo imati više od 3 ispitivanja kod neuspješnog traţenja, tada nam treba hash tablica veličine m = 701. Ovaj broj je izabran kao prim broj najbliţi odnosu α = 2000/3, a istodobno nije blizak nijednoj potenciji broja 2. U tom slučaju, ako svaki ključ smatramo cjelobrojnim brojem, hash funkcija glasi H(k) = k mod 701. 8.4.2 Metoda množenja Metoda mnoţenja za kreiranje hash funkcije radi u dva koraka. Prvo, pomnoţimo ključ k konstantom A, izabranom iz području 0 < A< 1 i izdvojimo decimalni dio (frakcijski) od produkta k*A. Tada pomnoţimo tu vrijednost s m i zaokruţimo rezultat. Jednostavno rečeno, hash funkcija glasi: h(k) = floor[ m(k*A mod 1) ] gdje „ k*A mod 1“ znači decimalni dio od k*A, takav da je k*A – floor[k*A]. Prednost ove metode u tome je da izbor za m više nije kritičan. Premda ta metoda radi s bilo kojom vrijednosti konstante A, za neke vrijednosti ipak radi bolje. Optimalan izbor ovisi o svojstvima podataka koji se trebaju hashirati. Knuth je razmatrao taj problem izbora konstante A i pokazao da sljedeća konstanta jako dobro radi: A ≈ (sqrt (5) -1)/2 = 0.6180339887…. tel: 01 2222 182, e-mail: [email protected] §www.racunarstvo.hr§ Str.143§ §STRUKTURE PODATAKA I ALGORITMI Primjer: Ako imamo ključ k= 123456 i zadan je m = 10000, a konstanta A je uzeta kako je prethodno predloţeno, tada dobijemo: h(k) = floor(10000*(123456*0.61803…mod 1)) = floor(10000*(76300.0041151… mod 1)) = floor(10000*0.0041151..) = floor(41.151…) = 41 8.4.3 Metoda univerzalnog hashiranja Ako zlonamjerni korisnik bira ključeve koji će se hashirati, tada moţe odabrati da se svih n ključeva hashira u isti pretinac, zbog čega je srednje vrijeme dohvata ϴ(n). Gotovo svaka fiksna hash funkcija ranjiva je na takav tip ponašanja. Jedini način za izbjegavanje takvih situacija izbor je hash funkcije slučajno, tako da ona bude neovisna o ključevima koji će stvarno biti pospremljeni u tablicu. Taj pristup se zove univerzalno hashiranje i u prosjeku ima dobre performanse, bez obzira na to kakvi su ključevi odabrani. U najkraćim crtama, hash funkcija se bira slučajno u trenutku izvršenja programa za hashiranje, iz paţljivo dizajnirane klase funkcija, no tom se metodom nećemo detaljnije baviti. 8.5 Otvoreno adresiranje Kod otvorenog adresiranja svi se elementi pospremaju u hash tablicu sami po sebi. U tom slučaju svaki ulaz tablice sadrţi ili element iz dinamičkog skupa ili NIL. Kada traţimo element, mi sustavno istraţujemo pretince tablice dok ne pronaĎemo element ili se ne uvjerimo da ga nema u tablici. U ovom slučaju nemamo ni liste ni elemente pospremljene van tablice, kao kod ulančavanja. Kako kod otvorenog adresiranja hash tablica moţe biti napunjena tako da više nijedno umetanje ne bude moguće, faktor opterećenja α ne smije prijeći 1. Naravno, moglo bi se započeti s pospremanjem u povezanu listu radi ulančavanja unutar hash tablice, ali prednost otvorenog adresiranja i u tome je da se izbjegnu bilo kakvi pokazivači. Umjesto toga, izračunava se niz pretinaca koji će se ispitivati. Za umetanje uporabom otvorenog adresiranja, uspješno ispitujemo ili isprobavamo hash tablicu dok ne naĎemo prazan pretinac u koji umećemo ključ. Umjesto da imamo fiksni poredak od 0, 1,…,m-1 (što zahtijeva O(n) vremena traţenja), niz pozicija koje moraju biti isprobane ovisi o ključevima koji su već umetnuti. Realizacija umetanja uporabom otvorenog adresiranja ostvaruje se uzastopnim isprobavanjima hash tablice dok se ne naĎe prazan pretinac u koji se umetne ključ. S otvorenim adresiranjem za svaki ključ niz proba (h(k,0), h(k,1), …,h(k,m - 1)) ostvaruje se permutiranjem od (0, 1, …, m - 1), tako da je svaka pozicija hash tablice moguć pretinac za novi ključ kako se tablica puni. Sljedeći pseudokod ilustrira operaciju umetanja uz pretpostavku da su elementi u hash tablici T ključevi bez satelitskih (dodatnih) informacija, tj. ključ k je identičan elementu koji sadrţi ključ k. Svaki pretinac sadrţi ili ključ ili NIL (ako je pretinac prazan). Zagreb – Ilica 242 §Visoka škola za primijenjeno računarstvo § Str.144§ §8. POGLAVLJE: TEHNIKE ADRESIRANJA HASH-INSERT (T,k) 1 i←0 2 repeat j ←h(k,i) 3 if T[j] = NIL 4 then T[j] = ← k 5 return j 6 else i ← i + 1 7 until i = m 8 error "hash tablica je puna" Algoritam za traţenje ključa k izvodi probavanje istog niza pretinaca koji je algoritam za umetanje realizirao kada je ključ k bio umetan. Zato algoritam traţenja moţe biti završen (neuspješno) kada je pronaĎen bilo koji prazan pretinac jer je ključ k trebao biti umetnut baš ondje i nigdje drugdje u nizu isprobavanja. HASH-SEARCH (T,k) 1 i←0 2 repeat j ←h(k,i) 3 if T[j] = k 4 then return j 5 i←i+1 6 until T[j] = NIL or i = m 7 return NIL Još treba naglasiti da je brisanje elementa u hash tablicama s otvorenim adresiranjem prilično teško, jer ne moţemo pretinac i, u kojem ţelimo obrisati ključ, jednostavno postaviti na NIL jer tako ne bismo mogli dohvatiti bilo koji ključ k za vrijeme čijeg umetanja smo isprobali pretinac i, te ga našli zauzetog. Jedno od rješenja je da ga označimo vrijednošću DELETED umjesto NIL, no u tom se slučaju moraju modificirati procedure HASH - SEARCH i HASH - INSERT. Nadalje, pretpostavit ćemo tzv. uniformno (jednoliko) umetanje u hash tablicu, što znači da svaki ključ ima jednaku vjerojatnost realizacije bilo koje od m! permutacija niza za isprobavanje {0, 1, …, m – 1}. Treba naglasiti da se vrlo teško postiţe pravo uniformno adresiranje, pa se u praksi postiţe uglavnom aproksimacija uniformnog umetanja u hash tablicu. Od tehnika koje se koriste za izračunavanje niza za isprobavanje, potrebnog za otvoreno adresiranje, poznate su tri metode: linearno isprobavanje kvadratno isprobavanje dvostruko hashiranje (isprobavanje) Sve tri tehnike jamče da su (h(k,0), h(k,1), …,h(k,m - 1)) permutacije iz skupa (0, 1, …, m - 1) za svaki ključ k. Dvostruko hashiranje moţe imati najviše isprobavanja, ali, što je očekivano, postiţe i najbolji rezultat. tel: 01 2222 182, e-mail: [email protected] §www.racunarstvo.hr§ Str.145§ 8.5.1 §STRUKTURE PODATAKA I ALGORITMI Linearno isprobavanje Za zadanu funkciju h': U → {0, 1, …, m – 1}, metoda linearnog isprobavanja koristi sljedeću hash funkciju: h(k, i) = (h' (k) + i ) mod m za svaki i = 0, 1, …, m – 1. Za zadani ključ k prvi isprobani pretinac je T[h' (k)]. Sljedeći isprobavani pretinac bio bi T[h' (k) + 1] i tako dalje do pretinca T[m - 1]. Nakon toga se prebacujemo na pretince T[0], T[1], … dok konačno ne isprobamo pretinac T[h' (k) - 1]. Kako pozicija početne probe odreĎuje cijeli niz isprobavanja, samo m različitih nizova isprobavanja koristi se kod linearnog isprobavanja. Linearno je isprobavanje jednostavno za realizaciju, ali se susreće s problemom poznatim kao primarni klastering, tj. punjenjem tablice stvaraju se klasteri ili nakupine zauzetih adresa, pa se povećava broj neuspješnih proba. Primjer: Potrebno je umetnuti niz ključeva 5, 22, 11, 3, 8, 27, 33, 45, 9, 28 u tablicu T[] s 12 pretinaca. Hash funkcija za linearno isprobavanje glasi: h(k, i) = (3*k + i ) mod m gdje je m = 12, i = 0, 1, …, 11. Nakon hashiranja dobije se sljedeća hash tablica: 0 1 2 3 4 5 6 7 8 9 10 11 T[] 8 28 5 33 45 22 9 11 3 27 Iz donje tablice vidimo koliko je za koji ključ bilo potrebno isprobavanja, pri čemu su tamnosivom nijansom označene konačne adrese. Vidimo da su za tri ključa trebala 2 isprobavanja, za dva ključa trebala su 3 isprobavanja, a za jedan ključ čak 5 isprobavanja. ključevi i - isprobavanje plus 0 plus 1 plus 2 plus 3 plus 4 Zagreb – Ilica 242 5 22 11 3 6 9 3 8 adrese 9 0 10 27 33 45 9 28 9 10 11 3 4 3 4 5 3 4 5 6 7 0 1 §Visoka škola za primijenjeno računarstvo § Str.146§ 8.5.2 §8. POGLAVLJE: TEHNIKE ADRESIRANJA Kvadratno isprobavanje Tehnika kvadratnog isprobavanja koristi hash funkciju sljedećeg oblika: h(k, i) = (h' (k) + c1 i + c2i2 ) mod m gdje je (kao i kod linearnog isprobavanja) h' pomoćna hash funkcija, c1 i c2 ≠ 0 su pomoćne konstante, a i = 0, 1, …, m – 1. Početna isprobana pozicija je T[h' (k)], kasnije isprobavane pozicije su odreĎene kvadratom broja i. Ova metoda radi puno bolje od linearnog isprobavanja, ali da bi se ostvarila punua uporaba hash tablice, vrijednosti c1, c2 i m su ograničene. Ako dva ključa imaju istu početnu poziciju isprobavanja, tada je njihov niz isprobavanja isti jer h(k 1, 0) = h(k2, 0) povlači da je h(k1, i) = h(k2, i). To dovodi do takozvanog sekundarnog klasteringa, tj. takoĎer se povećava broj neuspješnih proba. Primjer: Potrebno je umetnuti niz ključeva 77, 44, 26, 98, 7, 48, 34, 49, 29, 13 u tablicu T s 12 pretinaca. Hash funkcija glasi: h(k, i) = (2*k + 1*i2 ) mod m gdje je m = 12, c1 = 0, c2 = 1, i = 0, 1, …, 11. Nakon odreĎivanja adresa tehnikom kvadratnog isprobavanja dobije se sljedeća hash tablica: 0 1 2 3 4 5 6 7 8 9 10 11 T[] 48 7 49 44 26 13 98 34 77 29 Iz tablice u nastavku vidimo koliko je za koji ključ bilo isprobavanja, pri čemu su tamnosivom nijansom označene konačne adrese. Vidimo da su za četiri ključa trebala 2 isprobavanja, a za dva ključa 3 isprobavanja, što je bolji rezultat nego kod linearnog isprobavanja. tel: 01 2222 182, e-mail: [email protected] §www.racunarstvo.hr§ Str.147§ §STRUKTURE PODATAKA I ALGORITMI ključevi i - isprobavanje 0 1 2 3 4 8.5.3 77 44 26 10 4 4 5 98 7 Adrese 4 2 5 8 48 34 49 29 13 0 8 9 2 3 10 11 2 3 6 Dvostruko hashiranje Dvostruko hashiranje je jedna od najboljih metoda dostupnih za otvoreno adresiranje. Permutacije koje se generiraju imaju vrlo bliska svojstva tzv. slučajno izabranim permutacijama. Dvostruko hashiranje koristi hash funkciju oblika h(k, i) = (h1 (k) + ih2(k) ) mod m gdje h1 i h2 predstavljaju pomoćne hash funkcije. Početna pozicija isprobavanja je T[h1 (k)], a ostale nastavne pozicije isprobavanja odreĎene su s h2(k) i dijeljenjem po modulu m. Kod ove tehnike niz isprobavanja, nakon početnog, varira dva puta za ključ k (kao što pokazuje slika). k 0 h(k) j k o h1(j) 0 h(i) i o 0 i j o h2(j) 0 Primjer: Potrebno je umetnuti niz ključeva 7, 98, 58, 77, 79, 48, 14, 49, 29, 83 u tablicu T[] s 12 pretinaca. Hash funkcije za dvostruko hashiranje glase h1(k) = k mod m h2(k) = 1 + (k mod m') gdje je m = 12, m' = 11, i = 0, 1, …, 11. Zagreb – Ilica 242 §Visoka škola za primijenjeno računarstvo § Str.148§ §8. POGLAVLJE: TEHNIKE ADRESIRANJA Nakon izvršenog adresiranja dvostrukim hash funkcijama, hash tablica glasi: 0 1 2 3 4 5 6 7 8 9 10 11 T[] 48 49 98 79 14 77 7 29 58 83 Iz tablice u nastavku vidimo koliko je za koji ključ bilo isprobavanja, pri čemu su tamnosivom nijansom označene konačne adrese. Vidimo da je samo za tri ključa trebalo napraviti dvostruko hashiranje kroz jedno isprobavanje, što je puno bolji rezultat i od linearnog i od kvadratnog isprobavanja, ali je lošije što se tiče performansi jer koristimo dvije hash funkcije. Primjer je pokazao da su svojstva dvostrukog hashiranja vrlo blizu performansama “idealnog“ uniformnog hash adresiranja. ključevi hash funkcija h1, i=0 i *h2, i=1 i *h2, i=2 i *h2, i=3 8.6 7 98 58 7 2 10 77 79 adrese 5 7 3 48 14 49 29 83 0 2 4 1 5 8 11 Primjena hash funkcija u kriptografiji Pored tipične primjene hash tablica za pohranu ključeva radi brzog pretraţivanja, vrlo je česta primjena i u kriptografiji. Proces kriptiranja informacija je proces pretvorbe informacije iz njezina normalnog čitljivog prikaza u potpuno nečitljiv niz koji je moguće pročitati samo uz posebna znanja. Jedan od pristupa je korištenje hash funkcija koje omogućuju korištenje jednosmjernih algoritama koji, primijenjeni na jedinstvene ulaze (poruke) promjenjive duljine, uvijek daju jedinstven izlaz jedinstvene fiksne duljine, nazvan hash. Naravno, kod hash algoritama poţeljno je da uopće nema kolizija, mada neki algoritmi mogu imati kolizije za različite ulaze. Od poznatijih algoritama za kriptiranje spomenut ćemo neke: SHA (Secure Hash Algorithm), MD5 (Message-Digest algorithm 5), CRC (Cyclic Redundancy Check) itd. Svaki od tih algoritama je posebno područje koji izlazi izvan domene ovog kolegija, te ih stoga nećemo objašnjavati. Kao primjer ipak istaknimo kriptiranje lozinke (password) za nekog korisnika. Korisničko ime (user name) Lozinka (password) Jsmith mypass tel: 01 2222 182, e-mail: [email protected] §www.racunarstvo.hr§ Str.149§ §STRUKTURE PODATAKA I ALGORITMI Korisničko ime (user name) Kriptirana lozinka (password) Jsmith 5yfRRkrhJDbomacm2lsvEdg4GyY= Ako imamo samo jedno slovo razlike u lozinci, rezultat hashiranja bit će potpuno drukčiji: Tekstualni oblik lozinke (password) Kriptirana lozinka (password) Mypass 5yfRRkrhJDbomacm2lsvEdg4GyY= mypast hXdvNSKB5Ifd6fauhUAQZ4jA7o8= Za različite algoritme uzima se različiti broj bitova za hashiranje, npr. MD5 (128 bitova) ili SHA-1 (160 bitova). Naravno, što je veći broj bitova, to je puno teţe probijanje kriptiranih podataka “golom“ snagom računala jer hash algoritmi nisu reverzibilni, tj. nije moguće iz kriptirane informacije otkriti kako glasi hash funkcija, pa je jedini način proboja isprobavanje brojnih kombinacija. Zagreb – Ilica 242 §Visoka škola za primijenjeno računarstvo §
© Copyright 2024 Paperzz