0
1 1001 1
1100 j = i =1
Трябва да увеличим масива на указателите с 1 => i = 2 (т.е. 2 бита)
0001 1
0000
00
01 1001 2
10 1010
11
1100 2
Сега нека вмъкнем още два записа, които се хешират до 0000 и 0111
- 0000 директно го записваме в първия блок
- 0111 ще предизвика делене, но констатираме че j < i
i = 2
0001 2
0000
00
01 0111 2
10
11 1001
1010 2
1100 2
Когато трябва да вмъкнем още един запис, който се хешира до 1000 - той трябва да се вмъкне в трети блок, но няма място, тогава увеличаваме i с 1, т.е. удвояваме броя на указателите
i = 3 0000 2
0001
000
001 0111 2
010
011 1001 3
100 1000
101
110 1010 3
111
1100 3
Преимущества:
-
най – важно преимущество на линейните хеш таблици е че никога не търсим в повече от един блок;
-
масива с указатели е буфериран в оперативната памет, т.е. достъпи до него не се извършват, а достъпите са до блоковете в които сочат указателите;
Недостатъци:
-
когато се удвоява размера на масива на кофите при голямо i трябва да се извърши доста работа, т.е. достъпа до файла се прекратява сравнително продължително, или някои вмъквания на записи стават много по – бавно от други;
-
при удвояване на масива на указателите може той вече да не се побира в оперативната памет (използва много повече дискови операции за извършване на заявките);
-
ако броя на записите в 1 блок е малък, то тогава по – вероятно е блока да се раздели предварително за да се печели време, защото може да се стигне до такъв абсурд, че да се използват 20 бита за три записа;
-
най – съществен недостатък е нарастването на масива, поради тази причина се използва линейното хеширане, което също увеличава, но много по – слабо;
ЛИНЕЙНО ХЕШИРАНЕ
- броя на кофите n винаги се избира така, че запълнеността в дадена кофа да е 80 %;
- допускат се и блокове на препълване (по един блок);
! В най - лошия случай – три дискови достъпа.
- броя битове, които се използват за номериране на елементите е | log 2 n |, където n е броя кофи;
Имаме запис с ключ k, този запис се изчислява с помощта на функцията h(k), и това е някакво число m, което представено двоично изглежда така:
m = а1, а2, …аi ;
n – текущия брой кофи;
Ако m < n => означава, че съществува кофа, в която може да се запише записа;
Но ако n ≤ m < 2i => означава, че няма кофа, в която може да бъде вмъкнат този запис – тогава трябва да създадем съответната кофа. Този запис трябва да бъде поставен в кофа m – 2i – 1, т.е. ние трябва да го поставим в кофата в която а1 го заменим с 0 (а1 задължително е 1);
m = а1, а2, …аi ;
∕∕
0
Пример:
n = 2
i = 1 (използва се по 1 бит; имаме 2 блока)
r = 3 (броя записи, които в момента има) – критерий за запълненост на кофите
0 0000
1010
1 1111
Трябва да пресметнем за да решим дали да увеличим броя кофи, т.е. ако ≤ 1.7, тогава означава че поддържаме запълненост не повече от 85%, а ако > 1.7 следва, че трябва да увеличим кофите.
Изчисляваме хеш стойността на ключа, ако тази стойност m е < n , означава че можем да осъществим вмъкването в m–та кофа.
Но ако m ≥ n, тогава се опитваме да поставим в m – 2i – 1, т.е. а1 – (най-старшия) го превръщаме в нула, но може да се случи, че и там не можем да го вмъкнем, и тогава съществува блок на препълване, който го закачаме към m–та кофа. При вмъкване обаче (независимо как сме го извършили) винаги правим проверка какво става със запълването и ако сме надхвърлили средното запълване – тогава добавяме само една кофа и в тази кофа ние разделяме кофата, която е била с
0 а2 а3 … аi1 а2 а3 … аi
и тези записи ще ги разделим между нея и ново-добавената кофа.
Ако n превиши 2i – тогава i се увеличава с 1, което означава, че всички останали получават по една нула отпред, а поредицата от битове става с 1 повече.
Пример:
Да вмъкнем запис, чиито ключ се хешира до 0101
i = 1
n = 2 0 0000
r = 3 1010
1 1111
0101
Но това вмъкване надвишава 85 %, т.е. = 2 > 1,7
Тогава трябва да увеличим броя на кофите с още една, но това води и до увеличение на i
i = 2
n = 3 00 0000
r = 4
01 1111
0101
10 1010 } нова кофа; 1Я бит го превръщаме
↓ в 0 и гледаме в коя кофа ще попадне
ръководим се от 1Я бит
Разделянето засяга първата кофа;
Да добавим още един запис със стойност 0001. Той трябва да е във втория блок, но той е пълен и затова създаваме блок на препълване
i = 2
n = 3 0000
r = 5
1111 0001
0101
1010
Правим проверка =1,6 <1,7 ОК
Сега нека вмъкнем 0111 и тъй като няма такава кофа, тогава трием 0111 и преминаваме към 2 та кофа => т.е. записваме го в блока на препълване, но = =2 >1,7 тогава
i = 2
n = 4 00 0000
r = 6
01 0101
0001
10 1010
11 1111
0111 → нова кофа и от 01
Всъщност се прилагат динамичните хешове, а не линейните.
Многомерни и побитови индекси – използват се за решетъчни файлове, разпределени хеш функции.
До тук правим индексация по 1 атрибут, но много пъти се налага търсене по множество атрибути (едновременно) и там намират приложение тези многомерни и побитови индекси и те са надстройка в СУБД.
Page of
Сподели с приятели: |