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.


Хеш таблици

Клетъчни масиви (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