12. Речници

Речник АТД

Function
Input
Output
Description
size()
-
Integer
Връща броя на елементите на D.
isEmpty()
-
Boolean
Проверява дали D е празен.
elements()
-
Iterator of objects (elements)
Връща елементите, записани в D.
keys()
-
Iterator of objects (keys) Връща ключовете, записани в D.
find(k)
Object (key) Position
Ако D съдържа член с ключ, равен на k, връща позицията на този член. Ако не, връща nullposition .
findAll(k)
Object (key) Iterator of Positions Връща итератор от позициите на всички членове, чийто ключове са равни на k.
insertItem(k,e)
Objects k (key) and e (element) -
Вмъква двойка с елемент e и ключ k в D.
removeElement(k)
Object (key)
-
Премахва член с ключ равен на k от D. Ако в D няма такъв член се генерира грешка (error condition).
removeAllElements(k)
Object (key) -
Премахва всички двойки с ключове равни на k от D.
Operation
Output
Dictionary
insertItem(5,A)
insertItem(7,B)
insertItem(2,C)
insertItem(8,D)
insertItem(2,E)
find(7)
find(4)
find(2)
findAll(2)
size()
removeElement(5)
removeElement(5)
removeAllElements(2)
find(2)
findAll(2)
-
-
-
-
-
p(B)
"null"
p(C) or p(E)
p(C),p(E)
5
-
"error"
-
"null"
"empty iterator"
{(5,A)}
{(5,A),(7,B)}
{(5,A),(7,B),(2,C)}
{(5,A),(7,B),(2,C),(8,D)}
{(5,A),(7,B),(2,C),(8,D),(2,E)}
{(5,A),(7,B),(2,C),(8,D),(2,E)}
{(5,A),(7,B),(2,C),(8,D),(2,E)}
{(5,A),(7,B),(2,C),(8,D),(2,E)}
{(5,A),(7,B),(2,C),(8,D),(2,E)}
{(5,A),(7,B),(2,C),(8,D),(2,E)}
{(7,B),(2,C),(8,D),(2,E)}
{(7,B),(2,C),(8,D),(2,E)}
{(7,B),(8,D)}
{(7,B),(8,D)}
{(7,B),(8,D)}
Operation
Input
Output
Description
element() -
Object (element) Връща псевдоним на елемента от двойката на тази позиция.
key() -
Object (key) Връща константен псевдоним на ключа от двойката на тази позиция.
isNull() -
Boolean
Връща true, ако това е nullposition.

Log файлове

Хеш таблици

Клетъчни масиви (bucket arrays)
Анализ на структурата клетъчен масив

Пример: Речник, състоящ се от (FN, name) - факултетен номер и име на студент, като речникът съхранява данни за студентите от този курс - n = 100, N = 100000.

Хеш функции

  • Да се направи хеш таблица за речник, съдържащ двойки (SSN, Name), където SSN (social security number) е 9-цифрово положително число.
  • Ако хеш таблицата използва масив с размер N = 10000 и хеш функция h(x) = x mod 10000, т.е. (последните 4 цифри на x), може да възникнат колизии.
  • За да се избегнат колизии, ще трябва да се вземе N = 109 и хеш функция h(x) = x (Недостатък 1).

Хеш кодове
Хеш кодове в C++
C++ пример
32-bit integer if we have 32-bit integer hash function
int hashCode(int x)
{ return x; }
64-bit integer if we have 32-bit integer hash function
int hashCode(long x)
{ typedef unsigned long ulong;
return hashCode(static_cast<int>(static_cast<ulong>(x) >> 32)
+ static_cast<int>(x));
}
Полиномен хеш код
Циклични с преместване хеш кодове
int hashCode(const char* p, int len) // hash a character array
{ unsigned int h = 0;
for (int i = 0; i < len; i++)
{ h = (h << 5)|(h >> 27); // 5-bit cyclic shift
h += (unsigned int)p[i]; // add in next character
}
return hashCode(int(h));
}
Експериментални резултати за 25000 английски думи
Shift
Collisions Total
Collisions Max
0
23739
86
1
10517
21
5
4
2
6
6
2
11
453
4

Хеширане на типове с плаваща точка
int hashCode(const double& x)       // hash a double
{ int len = sizeof(x);
const char* p = reinterpret_cast<const char *>(&x);
return hashCode(p, len);
}
hash_code.cpp

Компресиращи изображения

Метод на деленето
Метод MAD
Умножи, събери и раздели (Multiply, Add and Divide - MAD):
Схеми за решаване на колизии
Самостоятелни вериги (separate chaining)

Подход на отворено адресиране
Отворено адресиране: при колизия обектът се поставя в друга клетка на таблицата.

Линейно пробване (linear probing)

  • h(x) = x mod 13
  • Добавяме ключове 18, 41, 22, 44, 59, 32, 31, 73 в този ред.

Търсене с линейно пробване
  • Нека хеш таблицата A използва линейно пробване.
  • find(k)
    • Започва се с клетка h(k).
    • Пробват се последователни клетки, докато се появи един от следните случаи:
      • обект с ключ k е намерен, или
      • достигната е празна клетка, или
      • N клетки се пробвани без резултат.
Algorithm find(k)
   i h(k)
   p ← 0
   repeat
      cA[i]
      if c = ∅
          return Position(null)
      else if c.key() = k
          return Position(c)
      else
         i ← (i + 1) mod N
         pp + 1
   until p = N
   return Position(null)

Обновяване с линейно пробване
Двойно хеширане


  • Разглеждаме хеш таблица за съхранение на целочислени ключове, обработваща колизии с двойно хеширане
    • N = 13
    • h(k) = k mod 13
    • d(k) = 7 − k mod 7
  • Въвеждат се ключове 18, 41, 22, 44, 59, 32, 31, 73, в този ред.

Реализация на хеш-таблица със C++

html-8.1 (HashEntry)
html-8.2
(Position)
html-8.3
(Hash1)
html-8.
4 (Hash2)

hash.cpp


Наредени речници

В нареден речник се иска освен обичайните операции за речник, да поддържа и такива, свързани с наредбата на ключовете.

Нареден речник АТД


Нареденият речник поддържа следните функции извън тези, включени в общия речник АТД:
Lookup таблици
Двоично търсене

bsearch.cpp

Анализ на двоично търсене

Сравнение на прости реализации на нареден речник АТД

Function
Log File
Lookup Table
size(), isEmpty()
O(1)
O(1)
keys(), elements()
O(n)
O(n)
find(key)
O(n)
O(log n)
findAll(key)
Theta(n)
O(log n + s)
insertItem(key, element)
O(1)
O(n)
removeElement(key)
O(n)
O(n)
removeAllElements()
Theta(n) O(n)