You are on page 1of 8

2.

Hasítótáblák (Tördelőtáblák)
2.1. Halmaz
Értékhalmaz: Halmaz = { H : H ⊆ E}
Műveletek:
H : Halmaz, x : E, I : Iterator

{Igaz} Letesit(H) /
{H = 0}
{H = H} Megszuntet(H) {Hamis}
{H = H} Uresit(H) /
{H = 0}
{H = H} Eleme(H, x) {Eleme = x ∈ Pre(H)}
{H = {a1 , . . . , an }} Elemszam(H) {Elemszam = n}
{H = H} Bovit(H, x) {H = Pre(H) ∪ {x}}
{H = H} Torol(H, x) {H = Pre(H) − {x}}
{H = H} IterKezd(H, I) {}
{I = I} IterAd(I, x) {}
{I = I} IterVege(I) {}

public interface Halmaz<E> extends Iterable<E>{


public int Elemszam();
public void Uresit();
public boolean Eleme(E x);
public void Bovit(E x);
public boolean Torol(E x);
public E Keres(E x);
}

Ha a halmaz elemein alapértelmezett egy lineáris rendezési reláció, akkor az RHalmaz adattípust használjuk.

public interface RHalmaz<E extends Comparable<E>>


extends Halmaz<E>, Iterable<E>{
}

A Halmaz adattípus megvalósításai:


HalmazB: bitvektor adatszerkezettel; E=1..n
HalmazT: tömb adatszerkezettel,
HalmazL: lánc adatszerkezettel,
HalmazHL: hasítótábla (ütközésfeloldás láncolással) adatszerkezettel,
HalmazHN: hasítótábla (ütközésfeloldás nyílt címzéssel) adatszerkezettel.
Az RHalmaz adattípus megvalósításai:
HalmazBKF: AVL-kiegyensúlyozott bináris keresőfa adatszerkezettel,
HalmazAVL: AVL-kiegyensúlyozott bináris keresőfa adatszerkezettel,
HalmazPFFa: piros-fekete fa adatszerkezettel.

Diszkrét ismétléses vezérlés megvalósításai iterátorral.

Forall x in H Do
M(x);

java megvalósítás:

1
Iterator<E> I=H.iterator(); //IterKezd(H,I)
while (I.hasNext()){ //!IterVege(I)
x=I.next(); //IterAd(I,x)
M(x);
}

vagy kiterjesztett for-ciklussal:

for (E x:H)
M(x);

Legyen U az Elemtip, univerzum,


H = {a1 , · · · , an } ⊆ U
Vegyünk egy T:Array[0..M-1] of Elemtip tömböt, amelyben a H halmazt tárolni akarjuk.
Válasszunk egy
h : U → {0, · · · , M − 1}
függvényt, amely minden ai halmazelemre megadja azt a táblázat indexet, ahol az elemet tárolni akarjuk, T [h(ai )] := ai .
Ha ai 6= a j és h(ai ) = h(a j ) ütközés.

2.2. Ütközésfeloldás láncolással


Legyen T:Array[0..M-1] of Lanc, és legyen T [ j] a {x : x ∈ H ∧ h(x) = j} elemek lánca.

T
0 ...

j ...

M−1 ...

1. ábra. Adatszerkezet ütközésfeloldás láncolással módszerhez.

public class HasitoLanc<E>{


private Lanc<E>[] Tar;
private int eszam;
private int meret=100;

public HasitoLanc(int m){


Tar=(Lanc<E>[])new Lanc[m];
meret=m;
}
protected int hf(E x){ //a hasító függvény
return x.hashCode()%meret;
}
public boolean Eleme(E x){
int i=hf(x);
Lanc<E> p=Tar[i];
while (p!=null && !x.equals(p.elem))
p=p.csat;

2
return p!=null;
}

public E Keres(E x){


int i=hf(x);
Lanc<E> p=Tar[i];
while (p!=null && !x.equals(p.elem))
p=p.csat;
if (p!=null)
return p.elem;
else
return null;
}
public void Bovit(E x){
int i=hf(x);
Tar[i]=new Lanc<E>(x, Tar[i]);
++eszam;
}

public boolean Torol(E x){


int i=hf(x);
Lanc<E> p=Tar[i];
Lanc<E> pp=p;
while (p!=null && !x.equals(p.elem)){
pp=p;
p=p.csat;
}
if (p!=null){
if (pp==p)
Tar[i]=p.csat;
else
pp.csat=p.csat;
--eszam;
return true;
}
else
return false;
}

2.3. Ütközésfeloldás nyílt címzéssel


Pótvizsgálat (próbasorozat)
h : U × {0, · · · , m − 1} → {0, · · · , m − 1}
hh(k, 0), · · · , h(k, m − 1)i
h0, · · · , m − 1i egy permutációja minden k kulcsra.
A k kulcsú elem helye a táblázatban az a j = h(k, i), amelyre

Min{i : T [h(k, i)] = Szabad}

Ekkor a próbák száma i + 1.


Például, ha U = Integer, h(x, i) = (x + i) mod m. Ezt a tördelőfüggvényt alkalmazva bővítsük a kezdetben üres táblát egymás
után a 15, 30, 16, 35, 20, és 28 elemekkel. Majd töröljük a táblából a 16-os elemet. Ha ezt követően a 28 elemet keressük a
táblában, akkor a h2, 3, 4, 5, . . .i próbasorozat kell alkalmazni, de a keresés nem állhat meg a 3 indexű törölt táblaelemnél. Tehát
a táblában a törölt helyeket nem tekinthetjük üresnek. Választanunk kell egy Ures és egy ettől különböző Torolt konstans kulcs
értéket az üres, illetve a törölt táblaelemek jelölésére.

3
0 1 2 3 4 5 6 7 8 9 10 11 12
T 15 16 30 28 20 35

2. ábra. Tördelőtábla a 15, 30, 16, 35, 20, és 28 elemekkel való bővítés után.

0 1 3 4 5 6
2  7 8 9 10 11 12
T 
 20 35
15 30 28

3. ábra. Tördelőtábla a 16 elem törlése után.

public class TordeloNyilt<E>{


private E[] Tar;
private int eszam;
private int meret=100;
private final E TOROLT;
private final boolean tobb;

protected int proba(E x, int i){


return (x.hashCode()+i)%meret;
}
public TordeloNyilt(){
tobb=true;
Tar=(E[])new Object[meret];
TOROLT= (E)new Object();
}
public TordeloNyilt(int m){
tobb=true;
meret=m;
Tar=(E[])new Object[meret];
TOROLT= (E)new Object();
}
public TordeloNyilt(boolean tobb){
this.tobb=tobb;
Tar=(E[])new Object[meret];
TOROLT= (E)new Object();
}
public TordeloNyilt(int m, boolean tobb){
this.tobb=tobb;
meret=m;
Tar=(E[])new Object[meret];
TOROLT= (E)new Object();
}

public int Keres(E x){


//az x elem táblabeli helyének keresése
int i=0;
int j;
do{
j=proba(x,i);
if (Tar[j]!=null && x.equals(Tar[j]))
return j;
}while (++i<meret && Tar[j]!=null);

4
return -1;
}
public boolean Eleme(E x){
return Keres(x)>=0;
}

public void Bovit(E x){


int i=0;
int j;
if (!tobb && Eleme(x)) return;
do{
j=proba(x,i);
if (Tar[j]==null || Tar[j]==TOROLT){
Tar[j]=x;
eszam++;
return;
}
}while (++i<meret);
throw new RuntimeException("A tábla megtelt");
}
public boolean Torol(E x){
int j=Keres(x);
if (j>=0){
Tar[j]=TOROLT;
eszam--;
return true;
}else
return false;
}
}

2.4. Pótvizsgálatok (próbasorozatok).


Lineáris pótvizsgálat
h(k, i) = (h0 (k) + i) mod m ,
h0 : U → {0, · · · , m − 1}

Négyzetes pótvizsgálat
h(k, i) = (h0 (k) + c1 · i + c2 · i2 ) mod m ,
h0 : U → {0, · · · , m − 1}

Dupla tördelés
h(k, i) = (h1 (k) + i · h2 (k)) mod m ,
h1 , h2 : U → {0, · · · , m − 1}
A h2 (k) értékeknek relatív prímnek kell lenni a táblázat m méretéhez. Pl. h1 (k) = k mod m és h2 (k) = 1 + (k mod m0 ), ahol
m0 = m − 1.

2.5. Tördelőfüggvények
Tegyük fel, hogy a k kulcs egész számérték.
Az osztás módszere: h(k) = k mod m
Ha k = ck . . . c1 c0 string, akkor vegyük a b = 256-os számrendszerbeli értékét:
a = (ck . . . c1 c0 )b = ∑ki=0 bi ∗ |ci |

5
(ahol |c| a c karakter kódja) majd képezzük a h(k) = a mod m értéket. A modulus műveletre teljesül az alábbi két azonosság.

(a + b) mod m = (a mod m + b mod m) mod m


(a ∗ b) mod m = ((a mod m) ∗ (b mod m)) mod m

static int h(String S, int m){


int k=S.length();
int a=0;
for (int i=k-1; i>=0; i--){
int c=Character.getNumericValue(S.charAt(i));
a=((a<<8)+c)%m;
}
return a;
}

A szorzás módszere: h(k) = bm(k · A mod 1)c


ahol k · A mod 1 = k ·√
A − bk · Ac
0 < A < 1, pl. A = ( 5 − 1)/2 = 0.6180 · · ·

2.6. Tördelőtáblák hatékonysági elemzése


Legyen h : U → {0, . . . , m − 1} a tördelőfüggvény.
α= n
m a tábla telítettségi tényezője.
Egyenletességi feltétel:

1
∑ Pr(k) =
m
( j = 0, · · · , m − 1)
k:h(k)= j

Feltesszük, hogy h(k) olcsó, azaz Θ(1) időben kiszámítható.

Ütközésfeloldás láncolással
A B OVIT futási ideje legrosszabb esetben is O(1).
A K ERES és TOROL futási ideje legrosszabb esetben O(n).
(Minden elem egyetlen láncban van és a keresés szekvenciális.)
Ha a T [ j] lánc hossza n j , akkor
n = n0 + n1 + · · · + nm−1
és n j várható értéke n/m = α. Így egy k kulcsú elem keresésének ideje lineárisan függ a T [h(k)] lánc nh(k) hosszától. A T [h(k)]
lánc azon elemeinek számát tekintsük, amelyekkel a keresés során összehasonlítódik a keresett k kulcs. Két esetet kell tekinte-
nünk, az első az, amikor a keresés sikeres, a másik pedig a sikertelen keresés.

2.1. tétel. Ha teljesül az egyenletességi feltétel, akkor láncolással történő ütközésfeloldás esetén a sikertelen keresés átlagos
ideje Θ(1 + α).

Bizonyítás. Az egyenletességi feltétel miatt bármely k kulcsra, ami még nincs a táblában, egyforma valószínűséggel adódik
bármely j = h(k) táblaindex. Ezért egy k kulcs sikertelen keresésének átlagos ideje megegyezik annak átlagos idejével, hogy
a T [h(k)] láncot végigkeressük. Ennek a láncnak az átlagos hossza α, tehát h(k) kiszámításával együtt az átlagos futási idő
Θ(1 + α). 
Sikertelen keresés esetén annak valószínűsége, hogy egy adott láncban keresünk, azonos a lánc hosszával.

2.2. tétel. Ha teljesül az egyenletességi feltétel, akkor láncolással történő ütközésfeloldás esetén a sikeres keresés átlagos ideje
Θ(1 + α).

Bizonyítás. Az x elem sikeres keresése esetén megvizsgált elemek várható száma eggyel nagyobb, mint azoknak az elemeknek a
várható száma, amelyek megelőzik x-et az x-et tartalmazó láncban. Az x-et megelőző elemeket x beszúrása után szúrtuk be, mivel
új elemet mindig a lánc elejéhez illesztünk. Tehát átlagolni kell a táblázat n elemére az 1+azon elemek várható száma értékeket,

6
amelyeket x után adtunk x láncához. Legyen xi a táblázatba i-edikként beszúrt elem és legyen ki = xi .kulcs. Az egyenletességi
feltétel miatt Pr{h(ki ) = h(k j )} = 1/m. Ezért a sikeres keresés során vizsgált elemek számának várható értéke
!
1 n n
1 1 n

n i=1
1+ ∑
m
= 1+ ∑ (n − i)
nm i=1
j=i+1
!
n n
1
= 1+
nm ∑n− ∑i
i=1 i=1
 
1 2 n(n + 1)
= 1+ n −
nm 2
n−1
= 1+
2m
α α
= 1+ − .
2 2n
Tehát a sikeres keresés futási ideje, beszámítva h(k) kiszámítását is
α α
Ta (n) = Θ(2 + − ) = Θ(1 + α)
2 2n

A nyílt címzés hatékonyságának elemzése
A legjobb eset
K ERES, B ÖVIT, TOROL : O(1)

A legrosszabb eset
B ÖVIT: O(n)
K ERES, TOROL : O(n)
Átlagos eset

1
2.3. tétel. Nyílt címzés esetén a sikertelen keresés során a próbák számának várható értéke ≤ 1−α .

Bizonyítás. pi = Pr{pontosan i táblaelem foglalt} azaz, i a legkisebb index, amelyre T [h(k, i)] = Szabad}
Ekkor a próbák számának várható értéke:
n
1 + ∑ i pi
i=0
Jelölje qi annak valószínűségét, hogy legfeljebb i próbát kell végezni. Tehát
n n n
1 + ∑ i pi = ∑ i (qi − qi−1 ) = ∑ qi
i=0 i=0 i=0
n
q1 = m
n n−1
q2 = m m−1

qi = n n−1
m m−1
n+1−i
· · · m+1−i ≤ ( mn )i = αi . Tehát
n n ∞
1
1 + ∑ i pi ≤ ∑ αi ≤ ∑ αi ≤
i=0 i=0 i=0 1−α

A B OVIT algoritmus átlagos futási ideje : 1


O( 1−α ). 
2.4. tétel. Nyílt címzés esetén a sikeres keresés során a próbák számának várható értéke ≤ α1 ln (1−α)
1
.

Bizonyítás. Sikeres keresés ugyanazon próbasorozatot hajtja végre, mint amikor az elemet beraktuk a táblázatba.
m
Ha a k kulcsú elem i-edikként került a táblázatba, akkor a próbák száma m−i . Tehát a próbák számának várható értéke:

1 n−1 m m n−1 1 1

n i=0 m − i
= ∑ = (Hm − Hm−n ),
n i=0 m − i α

7
ahol Hi = ∑ij=1 1j az i. harmonikus szám. 1/x csökkenő, így

m
1 1
α
(Hm − Hm−n ) = ∑
α k=m−n+1
1/k ≤
Z m
1 1 m 1 1
(1/x)dx = ln = ln
α m−n α m−n α 1−α

Tehát a Torol algoritmus átlagos futási ideje (= sikeres keresés) 1
O( α1 ln 1−α )
Pl. ha α = 0.5 akkor 1.387, ha α = 0.9 akkor 2.559 próba kell átlagosan a törléshez.

You might also like