Initial commit

This commit is contained in:
user
2026-07-12 14:22:00 +04:00
commit 49ecd4784c
90 changed files with 6910 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
TEMPLATE = app
QMAKE_CXXFLAGS += -O2 -finline-small-functions -momit-leaf-frame-pointer #-mpreferred-stack-boundary=2
#QMAKE_CXXFLAGS_DEBUG += -pg
#QMAKE_LFLAGS_DEBUG += -pg
CONFIG += \
c++14 \
#release
QT += \
widgets \
core \
gui \
charts \
xml
RESOURCES += \
SourceCode/resources.qrc
FORMS += \
SourceCode/UserInterface/FilesUI/demonstrationWidget.ui \
SourceCode/UserInterface/FilesUI/mainWindow.ui \
SourceCode/UserInterface/FilesUI/testingWidget.ui \
SourceCode/UserInterface/FilesUI/textBrowserWidget.ui
HEADERS += \
SourceCode/BusinessLogic/Convert/convert.h \
SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorDoubleHashing.h \
SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorFamily.h \
SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorPseudorandomProbing.h \
SourceCode/BusinessLogic/Hash/Algorithm/Family/doubleHashing.h \
SourceCode/BusinessLogic/Hash/Algorithm/Family/family.h \
SourceCode/BusinessLogic/Hash/Algorithm/Family/pseudorandomProbing.h \
SourceCode/BusinessLogic/Hash/Algorithm/One/creatorLinearProbing.h \
SourceCode/BusinessLogic/Hash/Algorithm/One/creatorOne.h \
SourceCode/BusinessLogic/Hash/Algorithm/One/creatorQuadraticProbing.h \
SourceCode/BusinessLogic/Hash/Algorithm/One/linearProbing.h \
SourceCode/BusinessLogic/Hash/Algorithm/One/one.h \
SourceCode/BusinessLogic/Hash/Algorithm/One/quadraticProbing.h \
SourceCode/BusinessLogic/Hash/Algorithm/abstract.h \
SourceCode/BusinessLogic/Hash/Algorithm/creatorAbstract.h \
SourceCode/BusinessLogic/Hash/Factory/abstract.h \
SourceCode/BusinessLogic/Hash/Factory/family.h \
SourceCode/BusinessLogic/Hash/Factory/one.h \
SourceCode/BusinessLogic/Hash/Function/Family/creatorFamily.h \
SourceCode/BusinessLogic/Hash/Function/Family/creatorFnv1a.h \
SourceCode/BusinessLogic/Hash/Function/Family/family.h \
SourceCode/BusinessLogic/Hash/Function/Family/fnv1a.h \
SourceCode/BusinessLogic/Hash/Function/One/creatorEquivalent.h \
SourceCode/BusinessLogic/Hash/Function/One/creatorOne.h \
SourceCode/BusinessLogic/Hash/Function/One/equivalent.h \
SourceCode/BusinessLogic/Hash/Function/One/one.h \
SourceCode/BusinessLogic/Hash/Function/One/creatorStandart.h \
SourceCode/BusinessLogic/Hash/Function/One/standart.h \
SourceCode/BusinessLogic/Hash/Function/Pattern/creatorFamilyToOne.h \
SourceCode/BusinessLogic/Hash/Function/Pattern/familyToOne.h \
SourceCode/BusinessLogic/Hash/Function/abstract.h \
SourceCode/BusinessLogic/Hash/Function/creatorAbstract.h \
SourceCode/BusinessLogic/Hash/Table/Pattern/subscriber.h \
SourceCode/BusinessLogic/Hash/Table/abstract.h \
SourceCode/BusinessLogic/Hash/Table/chains.h \
SourceCode/BusinessLogic/Hash/Table/openAddress.h \
SourceCode/BusinessLogic/Pattern/singleton.h \
SourceCode/BusinessLogic/Statistics/dispersion.h \
SourceCode/BusinessLogic/businessLogic.h \
SourceCode/BusinessLogic/hashHeaderFiles.h \
SourceCode/UserInterface/ClassesUI/Validator/validator.h \
SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.h \
SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.h \
SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.h \
SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.h
SOURCES += \
SourceCode/BusinessLogic/Convert/convert.cpp \
SourceCode/BusinessLogic/Statistics/dispersion.cpp \
SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.cpp \
SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.cpp \
SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.cpp \
SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.cpp \
SourceCode/main.cpp
#SourceCode/BusinessLogic/debug.cpp
+38
View File
@@ -0,0 +1,38 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Inserting into a hash table"
#define MyAppVersion "1.0.0"
#define MyAppExeName "HashTable.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{E9AC9BF2-18C1-4A8D-9576-5A1B632AC7F7}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
DefaultDirName={autopf}\HashTable
AllowNoIcons=yes
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "C:\Users\*\Desktop\HashTable\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\*\Desktop\HashTable\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
+101
View File
@@ -0,0 +1,101 @@
<?xml version="1.0"?>
<questions>
<question category = "hashTable|algorithm" complexity = "easy" type = "choice">
<caption>Соотнесите подходящие варианты ответа с высказыванием.</caption>
<text>Метод решения коллизий в хеш-таблице.</text>
<answer type = "wrong">Прямая адрессация.</answer>
<answer type = "correct">Открытая адрессация.</answer>
<answer type = "wrong">Регистровая адресация.</answer>
<answer type = "correct">Метод цепочек.</answer>
<answer type = "wrong">Ничего из вышеперечисленного.</answer>
</question>
<question category = "hashFunction" complexity = "easy" type = "choice">
<caption>Выберите несколько правильных ответов.</caption>
<text>С какими данными оперирует хеш-функция в процессе хеширования?</text>
<answer>Хеш-память.</answer>
<answer type = "correct">Хеш-значение.</answer>
<answer>Кеш-память.</answer>
<answer type = "correct">Множество ключей.</answer>
<answer type = "correct">Множество значений.</answer>
</question>
<question category = "hashFunction" complexity = "easy" type = "choice">
<caption>Выберите несколько правильных ответов.</caption>
<text>На что влияет коэффициент заполнения?</text>
<answer type = "correct">Поиск неиспользующегося бункера, при гарантии его существования.</answer>
<answer>Поиск использующегося бункера по его ключу.</answer>
<answer>Скорость хеширования.</answer>
<answer type = "correct">Количество используемых бункеров.</answer>
<answer>Количество возможных ключей.</answer>
</question>
<question category = "hashTable|algorithm" complexity = "easy" type = "choice">
<caption>Выберите несколько правильных ответов.</caption>
<text>Какие алгоритмы поиска бункера при решении коллизий открытой адресацией используют ровно одну хеш-функцию?</text>
<answer type = "correct">Линейное пробирование.</answer>
<answer type = "correct">Квадратичное пробирование.</answer>
<answer type = "correct">Псевдослучайное пробирование.</answer>
<answer>Двойное хеширование.</answer>
<answer>Ничего из перечисленного.</answer>
</question>
<question category = "hashTable|algorithm" complexity = "easy" type = "integer">
<caption>Введите правильное целочисленое число.</caption>
<text>Чему равна дисперсия, как мера разброса элементов хеш-таблицы от средней условной величины при идеальном хешировании?</text>
<answer type = "correct">0</answer>
</question>
<question category = "hashTable" complexity = "easy" type = "choice">
<caption>Выберите варианты ответов, которые подходят по смыслу с заданным текстом.</caption>
<text>Сопоставьте - идеальное хеширование.</text>
<answer type = "correct">Словарь.</answer>
<answer type = "correct">Прямая адрессация.</answer>
<answer type = "wrong">Открытая адрессация.</answer>
<answer type = "wrong">Регистровая адресация.</answer>
<answer type = "wrong">Метод цепочек.</answer>
<answer type = "wrong">Ничего из вышеперечисленного.</answer>
</question>
<question category = "hashTable|algorithm" complexity = "easy" type = "choice">
<caption>Определите про какие алгоритмы поиска бункера при решении коллизий открытой адресацией идёт речь?</caption>
<text>Политика разрешения коллизий использует шаг по индексу, который зависит от информации (позиция или данные) бункера.</text>
<answer type = "wrong">Линейное пробирование.</answer>
<answer type = "wrong">Квадратичное пробирование.</answer>
<answer type = "correct">Псевдослучайное пробирование.</answer>
<answer type = "correct">Двойное хеширование.</answer>
<answer type = "wrong">Ничего из вышеперечисленного.</answer>
</question>
<question category = "hashTable|algorithm" complexity = "easy" type = "choice">
<caption>Определите про какие алгоритмы поиска бункера при решении коллизий открытой адресацией идёт речь?</caption>
<text>Политика разрешения коллизий использует шаг по индексу, который зависит от количества итераций и/или размера хеш-таблицы.</text>
<answer type = "correct">Линейное пробирование.</answer>
<answer type = "correct">Квадратичное пробирование.</answer>
<answer type = "wrong">Псевдослучайное пробирование.</answer>
<answer type = "wrong">Двойное хеширование.</answer>
<answer type = "wrong">Ничего из вышеперечисленного.</answer>
</question>
<question category = "hashTable|algorithm|discreteMathematics" complexity = "hard" type = "integer">
<caption>Напишите правильный ответ.</caption>
<text>Рассмотрим хеш-функцию, которая равномерно распределяет значения по хеш-таблице.
Размер хеш-таблицы равен 20.
После какого количества вставок вероятность того, что при попытке вставить в хеш-таблицу новое значение произойдёт коллизия, превысит 0.5?</text>
<answer type = "correct">11</answer>
</question>
<question category = "hashTable" complexity = "medium" type = "integer">
<caption>Напишите правильный ответ.</caption>
<text>Чему будет равен коэффициент заполненности, если в хеш-таблица с 25 цепочками поместить 2000 элементов?</text>
<answer type = "correct">80</answer>
</question>
<question category = "discreteMathematics" complexity = "medium" type = "floatingPoint">
<caption>Напишите правильный ответ.</caption>
<text>Определите коэффициет заполнения хеш-таблицы с решением коллизий методом открытой адресациии, если её размер равняется 50, но свободных бункеров - 20.</text>
<answer type = "correct">0,60</answer>
</question>
</questions>
@@ -0,0 +1,22 @@
#include "convert.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Convert)
size_t FromStdString::operator()(const std::array<char, 5> &value, size_t alphabetPower) const {
if (value.empty()) {
throw std::invalid_argument("undefined key");
}
size_t result = 0;
size_t counter = 0;
for (auto crbegin = value.crbegin(), crend = value.crend()
; crbegin != crend && *crbegin >= '!' && *crbegin <= '~'; ++crbegin, ++counter
) {
result += (*crbegin) * std::pow(alphabetPower, counter);
}
return result;
}
END_NAMESPACE // Convert
END_NAMESPACE // BusinessLogic
@@ -0,0 +1,24 @@
#ifndef CONVERT_H
#define CONVERT_H
#include "../businessLogic.h"
#include <string>
#include <stdexcept>
#include <limits>
#include <array>
#include <cmath>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Convert)
class FromStdString
{
public:
size_t operator()(const std::array<char, 5> &, size_t) const;
};
END_NAMESPACE // Convert
END_NAMESPACE // BusinessLogic
#endif // CONVERT_H
@@ -0,0 +1,34 @@
#ifndef CREATOR_ALGHORITHM_DOUBLE_HASHING_H
#define CREATOR_ALGHORITHM_DOUBLE_HASHING_H
#include "doubleHashing.h"
#include "creatorFamily.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(DoubleHashing)
class Creator : public Family::Creator
{
private:
size_t m_firstHashFunction;
size_t m_secondHashFunction;
public:
Creator(size_t first, size_t second) : m_firstHashFunction(first), m_secondHashFunction(second)
{
}
public:
virtual std::unique_ptr<Abstract::Product> create() const override {
return std::unique_ptr<Abstract::Product>(new Product(m_firstHashFunction, m_secondHashFunction));
}
};
END_NAMESPACE // DoubleHashing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_DOUBLE_HASHING_H
@@ -0,0 +1,24 @@
#ifndef CREATOR_ALGHORITHM_FAMILY_H
#define CREATOR_ALGHORITHM_FAMILY_H
#include "../creatorAbstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(Family)
class Creator : public Abstract::Creator
{
protected:
Creator()
{
}
};
END_NAMESPACE // Family
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_FAMILY_H
@@ -0,0 +1,34 @@
#ifndef CREATOR_ALGHORITHM_PSEUDORANDOM_PROBING_H
#define CREATOR_ALGHORITHM_PSEUDORANDOM_PROBING_H
#include "pseudorandomProbing.h"
#include "creatorFamily.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(PseudorandomProbing)
class Creator : public Family::Creator
{
private:
size_t m_hashFunctionNumber;
public:
Creator(size_t number) : m_hashFunctionNumber(number)
{
}
public:
virtual std::unique_ptr<Abstract::Product> create() const override {
return std::unique_ptr<Abstract::Product>(new Product(m_hashFunctionNumber));
}
};
END_NAMESPACE // PseudorandomProbing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_PSEUDORANDOM_PROBING_H
@@ -0,0 +1,41 @@
#ifndef ALGHORITHM_DOUBLE_HASHING_H
#define ALGHORITHM_DOUBLE_HASHING_H
#include "family.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(DoubleHashing)
class Product final : public Family::Product
{
private:
size_t m_firstHashFunction;
size_t m_secondHashFunction;
size_t m_multiplier;
private:
friend Creator;
Product(size_t first, size_t second) : m_firstHashFunction(first), m_secondHashFunction(second)
{
if (first == second) {
throw std::invalid_argument("hash functions must be different");
}
}
protected:
virtual size_t getFirstCoefficient() override {
m_multiplier = m_hashFunction->getHash(m_convertValue, m_firstHashFunction);
return m_hashFunction->getHash(m_convertValue, m_firstHashFunction);
}
virtual size_t getSecondCoefficient(size_t counter) override {
return counter * m_multiplier;
}
};
END_NAMESPACE // DoubleHashing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_DOUBLE_HASHING_H
@@ -0,0 +1,36 @@
#ifndef ALGHORITHM_FAMILY_H
#define ALGHORITHM_FAMILY_H
#include "../../Function/Family/family.h"
#include "../abstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(Family)
class Product : public Abstract::Product
{
public:
using function_type = Function::Family::Product;
protected:
const function_type *m_hashFunction;
protected:
Product() : m_hashFunction(nullptr)
{
}
public:
void setHashFunction(const function_type &hashFunction) {
m_hashFunction = &hashFunction;
}
};
END_NAMESPACE // Family
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_FAMILY_H
@@ -0,0 +1,44 @@
#ifndef ALGHORITHM_PSEUDORANDOM_PROBING_H
#define ALGHORITHM_PSEUDORANDOM_PROBING_H
#include "family.h"
#include <random>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(PseudorandomProbing)
class Product final : public Family::Product
{
private:
size_t m_hashFunctionNumber;
size_t m_multiplier;
private:
friend Creator;
Product(size_t number) : m_hashFunctionNumber(number)
{
}
protected:
// virtual bool isValidInput() const override {
// return isPrimeNumber(size());
// }
virtual size_t getFirstCoefficient() override {
m_multiplier = m_hashFunction->getHash(m_convertValue, m_hashFunctionNumber);
srand(m_multiplier);
return m_hashFunction->getHash(m_convertValue, m_hashFunctionNumber);
}
virtual size_t getSecondCoefficient(size_t counter) override {
return counter * rand();
}
};
END_NAMESPACE // PseudorandomProbing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_PSEUDORANDOM_PROBING_H
@@ -0,0 +1,35 @@
#ifndef CREATOR_ALGHORITHM_LINEAR_PROBING_H
#define CREATOR_ALGHORITHM_LINEAR_PROBING_H
#include "linearProbing.h"
#include "creatorOne.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(LinearProbing)
class Creator : public One::Creator
{
private:
/* A number that is not mutually prime to the size will not apply */
const size_t m_coefficient;
public:
Creator(size_t coefficient = 1) : m_coefficient(coefficient)
{
}
public:
virtual std::unique_ptr<Abstract::Product> create() const override {
return std::unique_ptr<Abstract::Product>(new Product(m_coefficient));
}
};
END_NAMESPACE // LinearProbing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_LINEAR_PROBING_H
@@ -0,0 +1,24 @@
#ifndef CREATOR_ALGHORITHM_ONE_H
#define CREATOR_ALGHORITHM_ONE_H
#include "../creatorAbstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(One)
class Creator : public Abstract::Creator
{
protected:
Creator()
{
}
};
END_NAMESPACE // One
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_ONE_H
@@ -0,0 +1,30 @@
#ifndef CREATOR_ALGHORITHM_QUADRATIC_PROBING_H
#define CREATOR_ALGHORITHM_QUADRATIC_PROBING_H
#include "quadraticProbing.h"
#include "creatorOne.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(QuadraticProbing)
class Creator : public One::Creator
{
public:
Creator()
{
}
public:
virtual std::unique_ptr<Abstract::Product> create() const override {
return std::unique_ptr<Abstract::Product>(new Product());
}
};
END_NAMESPACE // LinearProbing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_QUADRATIC_PROBING_H
@@ -0,0 +1,41 @@
#ifndef ALGHORITHM_LINEAR_PROBING_H
#define ALGHORITHM_LINEAR_PROBING_H
#include "one.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(LinearProbing)
class Product final : public One::Product
{
private:
/* A number that is not mutually prime to the size will not apply */
const size_t m_coefficient;
private:
friend Creator;
Product(size_t coefficient)
: m_coefficient(coefficient == 0 ? 1 : coefficient)
{
}
protected:
// virtual bool isValidInput() const override {
// return gcd(m_coefficient, size()) == 1;
// }
virtual size_t getFirstCoefficient() override {
return m_hashFunction->getHash(m_convertValue);
}
virtual size_t getSecondCoefficient(size_t counter) override {
return counter * m_coefficient;
}
};
END_NAMESPACE // LinearProbing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_LINEAR_PROBING_H
@@ -0,0 +1,36 @@
#ifndef ALGHORITHM_ONE_H
#define ALGHORITHM_ONE_H
#include "../../Function/One/one.h"
#include "../abstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(One)
class Product : public Abstract::Product
{
public:
using function_type = Function::One::Product;
protected:
const function_type *m_hashFunction;
protected:
Product() : m_hashFunction(nullptr)
{
}
public:
void setHashFunction(const function_type &hashFunction) {
m_hashFunction = &hashFunction;
}
};
END_NAMESPACE // One
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_ONE_H
@@ -0,0 +1,36 @@
#ifndef ALGHORITHM_QUADRATIC_PROBING_H
#define ALGHORITHM_QUADRATIC_PROBING_H
#include "one.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(QuadraticProbing)
class Product final : public One::Product
{
private:
friend Creator;
Product()
{
}
protected:
// virtual bool isValidInput() const override {
// return isPrimeNumber(size());
// }
virtual size_t getFirstCoefficient() override {
return m_hashFunction->getHash(m_convertValue);
}
virtual size_t getSecondCoefficient(size_t counter) override {
return std::pow(size(), counter);
}
};
END_NAMESPACE // LinearProbing
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_QUADRATIC_PROBING_H
@@ -0,0 +1,101 @@
#ifndef ALGHORITHM_ABSTRACT_H
#define ALGHORITHM_ABSTRACT_H
#include "../../Convert/convert.h"
#include <vector>
#include <cmath>
#include <stdexcept>
#include <memory>
#include <array>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(Abstract)
class Product
{
public:
using value_type = std::array<char, 5>;
private:
const std::vector<value_type> *m_table;
BusinessLogic::Convert::FromStdString m_toInteger;
protected:
size_t m_convertValue;
protected:
Product() : m_table(nullptr)
{
}
protected:
size_t gcd(size_t first, size_t second) const {
while (first > 0 && second > 0) {
first > second
? first %= second
: second %= first;
}
return first + second;
}
bool isPrimeNumber(size_t value) const {
size_t size = static_cast<size_t>(sqrt(value));
for (size_t i = 2; i <= size; i++) {
if (value % i == 0) {
return false;
}
}
return true;
}
size_t size() const {
return m_table->size();
}
protected:
virtual bool isValidInput() const {
return true;
}
virtual size_t getFirstCoefficient() = 0;
virtual size_t getSecondCoefficient(size_t counter) = 0;
public:
void setTable(decltype(m_table) table) {
m_table = table;
}
size_t getIndex(const value_type &value, size_t& numberOfCollisions, size_t alphabetPower) {
if (not isValidInput()) {
throw std::invalid_argument("the condition for using the algorithm is not met");
}
size_t size = m_table->size();
m_convertValue = m_toInteger(value, alphabetPower);
// It is necessary to use some coefficient
numberOfCollisions = 0;
decltype (m_table->cbegin()) currentIterator;
constexpr std::array<char, 5> nullValue = {'\0', '\0', '\0', '\0', '\0'};
while (numberOfCollisions <= size) {
currentIterator = {
m_table->cbegin()
+ ( getFirstCoefficient() + getSecondCoefficient(numberOfCollisions) ) % size
};
if ( *currentIterator == nullValue || *currentIterator == value ) { // Free cell or value match
return ( currentIterator - m_table->cbegin() );
}
++numberOfCollisions;
}
return std::numeric_limits<size_t>::max();
}
};
END_NAMESPACE // Abstract
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ALGHORITHM_ABSTRACT_H
@@ -0,0 +1,29 @@
#ifndef CREATOR_ALGHORITHM_ABSTRACT_H
#define CREATOR_ALGHORITHM_ABSTRACT_H
#include "../../../BusinessLogic/businessLogic.h"
#include <memory>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Algorithm)
BEGIN_NAMESPACE(Abstract)
class Creator
{
protected:
Creator()
{
}
public:
virtual std::unique_ptr<Product> create() const = 0;
};
END_NAMESPACE // Abstract
END_NAMESPACE // Algorithm
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ALGHORITHM_ABSTRACT_H
@@ -0,0 +1,48 @@
#ifndef FACTORY_ABSTRACT_H
#define FACTORY_ABSTRACT_H
#include "../Function/abstract.h"
#include "../Algorithm/abstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Factory)
class Abstract
{
public:
/*
* I used to use a constant link. This led to UB.
*
* https://eel.is/c++draft/class.temporary#6 (27.10.2021)
*
* The exceptions to this lifetime rule are:
* (6.9) A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.
*/
using AFC_type = std::shared_ptr<Function::Abstract::Creator>;
using AAC_type = std::shared_ptr<Algorithm::Abstract::Creator>;
protected:
AFC_type m_functionCreator;
AAC_type m_algorithmCreator;
protected:
Abstract(AFC_type functionCreator, AAC_type algorithmCreator)
: m_functionCreator(functionCreator), m_algorithmCreator(algorithmCreator)
{
}
public:
using AFP_type = Function::Abstract::Product;
using AAP_type = Algorithm::Abstract::Product;
public:
virtual const AFP_type &getFunction() const = 0;
virtual std::unique_ptr<AAP_type> getAlgorithm() const = 0;
};
END_NAMESPACE // Factory
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FACTORY_ABSTRACT_H
@@ -0,0 +1,46 @@
#ifndef FACTORY_FAMILY_H
#define FACTORY_FAMILY_H
#include "../Factory/abstract.h"
#include "../Function/Family/family.h"
#include "../Function/Family/creatorFamily.h"
#include "../Algorithm/Family/family.h"
#include "../Algorithm/Family/creatorFamily.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Factory)
class Family final : public Abstract
{
public:
using FFC_type = std::shared_ptr<Function::Family::Creator>;
using FAC_type = std::shared_ptr<Algorithm::Family::Creator>;
using FFP_type = Function::Family::Product;
using FAP_type = Algorithm::Family::Product;
public:
Family(const FFC_type functionCreator, const FAC_type algorithmCreator)
: Abstract(functionCreator, algorithmCreator)
{
}
public:
virtual const FFP_type &getFunction() const override {
return dynamic_cast<const FFP_type &>(m_functionCreator->create());
}
virtual std::unique_ptr<AAP_type> getAlgorithm() const override {
std::unique_ptr<AAP_type> algorithm = m_algorithmCreator->create();
dynamic_cast<FAP_type *>(algorithm.get())->setHashFunction(getFunction());
return algorithm;
}
};
END_NAMESPACE // Factory
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FACTORY_FAMILY_H
@@ -0,0 +1,46 @@
#ifndef FACTORY_ONE_H
#define FACTORY_ONE_H
#include "../Factory/abstract.h"
#include "../Function/One/one.h"
#include "../Function/One/creatorOne.h"
#include "../Algorithm/One/one.h"
#include "../Algorithm/One/creatorOne.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Factory)
class One final : public Abstract
{
public:
using OFC_type = std::shared_ptr<Function::One::Creator>;
using OAC_type = std::shared_ptr<Algorithm::One::Creator>;
using OFP_type = Function::One::Product;
using OAP_type = Algorithm::One::Product;
public:
One(OFC_type functionCreator, OAC_type algorithmCreator)
: Abstract(functionCreator, algorithmCreator)
{
}
public:
virtual const OFP_type &getFunction() const override {
return dynamic_cast<const OFP_type &>(m_functionCreator->create());
}
virtual std::unique_ptr<AAP_type> getAlgorithm() const override {
std::unique_ptr<AAP_type> algorithm = m_algorithmCreator->create();
dynamic_cast<OAP_type *>(algorithm.get())->setHashFunction(getFunction());
return algorithm;
}
};
END_NAMESPACE // Factory
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FACTORY_ONE_H
@@ -0,0 +1,27 @@
#ifndef CREATOR_FUNCTION_FAMILY_H
#define CREATOR_FUNCTION_FAMILY_H
#include "../creatorAbstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Family)
class Creator : public Abstract::Creator
{
protected:
Creator()
{
}
public:
virtual const Product &create() const = 0;
};
END_NAMESPACE // Family
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // CREATOR_FUNCTION_FAMILY_H
@@ -0,0 +1,25 @@
#ifndef CREATOR_FUNCTION_FNV1a_H
#define CREATOR_FUNCTION_FNV1a_H
#include "fnv1a.h"
#include "creatorFamily.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(FNV1a)
class Creator : public Family::Creator
{
public:
virtual const Product &create() const override {
return Product::getInstance();
}
};
END_NAMESPACE // FNV1a
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_FUNCTION_FNV1a_H
@@ -0,0 +1,39 @@
#ifndef FUNCTION_FAMILY_H
#define FUNCTION_FAMILY_H
#include "../abstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Family)
using function_type = std::function<size_t(size_t, size_t)>;
class Product : public Abstract::Product
{
protected:
const function_type m_function;
protected:
Product(const function_type& function) : m_function(function)
{
}
public:
const function_type &to_std() const {
return m_function;
}
size_t getHash(size_t first, size_t second) const {
// First - the value that is hashed
// Second - coefficient
return m_function(first, second);
}
};
END_NAMESPACE // Family
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // FUNCTION_FAMILY_H
@@ -0,0 +1,40 @@
#ifndef FUNCTION_FNV1a_H
#define FUNCTION_FNV1a_H
#include "family.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(FNV1a)
using Singleton = BusinessLogic::Pattern::Singleton<Product>;
class Product final : public Family::Product, public Singleton
{
private:
const int32_t m_p;
private:
friend const Product &Singleton::getInstance();
Product()
: Family::Product(
[this](size_t value, size_t i) -> size_t {
size_t result = (0x811C9DC5 xor i) xor static_cast<int32_t>(value);
return static_cast<int32_t>(result * m_p);
}
)
, m_p(0x01000193)
{
}
public:
using Singleton::getInstance;
};
END_NAMESPACE // FNV1a
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FUNCTION_FNV1a_H
@@ -0,0 +1,25 @@
#ifndef CREATOR_FUNCTION_EQUIVALENT_H
#define CREATOR_FUNCTION_EQUIVALENT_H
#include "creatorOne.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Equivalent)
class Creator : public One::Creator
{
public:
virtual const Product &create() const override {
return Product::getInstance();
}
};
END_NAMESPACE // Equivalent
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_FUNCTION_EQUIVALENT_H
@@ -0,0 +1,27 @@
#ifndef CREATOR_FUNCTION_ONE_H
#define CREATOR_FUNCTION_ONE_H
#include "../creatorAbstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(One)
class Creator : public Abstract::Creator
{
protected:
Creator()
{
}
public:
virtual const Product &create() const = 0;
};
END_NAMESPACE // One
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_FUNCTION_ONE_H
@@ -0,0 +1,24 @@
#ifndef CREATOR_FUNCTION_STANDART_H
#define CREATOR_FUNCTION_STANDART_H
#include "creatorOne.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Standart)
class Creator : public One::Creator
{
public:
virtual const Product &create() const override {
return Product::getInstance();
}
};
END_NAMESPACE // Standart
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_FUNCTION_FNV1a_H
@@ -0,0 +1,35 @@
#ifndef FUNCTION_EQUIVALENT_H
#define FUNCTION_EQUIVALENT_H
#include "one.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Equivalent)
using Singleton = BusinessLogic::Pattern::Singleton<Product>;
class Product final : public One::Product, public Singleton
{
private:
friend const Product &Singleton::getInstance();
Product() :
One::Product(
[](size_t value) -> size_t {
return value;
}
)
{
}
public:
using Singleton::getInstance;
};
END_NAMESPACE // Equivalent
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FUNCTION_EQUIVALENT_H
@@ -0,0 +1,37 @@
#ifndef FUNCTION_ONE_H
#define FUNCTION_ONE_H
#include "../abstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(One)
using function_type = std::function<size_t(size_t)>;
class Product : public Abstract::Product
{
protected:
const function_type m_function;
protected:
Product(const function_type& function) : m_function(function)
{
}
public:
const function_type& to_std() const {
return m_function;
}
size_t getHash(size_t value) const {
return m_function(value);
}
};
END_NAMESPACE // One
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FUNCTION_ONE_H
@@ -0,0 +1,37 @@
#ifndef FUNCTION_STANDART_H
#define FUNCTION_STANDART_H
#include "one.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Standart)
using Singleton = BusinessLogic::Pattern::Singleton<Product>;
class Product final : public One::Product, public Singleton
{
private:
std::hash<size_t> m_standartHashFunction;
private:
friend const Product &Singleton::getInstance();
Product()
: One::Product(
std::bind(&std::hash<size_t>::operator(), &m_standartHashFunction, std::placeholders::_1)
)
, m_standartHashFunction()
{
}
public:
using Singleton::getInstance;
};
END_NAMESPACE // Standart
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FUNCTION_FNV1a_H
@@ -0,0 +1,36 @@
#ifndef CREATOR_ADAPTER_FAMILY_TO_ONE_H
#define CREATOR_ADAPTER_FAMILY_TO_ONE_H
#include "familyToOne.h"
#include "../One/creatorOne.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Pattern)
BEGIN_NAMESPACE(FamilyToOne)
class Creator final : public One::Creator
{
private:
Product m_product; // To support the interface
public:
Creator(std::shared_ptr<Family::Creator> adaptee, size_t coefficient)
: m_product(adaptee->create(), coefficient)
{
}
public:
virtual const Product &create() const override {
return m_product;
}
};
END_NAMESPACE // FamilyToOne
END_NAMESPACE // Pattern
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_ADAPTER_FAMILY_TO_ONE_H
@@ -0,0 +1,30 @@
#ifndef ADAPTER_FAMILY_TO_ONE_H
#define ADAPTER_FAMILY_TO_ONE_H
#include "../Family/family.h"
#include "../One/one.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Pattern)
BEGIN_NAMESPACE(FamilyToOne)
class Product final : public One::Product
{
public:
Product(const Family::Product &adaptee, size_t coefficient)
: One::Product(
std::bind(adaptee.to_std(), std::placeholders::_1, coefficient)
)
{
}
};
END_NAMESPACE // FamilyToOne
END_NAMESPACE // Pattern
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !ADAPTER_FAMILY_TO_ONE_H
@@ -0,0 +1,30 @@
#ifndef FUNCTION_ABSTRACT_H
#define FUNCTION_ABSTRACT_H
#include "../../businessLogic.h"
#include "../../Pattern/singleton.h"
#include <memory>
#include <functional>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Abstract)
class Product
{
protected:
Product()
{
}
/* With the virtual destructor, the compiler considers this class to be polymorphic */
virtual ~Product() = default;
};
END_NAMESPACE // Abstract
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !FUNCTION_ABSTRACT_H
@@ -0,0 +1,27 @@
#ifndef CREATOR_FUNCTION_ABSTRACT_H
#define CREATOR_FUNCTION_ABSTRACT_H
#include "../../businessLogic.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Function)
BEGIN_NAMESPACE(Abstract)
class Creator
{
protected:
Creator()
{
}
public:
virtual const Product &create() const = 0;
};
END_NAMESPACE // Abstract
END_NAMESPACE // Function
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // !CREATOR_FUNCTION_ABSTRACT_H
@@ -0,0 +1,58 @@
#ifndef SUBSCRIBER_H
#define SUBSCRIBER_H
#include "../../../businessLogic.h"
#include <vector>
#include <string>
#include <algorithm>
#include <array>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Table)
BEGIN_NAMESPACE(Pattern)
class InterfaceSubscriber
{
public:
virtual void successfulInsertion(const Table::Abstract *, const std::array<char, 5> &, std::pair<size_t, size_t>, size_t) = 0;
virtual void unsuccessfulInsertion(const Table::Abstract *, const std::array<char, 5> &) = 0;
};
class Publisher
{
private:
std::vector<InterfaceSubscriber *> m_subscribers;
public:
virtual void signTheObject(InterfaceSubscriber *subscriber) {
if (subscriber not_eq nullptr) {
m_subscribers.push_back(subscriber);
}
}
virtual void unsubscribe(InterfaceSubscriber *subscriber) {
if (subscriber not_eq nullptr) {
m_subscribers.erase(std::find(m_subscribers.begin(), m_subscribers.end(), subscriber));
}
}
protected:
virtual void sendSuccessfulInsertion(const Table::Abstract *sender, const std::array<char, 5> &value, std::pair<size_t, size_t> index, size_t numberOfCollisions) const {
for (decltype(auto) currentSubscriber : m_subscribers) {
currentSubscriber->successfulInsertion(sender, value, index, numberOfCollisions);
}
}
virtual void sendUnseccessInsertion(const Table::Abstract *sender, const std::array<char, 5> &value) const {
for (decltype(auto) currentSubscriber : m_subscribers) {
currentSubscriber->unsuccessfulInsertion(sender, value);
}
}
};
END_NAMESPACE // Pattern
END_NAMESPACE // Table
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // SUBSCRIBER_H
@@ -0,0 +1,60 @@
#ifndef ABSTRACT_HASH_TABLE_H
#define ABSTRACT_HASH_TABLE_H
#include "../../businessLogic.h"
#include "../../Statistics/dispersion.h"
#include "Pattern/subscriber.h"
#include <vector>
#include <list>
#include <memory>
#include <functional>
#include <string>
#include <stdexcept>
#include <typeinfo>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Table)
class Abstract : public Pattern::Publisher
{
public:
using value_type = std::array<char, 5>;
using collision_container = BusinessLogic::Statistics::Dispersion::container_type;
protected: // Members
size_t m_numberOfBuckets;
size_t m_alphabetPower;
BusinessLogic::Statistics::Dispersion m_dispersion;
protected:
Abstract(size_t alphabetPower)
: m_numberOfBuckets(0)
, m_alphabetPower(alphabetPower)
{
}
Abstract(Abstract &&) = default;
Abstract &operator=(Abstract &&) = default;
Abstract(const Abstract &) = delete;
Abstract &operator=(const Abstract &) = delete;
public:
virtual bool isExist(const value_type &) const = 0;
virtual size_t size() const = 0;
virtual bool insert(const value_type &value) = 0;
virtual double simpleUniformHashingCoefficient() const = 0;
size_t alphabetPower() const {
return m_alphabetPower;
}
size_t numberOfBuckets() const {
return m_numberOfBuckets;
}
};
END_NAMESPACE // Table
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // ABSTRACT_HASH_TABLE_H
@@ -0,0 +1,93 @@
#ifndef CHAINS_HASH_TABLE_H
#define CHAINS_HASH_TABLE_H
#include "abstract.h"
#include "../../Convert/convert.h"
#include "../Function/One/one.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Table)
class Chains final : public Abstract
{
public: // Types
using container_type = std::vector<std::list<value_type>>;
using OFP_type = Function::One::Product;
using OFC_type = Function::One::Creator;
private:
BusinessLogic::Convert::FromStdString m_toInteger;
public:
container_type m_container;
const OFP_type &m_function;
Chains(size_t size, const OFC_type &function, size_t alphabetPower = std::numeric_limits<char>::max())
: Abstract(alphabetPower)
, m_function(function.create())
{
if (size == 0) {
size = 1;
}
/* The use of 'this' is mandatory */
this->m_container.resize(size);
}
private:
bool isExist(const value_type &value, size_t index) const {
const std::list<value_type> &currentList = m_container[index];
return std::find(currentList.cbegin(), currentList.cend(), value) not_eq currentList.cend();
}
public:
virtual bool isExist(const value_type &value) const override {
size_t size = this->size();
size_t index = m_function.getHash(m_toInteger(value, m_alphabetPower)) % size;
return isExist(value, index);
}
auto row(size_t index) const {
return m_container[index];
}
virtual size_t size() const override {
return m_container.size();
}
virtual bool insert(const value_type &value) override {
using namespace BusinessLogic::Statistics;
size_t index = m_function.getHash(m_toInteger(value, m_alphabetPower)) % this->size();
if( isExist(value, index) ) {
sendUnseccessInsertion(this, value);
return false;
}
try {
// List does not need a reserve
m_container[index].push_back(value);
}
catch (const std::bad_alloc &) {
sendUnseccessInsertion(this, value);
return false;
}
++m_numberOfBuckets;
size_t listLength = m_container[index].size();
sendSuccessfulInsertion(this, value, std::make_pair(index, listLength - 1), listLength - 1);
return true;
}
virtual double simpleUniformHashingCoefficient() const override {
size_t size = this->size();
collision_container container(size);
for(size_t i = 0; i < size; ++i) {
container[i] = m_container[i].size();
}
return m_dispersion(container, size);
}
};
END_NAMESPACE // Table
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // CHAINS_HASH_TABLE_H
@@ -0,0 +1,82 @@
#ifndef DIRECT_ADRESS_HASH_TABLE_H
#define DIRECT_ADRESS_HASH_TABLE_H
#include "../Factory/abstract.h"
#include "abstract.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Hash)
BEGIN_NAMESPACE(Table)
class OpenAddressing final : public Abstract
{
public: // Types
using container_type = std::vector<value_type>;
using factory_type = Factory::Abstract;
private:
using sample_type = BusinessLogic::Statistics::Dispersion::container_type;
private:
friend factory_type::AAP_type;
container_type m_container;
collision_container m_numberOfCollision;
std::unique_ptr<Algorithm::Abstract::Product> m_algorithm;
public:
OpenAddressing(size_t size, const factory_type &factory, size_t alphabetPower = std::numeric_limits<char>::max())
: Abstract(alphabetPower)
, m_numberOfCollision(size, std::numeric_limits<size_t>::max())
, m_algorithm(factory.getAlgorithm())
{
constexpr std::array<char, 5> nullValue = {'\0', '\0', '\0', '\0', '\0'};
m_container.resize(size, nullValue);
m_algorithm->setTable(&m_container);
}
public:
virtual bool isExist(const value_type &value) const override {
size_t numberOfCollisions = 0;
size_t index = (*m_algorithm).getIndex(value, numberOfCollisions, m_alphabetPower);
return ( index != std::numeric_limits<size_t>::max() )
|| ( (m_container.begin() + index).operator*() == value );
}
virtual size_t size() const override {
return m_container.size();
}
virtual bool insert(const value_type &value) override {
using namespace BusinessLogic::Statistics;
size_t size = m_container.size();
if ( m_numberOfBuckets == size) {
sendUnseccessInsertion(this, value);
return false;
}
size_t numberOfCollisions = 0;
size_t index = (*m_algorithm).getIndex(value, numberOfCollisions, m_alphabetPower);
if (index == std::numeric_limits<size_t>::max()
|| (m_container.begin() + index).operator*() == value
) {
sendUnseccessInsertion(this, value);
return false;
}
m_container[index] = value;
m_numberOfCollision[m_numberOfBuckets] = numberOfCollisions;
++m_numberOfBuckets;
sendSuccessfulInsertion(this, value, std::make_pair(index, 0), numberOfCollisions);
return true;
}
virtual double simpleUniformHashingCoefficient() const override {
return m_dispersion(m_numberOfCollision, m_numberOfBuckets);
}
};
END_NAMESPACE // Table
END_NAMESPACE // Hash
END_NAMESPACE // BusinessLogic
#endif // DIRECT_ADRESS_HASH_TABLE_H
@@ -0,0 +1,37 @@
#ifndef SINGLETON_H
#define SINGLETON_H
#include "../businessLogic.h"
#include <memory>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Pattern)
template <typename T>
class Singleton {
private:
static std::unique_ptr<T> m_singleton;
public:
static const T &getInstance() {
if (m_singleton == nullptr) {
m_singleton = std::unique_ptr<T>(new T);
}
return m_singleton.operator*();
}
Singleton() = default;
Singleton(const Singleton &) = delete;
Singleton(Singleton &&) = delete;
Singleton &operator=(const Singleton &) = delete;
Singleton &operator=(Singleton &&) = delete;
};
template<typename T>
std::unique_ptr<T> Singleton<T>::m_singleton = nullptr;
END_NAMESPACE // Pattern
END_NAMESPACE // BusinessLogic
#endif // SINGLETON_H
@@ -0,0 +1,18 @@
#include "dispersion.h"
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Statistics)
long double Dispersion::operator()(const container_type &container, size_t size) const {
long double average = 0;
long double averageOfSquares = 0;
for(size_t i = 0; i < size; ++i) {
average += ( container[i] ) / static_cast<long double>(size);
averageOfSquares += ( container[i] ) * ( container[i] ) / static_cast<long double>(size);
}
return averageOfSquares - average * average;
}
END_NAMESPACE // Statistics
END_NAMESPACE // BusinessLogic
@@ -0,0 +1,25 @@
#ifndef DISPERSION_H
#define DISPERSION_H
#include "../businessLogic.h"
#include <vector>
#include <algorithm>
#include <functional>
BEGIN_NAMESPACE(BusinessLogic)
BEGIN_NAMESPACE(Statistics)
class Dispersion {
public: // Types
using value_type = size_t;
using container_type = std::vector<value_type>;
public:
long double operator()(const container_type &container, size_t size) const;
};
END_NAMESPACE // Statistics
END_NAMESPACE // BusinessLogic
#endif // DISPERSION_H
+102
View File
@@ -0,0 +1,102 @@
#ifndef BUSINESS_LOGIC_H
#define BUSINESS_LOGIC_H
/* Opening bracket */
#define OPEN {
/* Closing bracket */
#define CLOSE }
/* Begin of namespace */
#define BEGIN_NAMESPACE(name) \
namespace name OPEN
/* Begin of namespace */
#define END_NAMESPACE \
CLOSE
/* Declaring classes of factory method */
#define DFM_TYPES \
class Product; \
class Creator;
/* Factory method namespace declaration */
#define DFM_NAMESPACE(name) \
BEGIN_NAMESPACE(name) \
DFM_TYPES \
END_NAMESPACE
/* Factory method base cod declaration */
#define DFM_BASE \
DFM_NAMESPACE(Abstract) \
DFM_NAMESPACE(One) \
DFM_NAMESPACE(Family)
namespace BusinessLogic
{
namespace Hash
{
namespace Function
{
DFM_BASE
DFM_NAMESPACE(FNV1a)
DFM_NAMESPACE(Standart)
DFM_NAMESPACE(Equivalent)
namespace Pattern
{
DFM_NAMESPACE(FamilyToOne)
}
}
namespace Algorithm
{
DFM_BASE
DFM_NAMESPACE(LinearProbing)
DFM_NAMESPACE(QuadraticProbing)
DFM_NAMESPACE(PseudorandomProbing)
DFM_NAMESPACE(DoubleHashing)
}
namespace Factory
{
class Abstract;
class One;
class Family;
}
namespace Table /* Only string data */
{
class Abstract;
class OpenAddressing; // Direct address hash function
class Chains; // Hash function implemented by the chain method
namespace Pattern
{
class InterfaceSubscriber;
class Publisher;
}
}
}
namespace Pattern // Can be used for different classes
{
template<typename T>
class Singleton;
}
namespace Convert
{
class FromStdString;
}
namespace Statistics
{
class Dispersion;
}
}
#endif // BUSINESS_LOGIC_H
+197
View File
@@ -0,0 +1,197 @@
#include "hashHeaderFiles.h"
#include <iostream>
#include <string>
#include <ctime>
#include <initializer_list>
#include <tuple>
#include <array>
#include "Convert/convert.h"
using namespace BusinessLogic::Hash;
using namespace Function::Pattern;
using namespace Table::Pattern;
using factory_ptr = std::shared_ptr<const Factory::Abstract>;
class Subscriber : public InterfaceSubscriber {
private:
clock_t m_time;
size_t m_maxCollision;
size_t m_numberOfSuccesses;
size_t m_numberOfFailures;
size_t m_target;
long double m_lastCoefficients;
public:
Subscriber(size_t target)
: m_maxCollision(0)
, m_numberOfSuccesses(0)
, m_numberOfFailures(0)
, m_target(target)
, m_lastCoefficients(0)
{
}
void startTime() {
m_time = clock();
}
void endTime() {
m_time = clock() - m_time;
}
double lastCoefficient() const {
return m_lastCoefficients;
}
double workingTime() const {
return m_time / static_cast<double>(CLOCKS_PER_SEC);
}
size_t maxCollision() const {
return m_maxCollision;
}
auto numberOfSuccesses() const {
return m_numberOfSuccesses;
}
auto numberOfFailures() const {
return m_numberOfFailures;
}
virtual void successfulInsertion(const Table::Abstract *table, const std::array<char, 5> &, std::pair<size_t, size_t>, size_t numberOfCollisions) override {
m_maxCollision = {
numberOfCollisions > m_maxCollision
? numberOfCollisions
: m_maxCollision
};
++m_numberOfSuccesses;
if(m_numberOfSuccesses + m_numberOfFailures >= m_target) {
m_lastCoefficients = table->simpleUniformHashingCoefficient();
}
}
virtual void unsuccessfulInsertion(const Table::Abstract *, const std::array<char, 5> &) override {
++m_numberOfFailures;
}
virtual void filledInPart(const Table::Abstract *) override {
m_lastCoefficients = 0;
}
};
void runTable(std::unique_ptr<Table::Abstract> table, size_t target) {
/* 26 letters */
constexpr char firstChar = ' ';
constexpr char endChar = '~';
size_t progress = 0;
std::array<char, 5> currentString = { ' ', ' ', ' ', ' ', ' ' };
bool continueFlag = true;
while (continueFlag) {
if (++progress > target || not table->insert(currentString)) {
continueFlag = false;
}
currentString[4] < endChar ? ++currentString[4]
: (currentString[4] = firstChar, currentString[3] < endChar) ? ++currentString[3]
: (currentString[3] = firstChar, currentString[2] < endChar) ? ++currentString[2]
: (currentString[2] = firstChar, currentString[1] < endChar) ? ++currentString[1]
: (currentString[1] = firstChar, currentString[0] < endChar) ? ++currentString[0]
: (continueFlag = false);
}
}
int main(int /*argc*/, char **/*argv*/)
{
auto fnv1a = std::make_shared<Function::FNV1a::Creator>();
auto equivalent = std::make_shared<Function::Equivalent::Creator>();
auto standart = std::make_shared<Function::Standart::Creator>();
auto doubleHashing = std::make_shared<Algorithm::DoubleHashing::Creator>(0, 1);
auto pseudorandomProbing = std::make_shared<Algorithm::PseudorandomProbing::Creator>(0);
auto linearProbing = std::make_shared<Algorithm::LinearProbing::Creator>();
auto quadraticProbing = std::make_shared<Algorithm::QuadraticProbing::Creator>();
/* First Hash Function has a number 0, second - 1 */
const Factory::Abstract &fac1 { Factory::Family(fnv1a, doubleHashing) };
const Factory::Abstract &fac2 { Factory::Family(fnv1a, pseudorandomProbing) };
const Factory::Abstract &fac3 { Factory::One(equivalent, linearProbing) };
const Factory::Abstract &fac4 { Factory::One(equivalent, quadraticProbing) };
const Factory::Abstract &fac5 { Factory::One(standart, linearProbing) };
const Factory::Abstract &fac6 { Factory::One(standart, quadraticProbing) };
auto simpleFNV1a = std::make_shared<FamilyToOne::Creator>(fnv1a, 0);
const Factory::Abstract &fac7 { Factory::One(simpleFNV1a, linearProbing) };
const Factory::Abstract &fac8 { Factory::One(simpleFNV1a, quadraticProbing) };
/* 0x5 == 0b0101 */
auto complicatedFNV1a = std::make_shared<FamilyToOne::Creator>(fnv1a, 0x55555555);
const Factory::Abstract &fac9 { Factory::One(complicatedFNV1a, linearProbing) };
const Factory::Abstract &fac10 { Factory::One(complicatedFNV1a, quadraticProbing) };
/*
* Constants
*/
constexpr size_t numberOfInserts = (
//11
//101
//5'003
//50'021
//230'003
//456'959
//1'000'003
//5'000'011
//10'000'019
10'000'019
); // Must be simple - max is 10'371'957'246
constexpr size_t quantityOfTables = 14;
constexpr size_t numberOfBins = numberOfInserts / 10;
constexpr size_t alphabetPower = '~' - ' ' + 1;
constexpr double alpha = 0.9;
std::array<std::shared_ptr<Subscriber>, quantityOfTables> results;
for(std::shared_ptr<Subscriber> &current : results) {
current = std::make_shared<Subscriber>(static_cast<size_t>(numberOfInserts * alpha));
}
/*
* Constants
*/
std::array<std::unique_ptr<Table::Abstract>, quantityOfTables> tables {
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac1, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac2, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac3, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac4, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac5, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac6, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac7, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac8, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac9, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::OpenAddressing(numberOfInserts, fac10, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::Chains (numberOfBins, *equivalent, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::Chains (numberOfBins, *standart, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::Chains (numberOfBins, *simpleFNV1a, alphabetPower) ),
std::unique_ptr<Table::Abstract>( new Table::Chains (numberOfBins, *complicatedFNV1a, alphabetPower) )
};
std::cout << std::fixed;
std::cout.precision(10);
std::cout << "START!" << std::endl;
for(size_t i = 0; i < quantityOfTables; ++i) {
tables[i]->signTheObject( &results[i].operator*() );
results[i]->startTime();
runTable(std::move(tables[i]), numberOfInserts * alpha);
results[i]->endTime();
std::cout
<< results[i]->maxCollision() << ' '
<< std::sqrt(results[i]->lastCoefficient()) << ' '
<< results[i]->numberOfSuccesses() << '/'
<< alpha << '/'
<< numberOfInserts << ' '
<< results[i]->workingTime() << std::endl;
}
std::cout << "END!" << std::endl;
}
@@ -0,0 +1,32 @@
#ifndef HASH_HEADER_FILES_H
#define HASH_HEADER_FILES_H
#include "Statistics/dispersion.h"
#include "Hash/Algorithm/One/linearProbing.h"
#include "Hash/Algorithm/One/quadraticProbing.h"
#include "Hash/Algorithm/Family/pseudorandomProbing.h"
#include "Hash/Algorithm/Family/doubleHashing.h"
#include "Hash/Function/Family/fnv1a.h"
#include "Hash/Function/One/standart.h"
#include "Hash/Function/One/equivalent.h"
#include "Hash/Function/Pattern/familyToOne.h"
#include "Hash/Algorithm/One/creatorLinearProbing.h"
#include "Hash/Algorithm/One/creatorQuadraticProbing.h"
#include "Hash/Algorithm/Family/creatorPseudorandomProbing.h"
#include "Hash/Algorithm/Family/creatorDoubleHashing.h"
#include "Hash/Function/Family/creatorFnv1a.h"
#include "Hash/Function/One/creatorStandart.h"
#include "Hash/Function/One/creatorEquivalent.h"
#include "Hash/Function/Pattern/creatorFamilyToOne.h"
#include "Hash/Factory/one.h"
#include "Hash/Factory/family.h"
#include "Hash/Table/chains.h"
#include "Hash/Table/openAddress.h"
#endif // HASH_HEADER_FILES_H
Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demonstration</title>
</head>
<body>
<h2 style="text-align: center">Руководство пользователя</h2>
<h3 style="text-align: center">Система демонстрации</h3>
<p style="text-align: justify">
Данный раздел - описание существующих возможностей взаимодействия с
системой демонстрации изученного материала.<br />
На рисунке 3.1 виден весь основной интерфейс пользователя, необходимый для
полноценного комфортного взаимодействия с данной системой.
</p>
<div style="text-align: center">
<img src="demonstration.png" />
<p style="text-align: center">
Рисунок 2.1 - система демонстрации вставки элемента в хеш-таблицу
</p>
</div>
<p style="text-align: justify">
Каждая цифра указывает на определённый интерфейс пользователя, где даётся
его описание:
</p>
<ol>
<li style="text-align: justify">
Табличное представление модели, которое&nbsp;заполняется ранее
вставленными в хеш-таблицу элементами в порядке их хранения в самой
хей-таблице.
</li>
<li style="text-align: justify">
График, показывающий тенденцию изменения коэффициента простого
равномерного хеширования на протяжении процесса вставки элементов в
хеш-таблицу.
</li>
<li style="text-align: justify">
График, показывающий тенденцию изменения количества коллизий&nbsp;на
протяжении процесса вставки элементов в хеш-таблицу.
</li>
<li style="text-align: justify">
Группирующий блок, позволяющий изменять способ решения проблем
коллизий&nbsp;хеш-таблицы.
</li>
<li style="text-align: justify">
Группирующий блок, позволяющий изменять применяемую в процессе вставки
элемента хеш-функцию.
</li>
<li style="text-align: justify">
Группирующий блок, позволяющий изменять применяемую в процессе вставки
элемента&nbsp;алгоритм, применяемый в попытке решения колизии на основе
таблицы с открытой адрессацией.
</li>
<li style="text-align: justify">
Сгруппированный интерфейс, позволяющий создать новую хеш-таблицу с
указанием размера первоначального контейнера, сбросить действительную
хеш-таблицу, запросить последнюю статистику по операциям вставки
элементов
</li>
<li style="text-align: justify">
Сгруппированный интерфейс, позволяющий создавать инструкции по вставке
новых элементов в хеш таблицу несколькими способами: n-ое количество
элементов разных элементов и один единственный, где задаётся первый
элемент. Так же существует возможность поиска первого несуществующего
элемента хеш-таблице, остановки процесса вставки элементов в
хеш-таблцицу, фокусирования графиков для полного отображения информации.
Каждая функция соответствует своей кнопке данного сгруппированного
интерфейса.
</li>
<li style="text-align: justify">
Вывод информации о действиях пользователя и результатах хеширования
элементов.
</li>
<li style="text-align: justify">
Масштабирование всех видов, вплоть до освобождения места для
определённого вида с целью его более детального рассмотрения.
Существвует возможность полного масштабирования одного вида, взамен
скрытия всех остальных.
</li>
</ol>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Main</title>
</head>
<body>
<h2 style="text-align: center">Руководство пользователя</h2>
<h3 style="text-align: center">
Предоставление помощи пользователю<br />
в использовании демонстрационной программы:<br />
&quot;Алгоритм вставки в хеш-таблицу&quot;
</h3>
<p style="text-align: justify;">
Данное руководство предназначено пользователю для лучшего понимания работы
программы и взаимодействия с ней.
</p>
<p>Оглавление:</p>
<ol>
<li>
<a href="theoryPage.html">Раздел теории</a>
<ul>
<li><a href="theory.html">Теория</a></li>
<li><a href="demonstration.html">Демонстрация</a></li>
</ul>
</li>
<li><a href="testingPage.html">Раздел тестирования</a></li>
<li><a href="menubar.html">Полоса или строка меню</a></li>
</ol>
</body>
</html>
+57
View File
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Menubar</title>
</head>
<body>
<h2 style="text-align: center">Руководство пользователя</h2>
<h3 style="text-align: center">Полоска или строка меню</h3>
<p style="text-align: justify">
Данный раздел - описание существующих возможностей взаимодействия с
посолкой или строкой меню данной программы.<br />
На рисунке 5.1 и 5.2 отображены подменю, каждое из которых группирует
определённые действия.
</p>
<div style="text-align: center">
<img src="menubarFirst.png" />
<p style="text-align: center">
Рисунок 5.1 - подменю выбора текущего раздела
</p>
<p style="text-align: center">
<img src="menubarSecond.png" />
</p>
<p>Рисунок 5.2 - подменю предоставления помощи</p>
</div>
<p style="text-align: justify">
<span style="text-align: center"
>Первое подменю (см. рис. 5.1) необходимо для переключения разделов -
раздел теории, который включает две системы (система теории и система
демонстрации) и раздел тестирования.</span
>
</p>
<p style="text-align: justify">
Каждая цифра указывает на определённый интерфейс пользователя, где даётся
его описание:
</p>
<ol>
<li style="text-align: justify">
Действие подменю, необходимое для переключения вида на раздел теории.
</li>
<li style="text-align: justify">
Действие подменю, необходимое для переключения вида на раздел практики.
</li>
<li style="text-align: justify">
Действие подменю, необходимое для открытия модального диалогового окна -
руководства пользователя.
</li>
<li style="text-align: justify">
Действие подменю, необходимое для открытия модального диалогового окна,
которое содержит информацию об использующимся&nbsp;программой фреймворке
Qt.
</li>
</ol>
</body>
</html>
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PracticPage</title>
</head>
<body>
<h2 style="text-align: center">Руководство пользователя</h2>
<h3 style="text-align: center">Система тестирования</h3>
<p style="text-align: justify">
Данный раздел - описание существующих возможностей взаимодействия с
системой тестирования.<br />
На рисунке 4.1 виден весь основной интерфейс пользователя, необходимый для
полноценного комфортного взаимодействия с данной системой.
</p>
<div style="text-align: center">
<img src="testingPage.html" />
<p style="text-align: center">Рисунок 4.1 - система тестирования</p>
</div>
<p style="text-align: justify">
Каждая цифра указывает на определённый интерфейс пользователя, где даётся
его описание:
</p>
<ol>
<li style="text-align: justify">
Отображаемый текст, как текущий вопрос с описанием ввода правильного
ответа и самого тестового задания.
</li>
<li style="text-align: justify">
Панель ввода правильного ответа. Может представлять
определённое&nbsp;количество&nbsp;флагов для указания множественного
ответа из множества альтернатив (от 5-и до 9-и),&nbsp;поле ввода целого
числа или&nbsp;числа с плавающей точкой.
</li>
<li style="text-align: justify">
Нажимная кнопка для подтверждения ответа и проверки его на корректность.
</li>
<li style="text-align: justify">
Выходная информация, как способ идентификации успешного / безуспешного
начала тестирования с указанием конкретной ошибки, завершения
тестирования и успешного / безуспешного ответа на предыдущий вопрос.
</li>
<li style="text-align: justify">
Нажимная кнопка, реализующая начало тестирования.
</li>
<li style="text-align: justify">
Нажимная кнопка, реализующая предварительное завершение тестирования.
</li>
<li style="text-align: justify">
Группирующий интерфейс необходимый для выбора типа предоставляемых
вопросов в процессе тестирования.
</li>
<li style="text-align: justify">
Группирующий интерфейс&nbsp;необходимый для выбора сложности
предоставляемых вопросов в процессе тестирования.
</li>
</ol>
<p style="text-align: justify">
Стоит отметить, что результат тестирования сохраняется в бинарном файле
(формат записи смотри в технической документации), когда тестирование
завершается после окончания подходящих под критерии вопросов или решения
пользователя, при нажатии соответствующей кнопки.
</p>
</body>
</html>
+63
View File
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Theory</title>
</head>
<body>
<h2 style="text-align: center">Руководство пользователя</h2>
<h3 style="text-align: center">Система теории</h3>
<p style="text-align: justify">
Данный раздел - описание существующих возможностей взаимодействия с
системой изучения теоретического материала.<br />
На рисунке 2.1 виден весь основной интерфейс пользователя, необходимый для
полноценного комфортного взаимодействия с данной системой.
</p>
<div style="text-align: center">
<img src="theory.png" />
<p style="text-align: center">
Рисунок 2.1 - система изучения теоретического материала
</p>
</div>
<p style="text-align: justify">
Каждая цифра указывает на определённый интерфейс пользователя, где даётся
его описание:
</p>
<ol>
<li style="text-align: justify">
Нажимная кнопка, при нажатии которой пользователь переходит на следующую
страницу теоретического материала. Доступна, если отображается не
главная и не последняя страницы.
</li>
<li style="text-align: justify">
Нажимная кнопка, при нажатии которой пользователь переходит на главную
страницу теоретического материала. Доступна, если не отображается
главная страница.
</li>
<li style="text-align: justify">
Нажимная кнопка, при нажатии которой пользователь переходит на
предыдущую страницу теоретического материала. Доступна, если
отображается не главная и не первая страницы.
</li>
<li style="text-align: justify">
Нажимная кнопка, позволяющая&nbsp;отобразить предыдущую небольшую
доступную часть отображаемой страницы.
</li>
<li style="text-align: justify">
Ползунок, при перемещении которого можно перейти к любой части
отображаемой страницы.
</li>
<li style="text-align: justify">
Нажимная кнопка, позволяющая отобразить следующую&nbsp;небольшую
доступную&nbsp;часть отображаемой страницы.
</li>
<li style="text-align: justify">
Гиперссылка оглавления, при нажатии на которую пользователь может
перейти к любой интересующей его теме, которая описывается в отдельной
страцице.
</li>
</ol>
</body>
</html>
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TheoryPage</title>
</head>
<body>
<h2 style="text-align: center">Руководство пользователя</h2>
<h3 style="text-align: center">Раздел теории</h3>
<p style="text-align: justify">
Данный раздел - первое, что видит пользователь, при первом запуске
программы.<br />
На рисунке 1.1 виден весь основной интерфейс пользователя, необходимый для
перехода в ту или иную систему.
</p>
<div style="text-align: center">
<img src="theoryPage.png"/>
<p style="text-align: center">Рисунок 1.1 - раздел теории и практики</p>
</div>
<p>Всего существует три системы:</p>
<ul>
<li style="text-align: justify">Теории.</li>
<li style="text-align: justify">Демонстрации.</li>
<li style="text-align: justify">Тестирования.</li>
</ul>
<p style="text-align: justify">
Основой графического интерфейса пользователя являются нажимаемые кнопки,
переключающие между собой вкладки, флажки множественного или одиночного
выборов, и другие элементы, которые будут обсуждаться по мере описания
данного руководства. Каждая цифра указывает на определённый интерфейс
пользователя, где даётся его описание:
</p>
<ol>
<li style="text-align: justify">
Раздел изучения теоретического материала, необходимый для понимания темы
&quot;Алгоритм вставки элемента в хеш-таблицу&quot;.
</li>
<li style="text-align: justify">
Раздел демонстрации вставки элемента в хеш-таблицу.&nbsp;
</li>
<li style="text-align: justify">
Полоса или строка меню, как единственный способ переключения фокуса
между системами теории, которая&nbsp;подразумевает включение системы
демонстрации, и тестирования.
</li>
</ol>
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<info>
<directory>:/ManualHTML/Pages</directory>
<directory>:/ManualHTML/Images</directory>
<order>
<page>main.html</page>
<page>theoryPage.html</page>
<page>theory.html</page>
<page>demonstration.html</page>
<page>testingPage.html</page>
<page>menubar.html</page>
</order>
</info>
@@ -0,0 +1,21 @@
#ifndef LATIN_VALIDATOR_H
#define LATIN_VALIDATOR_H
#include <QValidator>
class LatinValidator : public QValidator {
public:
LatinValidator(QObject *parent) : QValidator(parent)
{
}
virtual State validate(QString& str, int&) const override {
QRegExp rxp = QRegExp("[!-~]*");
if (str.contains(rxp)) {
return Acceptable;
}
return Invalid;
}
};
#endif // LATIN_VALIDATOR_H
@@ -0,0 +1,564 @@
#include "demonstrationWidget.h"
inline void DemonstrationWidget::TableInformation::clear() {
for (size_t *value :
{&m_maxCollision, &m_numberOfSuccesses, &m_numberOfFailures}) {
*value = 0;
}
for (double *value : {&m_lastCoefficient, &m_maxCoefficient}) {
*value = 0;
}
for (auto *series : {m_pSeriesNumberOfCollisions}) {
series->removePoints(0, series->count());
}
m_pSeriesNumberOfCollisions->append(0, 0);
m_lastCoord = {0, 0};
m_lastValue = {'\0', '\0', '\0', '\0', '\0'};
m_lastInsertion = false;
}
DemonstrationWidget::DemonstrationWidget(QWidget *pWidget)
: QWidget(pWidget),
m_pChartCollisionsView(new QChartView(new QChart, this)),
m_pStandardModel(nullptr), m_stop(false), m_pFunction(nullptr),
m_complicatedFunction(nullptr), m_pAlgorithm(nullptr),
m_alphabetPower(endChar - firstChar + 1), m_pTable(nullptr),
m_tableInformation(new QLineSeries(m_pChartCollisionsView->chart())) {
setupUi(dynamic_cast<QWidget *>(this));
m_tableView->horizontalHeader()->setSectionResizeMode(
QHeaderView::ResizeToContents);
QGridLayout *gridLayout = new QGridLayout;
/*
* Сhart
*/
auto *axisX = new QValueAxis();
auto *axisY = new QValueAxis();
axisX->setTickCount(20);
axisY->setTickCount(10);
axisX->setRange(1, 2);
axisY->setRange(0, 1);
QChart *chartCollision = m_pChartCollisionsView->chart();
chartCollision->setTitle("Graph of collision changes");
chartCollision->legend()->hide();
chartCollision->addAxis(axisX, Qt::AlignBottom);
chartCollision->addAxis(axisY, Qt::AlignLeft);
chartCollision->addSeries(m_tableInformation.m_pSeriesNumberOfCollisions);
m_tableInformation.m_pSeriesNumberOfCollisions->attachAxis(axisX);
m_tableInformation.m_pSeriesNumberOfCollisions->attachAxis(axisY);
/*
* View(-s)
*/
m_pChartCollisionsView->installEventFilter(this);
m_pChartCollisionsView->setRubberBand(QChartView::RectangleRubberBand);
m_pChartCollisionsView->setRenderHint(QPainter::Antialiasing);
m_pChartCollisionsView->setMinimumHeight(m_tableView->minimumHeight());
m_pChartCollisionsView->setMinimumWidth(m_tableView->minimumWidth());
/*
* Splitter
*/
QSplitter *splitter = new QSplitter(Qt::Vertical);
splitter->addWidget(m_tableView);
splitter->addWidget(m_pChartCollisionsView);
gridLayout->addWidget(splitter, 0, 0, 1, 1);
gridLayout->addWidget(m_rightScrollArea, 0, 1, 1, 1);
gridLayout->addWidget(m_frmProgressBar, 1, 0, 1, 2);
setLayout(gridLayout);
/*
* Validator and HTML theory
*/
m_leFrom->setValidator(new LatinValidator(m_leFrom));
m_leInsert->setValidator(new LatinValidator(m_leInsert));
/*
* Signal & slots
*/
connect(m_pbReset, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedReset);
connect(m_pbApply, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedApply);
connect(m_pbStatistics, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedStatistics);
connect(m_pbMakeItems, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedMakeItems);
connect(m_pbInsert, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedInsert);
connect(m_pbFindFree, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedFindFree);
connect(m_pbStop, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedStop);
connect(m_pbFocus, &QPushButton::clicked, this,
&DemonstrationWidget::slotClickedFocus);
connect(m_rbFNV1a32bit, &QRadioButton::toggled, this,
&DemonstrationWidget::slotUpdateAdditionalInputData);
connect(m_rbPseudorandomProbing, &QRadioButton::toggled, this,
&DemonstrationWidget::slotUpdateAdditionalInputData);
connect(m_rbDoubleHashing, &QRadioButton::toggled, this,
&DemonstrationWidget::slotUpdateAdditionalInputData);
connect(m_rbChains, &QRadioButton::toggled, this,
&DemonstrationWidget::slotUpdateAdditionalInputData);
/*
* GUI
*/
m_frmProgressBar->hide();
m_frmFirstInputData->hide();
m_frmSecondInputData->hide();
m_gbInputData->hide();
}
/*
* Inserting elements
*/
void DemonstrationWidget::successfulInsertion(const table_type *,
const value_type &value,
std::pair<size_t, size_t> index,
size_t numberOfCollisions) {
m_tableInformation.m_lastCoord = index;
m_tableInformation.m_lastValue = value;
m_tableInformation.m_lastInsertion = true;
++m_tableInformation.m_numberOfSuccesses;
m_tableInformation.m_lastCollision = numberOfCollisions;
m_tableInformation.m_maxCollision = {numberOfCollisions >
m_tableInformation.m_maxCollision
? numberOfCollisions
: m_tableInformation.m_maxCollision};
m_tableInformation.m_lastCollision = numberOfCollisions;
if (numberOfCollisions > m_tableInformation.m_maxCollision) {
m_tableInformation.m_maxCollision = numberOfCollisions;
}
m_tableInformation.m_pSeriesNumberOfCollisions->append(
m_tableInformation.m_numberOfSuccesses, numberOfCollisions);
QModelIndex modelIndex = m_pStandardModel->index(index.first, index.second);
if (getCurrentTableType() == TableType::Chain) {
updateColumns(index.first);
} else {
m_pStandardModel->setData(modelIndex, QVariant(toQString(value)));
}
}
void DemonstrationWidget::unsuccessfulInsertion(const table_type *,
const value_type &value) {
m_tableInformation.m_lastValue = value;
m_tableInformation.m_lastInsertion = false;
++m_tableInformation.m_numberOfFailures;
}
inline void DemonstrationWidget::updateColumns(size_t rowIndex) {
using namespace BusinessLogic::Hash::Table;
auto tableRow =
dynamic_cast<BusinessLogic::Hash::Table::Chains *>(m_pTable.get())
->row(rowIndex);
size_t modelColumnCount = m_pStandardModel->columnCount();
size_t tableColumnCount = tableRow.size();
if (modelColumnCount < tableColumnCount) {
m_pStandardModel->insertColumns(
modelColumnCount,
std::max(tableColumnCount - modelColumnCount,
static_cast<size_t>(std::ceil(
std::sqrt(m_tableInformation.m_lastCoefficient)))));
}
QModelIndex modelIndex;
auto iterator = tableRow.begin();
for (size_t i = 0, size = tableRow.size(); i < size; ++i, ++iterator) {
modelIndex = m_pStandardModel->index(rowIndex, i);
m_pStandardModel->setData(modelIndex, QVariant(toQString(*iterator)));
}
}
inline void DemonstrationWidget::updateCharts() {
m_pChartCollisionsView->chart()
->axes(Qt::Horizontal)
.front()
->setRange(1, m_tableInformation.m_numberOfSuccesses);
m_pChartCollisionsView->chart()
->axes(Qt::Vertical)
.front()
->setRange(0, m_tableInformation.m_maxCollision);
m_pChartCollisionsView->chart()->resetMatrix();
}
inline void DemonstrationWidget::updateTableView() {
m_tableView->scrollTo(
m_pStandardModel->index(m_tableInformation.m_lastCoord.first,
m_tableInformation.m_lastCoord.second),
QAbstractItemView::PositionAtCenter);
m_tableView->repaint();
}
inline DemonstrationWidget::value_type &
DemonstrationWidget::next(value_type &value) const {
auto rbegin = value.rbegin();
auto rend = value.rend();
for (; rbegin != rend; ++rbegin) {
if (*rbegin >= firstChar && *rbegin < endChar) {
++(*rbegin);
return value;
} else if (*rbegin == '\0') {
*rbegin = firstChar;
return value;
} else {
*rbegin = firstChar;
}
}
value = toStdArray(std::string(4, '\0') + firstChar);
return value;
}
inline bool DemonstrationWidget::checkBeforeInsertion(bool tableTypeIsChain) {
size_t quantityOfInserts = m_sbQuantity->value();
if (tableTypeIsChain &&
(m_pTable->numberOfBuckets() + quantityOfInserts) / m_pTable->size() >
10) {
outputMessage(
"Prohibit insertion when allocating more than 10 elements per chain",
"red");
return false;
}
return true;
}
inline void DemonstrationWidget::slotClickedMakeItems() {
using namespace BusinessLogic::Convert;
bool tableTypeIsChain = getCurrentTableType() == TableType::Chain;
if (not checkBeforeInsertion(tableTypeIsChain)) {
return;
}
/*
* Preparing
*/
if (tableTypeIsChain && m_pStandardModel->columnCount() == 0) {
m_pStandardModel->insertColumns(0, m_sbQuantity->value() /
m_sbBucketQuantity->value());
}
m_frmProgressBar->setVisible(true);
m_progressBar->setValue(0);
/*
* For other thread
*/
setEnabledInsertingProcess(false);
m_frmProgressBar->setVisible(true);
auto differenceNumberOfSuccesses = m_tableInformation.m_numberOfSuccesses;
auto differenceNumberOfFailures = m_tableInformation.m_numberOfFailures;
int value;
value_type currentString = toStdArray(m_leFrom->text().toStdString());
for (size_t progress = 0, target = m_sbQuantity->value(); progress < target;
++progress) {
m_pTable->insert(currentString);
next(currentString);
if (m_stop) {
m_stop = false;
break;
}
value = static_cast<int>(
progress * static_cast<double>(m_progressBar->maximum()) / target);
if (value > m_progressBar->value()) {
m_progressBar->setValue(value);
}
QApplication::processEvents();
}
updateCharts();
updateTableView();
m_frmProgressBar->setVisible(false);
setEnabledInsertingProcess(true);
/*
* Output message
*/
differenceNumberOfSuccesses =
m_tableInformation.m_numberOfSuccesses - differenceNumberOfSuccesses;
differenceNumberOfFailures =
m_tableInformation.m_numberOfFailures - differenceNumberOfFailures;
m_lblOutputMessages->setText(
getColorTextHTML(
QString("Successful inserts: %1").arg(differenceNumberOfSuccesses),
"green") +
"<br>" +
getColorTextHTML(QString("Failed inserts&nbsp;&nbsp;&nbsp;&nbsp;: %1")
.arg(differenceNumberOfFailures),
"red"));
}
inline void DemonstrationWidget::slotClickedInsert() {
bool tableTypeIsChain = getCurrentTableType() == TableType::Chain;
if (not checkBeforeInsertion(tableTypeIsChain)) {
return;
}
m_pTable->insert(toStdArray(m_leInsert->text().toStdString()));
outputMessage(m_tableInformation.m_lastInsertion ? "Inserting is successful"
: "The insertion has failed",
m_tableInformation.m_lastInsertion ? "green" : "red");
}
/*
* Other logic
*/
inline auto DemonstrationWidget::getCurrentFactory() const {
using namespace BusinessLogic::Hash;
std::unique_ptr<const Factory::Abstract> factory;
bool functionTypeIsFamily =
getCurrentFunctionType() == RelationshipType::Family;
if (getCurrentAlgorythmType() == RelationshipType::One) {
factory = std::make_unique<Factory::One>(
functionTypeIsFamily
? m_complicatedFunction // The complicated function must be prepared
: std::dynamic_pointer_cast<Function::One::Creator>(m_pFunction),
std::dynamic_pointer_cast<Algorithm::One::Creator>(m_pAlgorithm));
} else if (functionTypeIsFamily) {
factory = std::make_unique<Factory::Family>(
std::dynamic_pointer_cast<Function::Family::Creator>(m_pFunction),
std::dynamic_pointer_cast<Algorithm::Family::Creator>(m_pAlgorithm));
} else {
std::invalid_argument("function type not defined");
}
return factory;
}
inline void DemonstrationWidget::updateFunctionCreator() {
using namespace BusinessLogic::Hash::Function;
if (m_rbEquivalent->isChecked()) {
m_pFunction = std::make_shared<Equivalent::Creator>();
} else if (m_rbStandart->isChecked()) {
m_pFunction = std::make_shared<Standart::Creator>();
} else { // m_rbFNV1a32bit->isChecked()
m_pFunction = std::make_shared<FNV1a::Creator>();
}
}
inline void DemonstrationWidget::updateAlgorithmCreator() {
using namespace BusinessLogic::Hash::Algorithm;
if (m_rbLinearProbing->isChecked()) {
m_pAlgorithm = std::make_shared<LinearProbing::Creator>();
} else if (m_rbQuadraticProbing->isChecked()) {
m_pAlgorithm = std::make_shared<QuadraticProbing::Creator>();
} else if (m_rbPseudorandomProbing->isChecked()) {
m_pAlgorithm = std::make_shared<PseudorandomProbing::Creator>(
m_sbFirstInputData->value());
} else { // m_rbDoubleHashing->isChecked()
m_pAlgorithm = std::make_shared<DoubleHashing::Creator>(
m_sbFirstInputData->value(), m_sbSecondInputData->value());
}
}
inline void DemonstrationWidget::deleteModel() {
auto stringListModel = m_tableView->selectionModel();
m_tableView->setModel(nullptr);
if (stringListModel not_eq nullptr) {
delete stringListModel;
}
}
/*
* Table GUI
*/
inline void DemonstrationWidget::slotUpdateAdditionalInputData() {
bool predicate = {getCurrentFunctionType() == RelationshipType::Family};
m_gbInputData->setVisible(predicate);
m_frmFirstInputData->setVisible(predicate);
if (getCurrentTableType() == TableType::Chain) {
m_rbStandart->setEnabled(true);
m_rbEquivalent->setEnabled(true);
m_frmSecondInputData->setVisible(false);
} else {
bool algorythmIsFamily =
getCurrentAlgorythmType() == RelationshipType::Family;
m_rbEquivalent->setDisabled(algorythmIsFamily);
m_rbStandart->setDisabled(algorythmIsFamily);
m_frmSecondInputData->setVisible(algorythmIsFamily);
if (algorythmIsFamily) {
m_rbFNV1a32bit->setChecked(true);
repaint();
m_frmSecondInputData->setVisible(m_rbDoubleHashing->isChecked());
}
}
}
inline void DemonstrationWidget::slotClickedApply() {
using namespace BusinessLogic::Hash;
using namespace BusinessLogic::Hash::Function::Pattern;
if (m_rbDoubleHashing->isChecked() &&
m_sbFirstInputData->value() == m_sbSecondInputData->value()) {
outputMessage("Hash function coefficients should not match", "red");
return;
}
updateFunctionCreator();
updateAlgorithmCreator();
bool tableTypeIsChain = getCurrentTableType() == TableType::Chain;
bool functionTypeIsFamily =
getCurrentFunctionType() == RelationshipType::Family;
if (functionTypeIsFamily && (tableTypeIsChain || getCurrentAlgorythmType() ==
RelationshipType::One)) {
m_complicatedFunction = std::make_shared<FamilyToOne::Creator>(
std::dynamic_pointer_cast<Function::Family::Creator>(m_pFunction),
m_sbFirstInputData->value());
}
size_t bucketQuantity = m_sbBucketQuantity->value();
try {
if (tableTypeIsChain) {
m_pTable = std::make_unique<Table::Chains>(
bucketQuantity,
functionTypeIsFamily
? *m_complicatedFunction
: *std::dynamic_pointer_cast<Function::One::Creator>(m_pFunction),
m_alphabetPower);
} else {
auto factory = getCurrentFactory();
m_pTable = std::make_unique<Table::OpenAddressing>(
bucketQuantity, *factory, m_alphabetPower);
}
} catch (const std::bad_alloc &err) {
outputMessage("Not enough RAM", "red");
return;
}
setEnabledCreateHashTable(false);
m_pbFocus->setEnabled(true);
m_pTable->signTheObject(this);
/*
* A descendant will notify an ancestor of his own destruction when using
* delete
*/
deleteModel();
m_pStandardModel =
new QStandardItemModel(bucketQuantity, (tableTypeIsChain ? 0 : 1), this);
m_tableView->setModel(m_pStandardModel);
m_lblOutputMessages->setText(
getColorTextHTML("The model was created", "green"));
}
inline void DemonstrationWidget::slotClickedStatistics() {
m_tableInformation.m_lastCoefficient =
m_pTable->simpleUniformHashingCoefficient();
QMessageBox::information(
nullptr, "Statistics",
QString("Maximum number of collisions:\t%1\n")
.arg(m_tableInformation.m_maxCollision) +
QString("Number of successful inserts:\t\t%1\n")
.arg(m_tableInformation.m_numberOfSuccesses) +
QString("Number of failed inserts:\t\t%1\n")
.arg(m_tableInformation.m_numberOfFailures) +
QString("Simple uniform hashing coefficient:\t%1\n")
.arg(m_tableInformation.m_lastCoefficient));
}
inline void DemonstrationWidget::slotClickedFindFree() {
QString result;
if (m_pTable->numberOfBuckets() == 0) {
result = firstChar;
} else {
value_type currentString = m_tableInformation.m_lastValue;
while (m_pTable->isExist(next(currentString)))
continue;
result = toQString(currentString);
}
m_leFrom->setText(result);
m_leInsert->setText(result);
}
inline void DemonstrationWidget::slotClickedStop() {
m_stop = true;
setEnabledInsertingProcess(true);
}
inline void DemonstrationWidget::slotClickedFocus() { updateCharts(); }
/*
* Base GUI
*/
inline void DemonstrationWidget::slotClickedReset() {
setEnabledCreateHashTable(true);
m_pbFocus->setDisabled(true);
m_complicatedFunction.reset();
m_pTable.release();
m_tableInformation.clear();
resetAxes();
deleteModel();
outputMessage("The model has been deleted", "green");
}
inline QString
DemonstrationWidget::getColorTextHTML(const QString &text,
const char *const color) const {
return QString(m_fontBeginColorHTML).arg(color) + text + m_fontEndHTML;
}
inline void DemonstrationWidget::outputMessage(const QString &text,
const char *const color) {
m_lblOutputMessages->setText(getColorTextHTML(text, color));
}
inline void DemonstrationWidget::setEnabledCreateHashTable(bool flag) {
for (QWidget *widget : std::initializer_list<QWidget *>{
m_pbApply, m_sbBucketQuantity, m_gbResolutionOfCollisions,
m_gbFunction, m_gbInputData}) {
widget->setEnabled(flag);
}
if (getCurrentTableType() not_eq TableType::Chain) {
m_gbAlgorithm->setEnabled(flag);
}
m_gbLoadTable->setDisabled(flag);
m_pbStatistics->setDisabled(flag);
}
inline void DemonstrationWidget::setEnabledInsertingProcess(bool flag) {
for (QWidget *widget : std::initializer_list<QWidget *>{
m_leFrom, m_sbQuantity, m_pbMakeItems, m_leInsert, m_pbInsert,
m_pbReset, m_pbStatistics, m_pbFindFree}) {
widget->setEnabled(flag);
}
m_pbStop->setDisabled(flag);
}
@@ -0,0 +1,233 @@
#ifndef DEMONSTRATION_WIDGET_H
#define DEMONSTRATION_WIDGET_H
#include "../../Validator/validator.h"
#include "SourceCode/BusinessLogic/businessLogic.h"
#include "SourceCode/BusinessLogic/hashHeaderFiles.h"
#include "hashTable.h"
#include "ui_demonstrationWidget.h"
#include <algorithm>
#include <array>
#include <memory>
#include <thread>
#include <QChartView>
#include <QLineSeries>
#include <QStringListModel>
#include <QtCharts>
class DemonstrationWidget
: public QWidget,
protected Ui::DemonstrationWidget,
public BusinessLogic::Hash::Table::Pattern::InterfaceSubscriber {
public:
using value_type = BusinessLogic::Hash::Table::Abstract::value_type;
using table_type = BusinessLogic::Hash::Table::Abstract;
private:
struct TableInformation {
public:
/* Qt containers */
QLineSeries *m_pSeriesNumberOfCollisions;
/* If successful */
std::pair<size_t, size_t> m_lastCoord;
size_t m_numberOfSuccesses;
size_t m_lastCollision;
size_t m_maxCollision;
double m_lastCoefficient;
double m_maxCoefficient;
/* If unsuccessful */
size_t m_numberOfFailures;
/* In any case */
value_type m_lastValue;
bool m_lastInsertion;
public:
TableInformation(const TableInformation &) = delete;
TableInformation(TableInformation &&) = delete;
TableInformation(QLineSeries *maxCollision)
: m_pSeriesNumberOfCollisions(maxCollision) {
clear();
};
public:
void clear();
};
private: // Event filter
virtual bool eventFilter(QObject *target, QEvent *event) override {
if (target == m_pChartCollisionsView) {
QChartView *view = dynamic_cast<QChartView *>(target);
QChart *chart = view->chart();
switch (event->type()) {
case QEvent::Wheel: {
QWheelEvent *currentEvent = dynamic_cast<QWheelEvent *>(event);
qreal factor = currentEvent->angleDelta().y() > 0 ? 0.9 : 1.1;
QRectF rect = QRectF(chart->plotArea().left(), chart->plotArea().top(),
chart->plotArea().width() * factor,
chart->plotArea().height() * factor);
QPointF mousePos = view->mapFromGlobal(QCursor::pos());
rect.moveCenter(mousePos);
chart->zoomIn(rect);
QPointF delta = chart->plotArea().center() - mousePos;
chart->scroll(delta.x(), -delta.y());
return true;
} break;
default: {
return false;
} break;
}
}
return false;
}
public:
enum class TableType : short { Chain, OpenAdressing, Indefined };
enum class RelationshipType : short { One, Family, Indefined };
private:
/*
* Constants
*/
static constexpr char firstChar = '!';
static constexpr char endChar = '~';
QChartView *m_pChartCollisionsView;
QStandardItemModel *m_pStandardModel;
bool m_stop;
/*
* Business logic
*/
std::shared_ptr<BusinessLogic::Hash::Function::Abstract::Creator> m_pFunction;
std::shared_ptr<BusinessLogic::Hash::Function::One::Creator>
m_complicatedFunction;
std::shared_ptr<BusinessLogic::Hash::Algorithm::Abstract::Creator>
m_pAlgorithm;
size_t m_alphabetPower;
std::unique_ptr<BusinessLogic::Hash::Table::Abstract> m_pTable;
TableInformation m_tableInformation;
/*
* HTML tags
*/
static constexpr auto m_fontBeginColorHTML = R"(<font color="%1">)";
static constexpr auto m_fontEndHTML = R"(</font>)";
public:
DemonstrationWidget(QWidget *pWidget = nullptr);
public: // Custom slots
virtual void successfulInsertion(const table_type *, const value_type &,
std::pair<size_t, size_t>, size_t) override;
virtual void unsuccessfulInsertion(const table_type *,
const value_type &) override;
private:
/*
* Business logic
*/
TableType getCurrentTableType() const {
TableType result;
result = {m_rbChains->isChecked() ? TableType::Chain
: m_rbOpenAdressing->isChecked() ? TableType::OpenAdressing
: TableType::Indefined};
if (result == TableType::Indefined) {
throw std::invalid_argument("table not defined");
}
return result;
}
RelationshipType getCurrentFunctionType() const {
RelationshipType result;
result = {m_rbEquivalent->isChecked() ? RelationshipType::One
: m_rbStandart->isChecked() ? RelationshipType::One
: m_rbFNV1a32bit->isChecked() ? RelationshipType::Family
: RelationshipType::Indefined};
if (result == RelationshipType::Indefined) {
throw std::invalid_argument("function not defined");
}
return result;
}
RelationshipType getCurrentAlgorythmType() const {
RelationshipType result;
result = {m_rbLinearProbing->isChecked() ? RelationshipType::One
: m_rbQuadraticProbing->isChecked() ? RelationshipType::One
: m_rbPseudorandomProbing->isChecked() ? RelationshipType::Family
: m_rbDoubleHashing->isChecked() ? RelationshipType::Family
: RelationshipType::Indefined};
if (result == RelationshipType::Indefined) {
throw std::invalid_argument("algorythm not defined");
}
return result;
}
auto getCurrentFactory() const;
void updateFunctionCreator();
void updateAlgorithmCreator();
void deleteModel();
void resetAxes() {
m_pChartCollisionsView->chart()
->axes(Qt::Horizontal)
.front()
->setRange(1, 2);
m_pChartCollisionsView->chart()->axes(Qt::Vertical).front()->setRange(0, 1);
}
QString toQString(const value_type &value) {
auto convert = value;
unsigned size =
std::remove(convert.begin(), convert.end(), '\0') - convert.begin();
return QString::fromLatin1(convert.data(), size);
}
value_type toStdArray(std::string &&value) const {
value_type result = {'\0', '\0', '\0', '\0', firstChar};
std::copy(value.rbegin(), value.rend(), result.rbegin());
return result;
}
value_type &next(value_type &value) const;
bool checkBeforeInsertion(bool);
/*
* GUI and displaying
*/
QString getColorTextHTML(const QString &text, const char *const color) const;
void outputMessage(const QString &text, const char *const color);
void updateColumns(size_t rowIndex);
void updateCharts();
void updateTableView();
void setEnabledCreateHashTable(bool flag);
void setEnabledInsertingProcess(bool flag);
public slots:
void slotTabSwitched(int index) {
if (index == 1) {
QSplitter *splitter = findChild<QSplitter *>("");
auto children = splitter->children();
QList<int> sizes{dynamic_cast<QWidget *>(children[0])->minimumHeight(),
dynamic_cast<QWidget *>(children[1])->minimumHeight()};
splitter->setSizes(sizes);
}
}
private slots:
void slotUpdateAdditionalInputData();
void slotClickedReset();
void slotClickedApply();
void slotClickedMakeItems();
void slotClickedInsert();
void slotClickedStatistics();
void slotClickedFindFree();
void slotClickedStop();
void slotClickedFocus();
};
#endif // DEMONSTRATION_WIDGET_H
@@ -0,0 +1,284 @@
#include "testingWidget.h"
TestingWidget::TestingWidget(QWidget *pWidget)
: QWidget(pWidget), m_currentComplexityName("everything"),
m_currentTopicName("everything"), m_file("./QuestionsXML/questions.xml") {
setupUi(dynamic_cast<QWidget *>(this));
connect(m_pbConfirm, &QPushButton::clicked, this,
&TestingWidget::slotClickedConfirm);
connect(m_pbStart, &QPushButton::clicked, this,
&TestingWidget::slotClickedStart);
connect(m_pbStop, &QPushButton::clicked, this,
&TestingWidget::slotResetTesting);
connect(m_rbAllDifficulties, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedComplexity);
connect(m_rbEasy, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedComplexity);
connect(m_rbMedium, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedComplexity);
connect(m_rbHard, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedComplexity);
connect(m_rbAllTopics, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedTopics);
connect(m_rbDiscreteMathematics, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedTopics);
connect(m_rbHashFunction, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedTopics);
connect(m_rbHashTable, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedTopics);
connect(m_rbAlgorithm, &QRadioButton::clicked, this,
&TestingWidget::slotSwitchedTopics);
m_frmConfirm->hide();
}
inline void TestingWidget::hideCheckBoxes() {
QCheckBox *currentCheckBox;
for (unsigned i = 0; i < 9; ++i) {
currentCheckBox = findChild<QCheckBox *>(QString("m_cbIndex%1").arg(i));
currentCheckBox->hide();
}
}
inline void TestingWidget::showCheckBoxes() {
QCheckBox *currentCheckBox;
for (unsigned i = 0, size = m_answers.size(); i < size; ++i) {
currentCheckBox = findChild<QCheckBox *>(QString("m_cbIndex%1").arg(i));
currentCheckBox->show();
currentCheckBox->setText(m_answers[i].first);
}
}
inline QString TestingWidget::getHTMLQuestion(QDomElement element) {
QString currentQuestion;
element = element.firstChildElement();
do {
switch (getTagsEnumFromQString(element.tagName())) {
case TagXML::Caption: {
currentQuestion.append(QString("<h3>%1</h3>").arg(element.text()));
} break;
case TagXML::Text: {
currentQuestion.append(QString(R"(
<p align="justify">
<var>
<font face="Times New Roman, Times, serif">
%2
</font>
</var>
</p>
)")
.arg(element.text()));
} break;
case TagXML::Answer: {
m_answers.append(std::make_pair(
element.text(), element.hasAttribute("type")
? (element.attribute("type") == "correct")
: false));
} break;
case TagXML::Question: {
throw std::invalid_argument(
"the question cannot be nested within the question");
} break;
case TagXML::Undefined: {
throw std::invalid_argument("tag undefined");
} break;
}
element = element.nextSiblingElement();
} while (not element.isNull());
return currentQuestion;
}
inline void TestingWidget::configureInput(const QString &value) {
hideCheckBoxes();
resetInput();
if (value == "choice") {
m_swInputData->setCurrentIndex(0);
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::shuffle(m_answers.begin(), m_answers.end(),
std::default_random_engine(seed));
showCheckBoxes();
} else if (value == "integer") {
m_swInputData->setCurrentIndex(1);
} else if (value == "floatingPoint") {
m_swInputData->setCurrentIndex(2);
} else {
throw std::invalid_argument("the type of the input option is undefined");
}
}
inline bool TestingWidget::showNextQuestion() {
bool continueFlag = true;
auto checkType = [](const QString &value) -> bool {
return bool{value == "choice" || value == "integer" ||
value == "floatingPoint"};
};
while (not m_currentQuestion.isNull() && continueFlag) {
m_currentTypeName = m_currentQuestion.attribute("type");
if ((m_currentTopicName == "everything" ||
m_currentQuestion.attribute("category")
.split('|')
.contains(m_currentTopicName)) &&
(m_currentComplexityName == "everything" ||
m_currentComplexityName ==
m_currentQuestion.attribute("complexity")) &&
checkType(m_currentTypeName)) {
m_answers.clear();
m_testingTextBrowser->setHtml(getHTMLQuestion(m_currentQuestion));
configureInput(m_currentTypeName);
continueFlag = false;
}
m_currentQuestion = m_currentQuestion.nextSiblingElement("question");
}
return (not continueFlag);
}
inline void TestingWidget::setEnabledGUIStartTesting(bool flag) {
m_gbTopics->setEnabled(flag);
m_gbDifficulty->setEnabled(flag);
m_pbStart->setEnabled(flag);
m_pbStop->setDisabled(flag);
m_frmConfirm->setVisible(not flag);
}
inline TestingWidget::TagXML
TestingWidget::getTagsEnumFromQString(const QString &value) {
TagXML result = {value == "question" ? TagXML::Question
: value == "caption" ? TagXML::Caption
: value == "text" ? TagXML::Text
: value == "answer" ? TagXML::Answer
: TagXML::Undefined};
return result;
}
/*
* Slots
*/
inline void TestingWidget::slotSwitchedTopics() {
QString result = {m_rbAllTopics->isChecked() ? QString("everything")
: m_rbDiscreteMathematics->isChecked()
? QString("discreteMathematics")
: m_rbHashFunction->isChecked() ? QString("hashFunction")
: m_rbHashTable->isChecked() ? QString("hashTable")
: m_rbAlgorithm->isChecked() ? QString("algorithm")
: QString()};
if (result.isNull()) {
throw std::invalid_argument("topic undefined");
}
m_currentTopicName = result;
}
inline void TestingWidget::slotSwitchedComplexity() {
QString result = {m_rbAllDifficulties->isChecked() ? QString("everything")
: m_rbEasy->isChecked() ? QString("easy")
: m_rbMedium->isChecked() ? QString("medium")
: m_rbHard->isChecked() ? QString("hard")
: QString()};
if (result.isNull()) {
throw std::invalid_argument("complexity undefined");
}
m_currentComplexityName = result;
}
inline bool TestingWidget::checkAnswer(const QString &value) {
if (m_answers.size() <= 0) {
return false;
}
bool result = true;
if (value == "choice") {
QCheckBox *currentCheckBox;
for (unsigned i = 0, size = m_answers.size(); i < size; ++i) {
currentCheckBox = findChild<QCheckBox *>(QString("m_cbIndex%1").arg(i));
if (m_answers[i].second) {
result &= currentCheckBox->isChecked();
} else {
result &= not currentCheckBox->isChecked();
}
}
} else if (value == "integer" || value == "floatingPoint") {
QString answer = {value == "integer" ? m_sbInteger->text()
: m_sbDouble->text()};
auto iter =
std::find_if(m_answers.begin(), m_answers.end(),
[answer](const std::pair<QString, bool> &value) -> bool {
return (value.second == true && value.first == answer);
});
return (iter not_eq m_answers.end());
} else {
throw std::invalid_argument("input not defined");
}
return result;
}
inline void TestingWidget::slotClickedConfirm() {
bool result = checkAnswer(m_currentTypeName);
emit signalReplyGiven(result);
if (not showNextQuestion()) {
setEnabledGUIStartTesting(true);
slotResetTesting();
}
}
inline void TestingWidget::slotClickedStart() {
bool isOpened = m_file.open(QIODevice::ReadOnly);
emit signalFileOpened(isOpened);
if (isOpened) {
bool isSet = m_document.setContent(&m_file);
m_file.close();
emit signalContentIsSet(isSet);
if (isSet) {
QDomNode questions =
m_document.firstChild().nextSiblingElement("questions");
if (questions.isNull()) {
return;
}
QDomNode firstQuestion =
questions.firstChild().nextSiblingElement("question");
if (firstQuestion.isNull()) {
return;
}
m_currentQuestion = firstQuestion.toElement();
if (showNextQuestion()) {
setEnabledGUIStartTesting(false);
emit signalStartOfTesting();
}
}
}
return;
}
inline void TestingWidget::resetInput() {
QCheckBox *currentCheckBox;
for (unsigned i = 0; i < 9; ++i) {
currentCheckBox = findChild<QCheckBox *>(QString("m_cbIndex%1").arg(i));
currentCheckBox->setChecked(false);
}
m_sbInteger->clear();
m_sbDouble->clear();
}
inline void TestingWidget::slotResetTesting() {
m_testingTextBrowser->clear();
setEnabledGUIStartTesting(true);
resetInput();
emit signalEndOfTesting();
}
@@ -0,0 +1,71 @@
#ifndef TESTING_WIDGET_H
#define TESTING_WIDGET_H
#include "ui_testingWidget.h"
#include <random>
#include <QWidget>
#include <QtXml>
#include <QMessageBox>
class TestingWidget : public QWidget
, protected Ui::TestingWidget
{
Q_OBJECT
private:
QDomDocument m_document;
QDomElement m_currentQuestion;
QString m_currentComplexityName;
QString m_currentTopicName;
QString m_currentTypeName;
QFile m_file;
QVector<std::pair<QString, bool>> m_answers;
private:
enum class Topic : short {
Everything, DiscreteMathematics, HashFunction, HashTable, Algorithm, Undefined
};
enum class Complexity : short {
Everything, Easy, Medium, Hard, Undefined
};
enum class TagXML : short {
Question, Caption, Text, Answer, Undefined
};
public:
TestingWidget(QWidget *pWidget = nullptr);
~TestingWidget() {
if(m_file.isOpen()) {
m_file.close();
}
}
private:
void hideCheckBoxes();
void showCheckBoxes();
QString getHTMLQuestion(QDomElement domNode);
void configureInput(const QString &);
bool showNextQuestion();
void setEnabledGUIStartTesting(bool flag);
TagXML getTagsEnumFromQString(const QString&);
bool checkAnswer(const QString&);
void resetInput();
private slots:
void slotSwitchedTopics();
void slotSwitchedComplexity();
void slotClickedConfirm();
void slotClickedStart();
void slotResetTesting();
signals:
void signalFileOpened(bool /*isOpen*/);
void signalContentIsSet(bool /*isSet*/);
void signalReplyGiven(bool /*isCorrect*/);
void signalStartOfTesting();
void signalEndOfTesting();
};
#endif // TESTING_WIDGET_H
@@ -0,0 +1,112 @@
#include "textBrowserWidget.h"
TextBrowserWidget::TextBrowserWidget(const QString &xmlFile, QWidget *pWidget)
: QWidget(pWidget)
{
setupUi(dynamic_cast<QWidget *>(this));
connect( m_main, &QPushButton::clicked, this, &TextBrowserWidget::slotClickedMain );
connect( m_next, &QPushButton::clicked, this, &TextBrowserWidget::slotClickedNext );
connect( m_previous, &QPushButton::clicked, this, &TextBrowserWidget::slotClickedPrev );
connect( m_textBrowser, &QTextBrowser::sourceChanged, this, &TextBrowserWidget::slotPageChanged );
m_textBrowser->setOpenExternalLinks(true);
unpack(xmlFile);
}
/*
* HTML theory
*/
inline void TextBrowserWidget::slotPageChanged(const QUrl &url) {
QString value = url.toString().section('/', -1);
auto iterator = std::find_if(m_htmlPages.cbegin(), m_htmlPages.cend()
, [value](const QString &other)->bool {
return ( other.section('/', -1) == value );
});
if(iterator == m_htmlPages.cend()) {
m_textBrowser->clear();
return;
}
m_currentIndexPage = iterator - m_htmlPages.cbegin();
bool isMainPage = (m_currentIndexPage == 0);
m_main->setDisabled(isMainPage);
m_previous->setEnabled( isMainPage ? false : m_currentIndexPage not_eq 1 );
m_next->setEnabled( isMainPage ? false : m_currentIndexPage not_eq (m_htmlPages.size() - 1) );
}
inline bool TextBrowserWidget::unpack(const QString &xmlFileName) {
QDomDocument xmlDocument;
QFile xmlFile(xmlFileName);
if(not xmlFile.open(QIODevice::ReadOnly)) {
return false;
}
bool isSet = xmlDocument.setContent(&xmlFile);
xmlFile.close();
if(not isSet) {
return false;
}
QDomElement infoNode = xmlDocument.firstChild().nextSiblingElement("info");
QDomElement currentDirectoryElement = infoNode.firstChildElement("directory");
QStringList searchPaths;
while (not currentDirectoryElement.isNull()) {
searchPaths.append(currentDirectoryElement.text());
currentDirectoryElement = currentDirectoryElement.nextSiblingElement("directory");
}
QDomElement currentPage = infoNode.firstChildElement("order").firstChildElement("page");
if(currentPage.isNull()) {
return false;
}
QStringList result;
QString currentTagName;
bool isExists;
while(not currentPage.isNull()) {
currentTagName = currentPage.text();
isExists = false;
for(const QString &name : searchPaths) {
if(QDir(name).exists(currentTagName)) {
isExists = true;
break;
}
}
if(not isExists) {
return false;
}
result.push_back(currentTagName);
currentPage = currentPage.nextSiblingElement("page");
}
m_textBrowser->setSearchPaths(searchPaths);
m_htmlPages = result;
return setSourceMainPage();
}
inline void TextBrowserWidget::slotClickedMain() {
if(m_currentIndexPage not_eq 0) {
m_textBrowser->setSource(m_htmlPages.front());
}
}
inline void TextBrowserWidget::slotClickedPrev() {
if(m_currentIndexPage not_eq 1) {
m_textBrowser->setSource(m_htmlPages[--m_currentIndexPage]);
}
}
inline void TextBrowserWidget::slotClickedNext() {
if(m_currentIndexPage not_eq (m_htmlPages.size() - 1)) {
m_textBrowser->setSource(m_htmlPages[++m_currentIndexPage]);
}
}
@@ -0,0 +1,50 @@
#ifndef THEORY_WIDGET_H
#define THEORY_WIDGET_H
#include "ui_textBrowserWidget.h"
#include <QWidget>
#include <QFile>
#include <QtXml>
class TextBrowserWidget : public QWidget
, protected Ui::TextBrowserWidget
{
private:
/*
* HTML
*/
QStringList m_htmlPages;
int m_currentIndexPage;
public:
TextBrowserWidget(const QString &xmlFile = {}
, QWidget *pWidget = nullptr);
public:
bool unpack(const QString &xmlFile);
void setFontPointSize(int size) {
QFont font = m_textBrowser->font();
font.setPointSize(size);
m_textBrowser->setFont(font);
}
private:
/*
* Business logic
*/
bool setSourceMainPage() {
if(not m_htmlPages.isEmpty()) {
m_textBrowser->setSource( QUrl( m_htmlPages.front() ) );
return true;
}
return false;
}
private slots:
void slotPageChanged(const QUrl &url);
void slotClickedMain();
void slotClickedPrev();
void slotClickedNext();
};
#endif // THEORY_WIDGET_H
@@ -0,0 +1,154 @@
#include "mainWindow.h"
inline void MainWindow::appendStatusbarText(const QString &value) {
m_timer->stop();
QString newData;
if(m_lblStatusbarText->text().size() + value.size() < 150) {
newData.append(m_lblStatusbarText->text());
}
newData.append(value + "; ");
m_lblStatusbarText->setText(newData);
m_timer->start();
}
inline void MainWindow::saveResult() {
QDate currentTime = QDate::currentDate();
short day = currentTime.day();
short month = currentTime.month();
short year = currentTime.year() % 1000;
constexpr short sizeDay = 5;
constexpr short sizeMonth = 4;
constexpr short sizeYear = 10;
constexpr short sizeCorrect = 8;
constexpr short sizeTotal = 8;
//constexpr short sizeSubject = 3;
//constexpr short sizeComplexity = 2;
constexpr short size = {
sizeDay + sizeMonth + sizeYear
+ sizeCorrect + sizeTotal
// + sizeSubject + sizeComplexity
};
std::bitset<size> newData;
for(const auto &value : std::initializer_list<std::pair<short, short>>{
{day, sizeDay}, {month, sizeMonth}, {year, sizeYear}
, {m_numerOfCorrect, sizeCorrect}, {m_numberOfAll, sizeTotal}
}) {
newData <<= value.second;
newData |= value.first;
}
QByteArray byteArray;
while(newData.any()) {
byteArray.push_front( static_cast<char>( newData.to_ullong()) );
newData >>= CHAR_BIT;
}
QFile file("save.dat");
file.open(QIODevice::Append);
file.write(byteArray);
file.close();
}
MainWindow::MainWindow(QWidget *pWidget)
: QMainWindow ( pWidget )
, m_timer( new QTimer(this) )
, m_lblStatusbarText(new QLabel)
{
setupUi(dynamic_cast<QMainWindow *>(this));
/*
* Size
*/
QSize screen = QApplication::desktop()->screenGeometry().size();
move(screen.width() / 30, screen.height() / 20);
/*
* Signals and slots
*/
connect( m_tabWidget, &QTabWidget::tabBarClicked, m_demonstrationTab, &DemonstrationWidget::slotTabSwitched);
connect( m_actionTheory, &QAction::triggered, this, [this]() {
m_stackedWidget->setCurrentIndex(0);
});
connect( m_actionPractice, &QAction::triggered, this, [this]() {
m_stackedWidget->setCurrentIndex(1);
});
connect( m_actionAbout, &QAction::triggered, this, [](){
QMessageBox::aboutQt(nullptr);
});
/*
* Theory
*/
m_theoryTab->unpack("./TheoryHTML/info.xml");
/*
* Testing page
*/
m_lblStatusbarText->setParent(m_statusbar);
QFont font = m_lblStatusbarText->font();
font.setPointSize(12);
m_lblStatusbarText->setFont(font);
m_statusbar->addWidget(m_lblStatusbarText);
m_timer->setParent(this);
m_timer->setInterval(1000 * 5);
m_timer->callOnTimeout(m_lblStatusbarText, &QLabel::clear);
connect( m_secondPage, &TestingWidget::signalStartOfTesting, this, [this]() {
m_numerOfCorrect = 0;
m_numberOfAll = 0;
appendStatusbarText("Testing has begun");
});
connect( m_secondPage, &TestingWidget::signalEndOfTesting, this, [this]() {
saveResult();
appendStatusbarText("Test ended, results saved");
});
connect( m_secondPage, &TestingWidget::signalReplyGiven, this, [this](bool result) {
++m_numberOfAll;
if(result) {
++m_numerOfCorrect;
appendStatusbarText("Correct answer");
}
else {
appendStatusbarText("False answer");
}
});
connect( m_secondPage, &TestingWidget::signalFileOpened, this, [this](bool flag) {
appendStatusbarText(flag ? "File successfully opened" : "File cannot be opened");
});
connect( m_secondPage, &TestingWidget::signalContentIsSet, this, [this](bool flag) {
appendStatusbarText(flag ? "Content of file successfully set" : "Failure to set content of file");
});
/*
* Manual window
*/
connect( m_actionManual, &QAction::triggered, this, [this]() {
auto *manualWindow = new QDialog(this, Qt::Dialog);
manualWindow->setModal(true);
auto *centralLayout = new QVBoxLayout;
auto *textBrowser = new TextBrowserWidget(":/ManualHTML/info.xml");
textBrowser->setFontPointSize(12);
centralLayout->addWidget(textBrowser);
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
connect(buttonBox, &QDialogButtonBox::clicked, manualWindow, &QDialog::close);
centralLayout->addWidget(buttonBox);
manualWindow->setLayout(centralLayout);
manualWindow->setMinimumSize({ 800, 600 });
manualWindow->setWindowFlags(manualWindow->windowFlags() & ~Qt::WindowContextHelpButtonHint);
manualWindow->setWindowTitle("Manual");
manualWindow->show();
});
}
@@ -0,0 +1,29 @@
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include "ui_mainWindow.h"
#include <bitset>
#include <QDateTime>
#include <QFile>
#include <QArrayData>
class MainWindow : public QMainWindow
, protected Ui::MainWindow
{
private:
QTimer *m_timer;
QLabel *m_lblStatusbarText;
size_t m_numerOfCorrect;
size_t m_numberOfAll;
private:
void appendStatusbarText(const QString &value);
void saveResult();
public:
MainWindow(QWidget *pWidget = nullptr);
};
#endif // MAIN_WINDOW_H
@@ -0,0 +1,972 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DemonstrationWidget</class>
<widget class="QWidget" name="DemonstrationWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>805</width>
<height>460</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QFrame" name="m_frmProgressBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>0</width>
<height>0</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<widget class="QLabel" name="m_lblProgressBar">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Progress of inserting elements:</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="m_progressBar">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
<underline>false</underline>
<strikeout>false</strikeout>
<kerning>true</kerning>
</font>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QScrollArea" name="m_rightScrollArea">
<property name="geometry">
<rect>
<x>501</x>
<y>0</y>
<width>250</width>
<height>250</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>234</width>
<height>1020</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="scrollAreaWidgetContentsLayout">
<item>
<widget class="QGroupBox" name="m_gbResolutionOfCollisions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Resolution of collisions</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QRadioButton" name="m_rbChains">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Chains</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbOpenAdressing">
<property name="text">
<string>Open addressing</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_gbFunction">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Function</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QRadioButton" name="m_rbEquivalent">
<property name="text">
<string>Equivalent</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbStandart">
<property name="text">
<string>Standart</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbFNV1a32bit">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FNV1a 32 bit</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_gbAlgorithm">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Algorithm</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QRadioButton" name="m_rbLinearProbing">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Linear probing</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbPseudorandomProbing">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Pseudorandom probing</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbQuadraticProbing">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Quadratic probing</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbDoubleHashing">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Double hashing</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_gbInputData">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Additional input data</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QFrame" name="m_frmFirstInputData">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<widget class="QLabel" name="lblFirstInputData">
<property name="text">
<string>Coefficient of the first family function:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>m_sbFirstInputData</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="m_sbFirstInputData">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100000000</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="stepType">
<enum>QAbstractSpinBox::DefaultStepType</enum>
</property>
<property name="value">
<number>0</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="m_frmSecondInputData">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<widget class="QLabel" name="m_lblSecondInputData">
<property name="text">
<string>Coefficient of the second family function:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>m_sbSecondInputData</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="m_sbSecondInputData">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100000000</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="stepType">
<enum>QAbstractSpinBox::DefaultStepType</enum>
</property>
<property name="value">
<number>1</number>
</property>
<property name="displayIntegerBase">
<number>16</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gbHashTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Hash table</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="lblNumberOfElements">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bucket quantity:</string>
</property>
<property name="buddy">
<cstring>m_sbBucketQuantity</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="m_sbBucketQuantity">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="m_pbReset">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="m_pbApply">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="m_pbStatistics">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Statistics</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_gbLoadTable">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Load table</string>
</property>
<layout class="QVBoxLayout" name="loadTableLayout">
<item>
<layout class="QFormLayout" name="makeItemsLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblFrom">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>From:</string>
</property>
<property name="buddy">
<cstring>m_leFrom</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblQuantity">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Quantity:</string>
</property>
<property name="buddy">
<cstring>m_sbQuantity</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="m_sbQuantity">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="m_leFrom">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="inputMethodHints">
<set>Qt::ImhNone</set>
</property>
<property name="maxLength">
<number>4</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="m_pbMakeItems">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Make items</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="insertLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_lblInsert">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Value:</string>
</property>
<property name="buddy">
<cstring>m_leInsert</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="m_leInsert">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxLength">
<number>4</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="m_pbInsert">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Insert</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="m_pbFindFree">
<property name="text">
<string>Find free</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_pbStop">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="m_pbFocus">
<property name="text">
<string>Focus</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="spacerOverOutputMessages">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frmOutputMessages">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="midLineWidth">
<number>0</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QLabel" name="lblOutputMessages">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Output messages:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_lblOutputMessages">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Consolas</family>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::DefaultContextMenu</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="inputMethodHints">
<set>Qt::ImhNone</set>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="midLineWidth">
<number>0</number>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>0</number>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QTableView" name="m_tableView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>250</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>200</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="gridStyle">
<enum>Qt::SolidLine</enum>
</property>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
</widget>
</widget>
<tabstops>
<tabstop>m_tableView</tabstop>
<tabstop>m_rightScrollArea</tabstop>
<tabstop>m_rbChains</tabstop>
<tabstop>m_rbOpenAdressing</tabstop>
<tabstop>m_rbEquivalent</tabstop>
<tabstop>m_rbStandart</tabstop>
<tabstop>m_rbFNV1a32bit</tabstop>
<tabstop>m_rbLinearProbing</tabstop>
<tabstop>m_rbPseudorandomProbing</tabstop>
<tabstop>m_rbQuadraticProbing</tabstop>
<tabstop>m_rbDoubleHashing</tabstop>
<tabstop>m_sbFirstInputData</tabstop>
<tabstop>m_sbSecondInputData</tabstop>
<tabstop>m_sbBucketQuantity</tabstop>
<tabstop>m_pbReset</tabstop>
<tabstop>m_pbApply</tabstop>
<tabstop>m_pbStatistics</tabstop>
<tabstop>m_leFrom</tabstop>
<tabstop>m_sbQuantity</tabstop>
<tabstop>m_pbMakeItems</tabstop>
<tabstop>m_leInsert</tabstop>
<tabstop>m_pbInsert</tabstop>
<tabstop>m_pbFindFree</tabstop>
<tabstop>m_pbStop</tabstop>
<tabstop>m_pbFocus</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>m_rbChains</sender>
<signal>clicked(bool)</signal>
<receiver>m_gbAlgorithm</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>861</x>
<y>45</y>
</hint>
<hint type="destinationlabel">
<x>858</x>
<y>225</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_rbOpenAdressing</sender>
<signal>clicked(bool)</signal>
<receiver>m_gbAlgorithm</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>887</x>
<y>78</y>
</hint>
<hint type="destinationlabel">
<x>892</x>
<y>219</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,261 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1093</width>
<height>548</height>
</rect>
</property>
<property name="windowTitle">
<string>Hash tables</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QStackedWidget" name="m_stackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="m_firstPage">
<layout class="QVBoxLayout" name="firstPageLayout">
<item>
<widget class="QTabWidget" name="m_tabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="TextBrowserWidget" name="m_theoryTab">
<attribute name="title">
<string>Theory</string>
</attribute>
</widget>
<widget class="DemonstrationWidget" name="m_demonstrationTab">
<attribute name="title">
<string>Demonstration</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="TestingWidget" name="m_secondPage">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="bottomLayout">
<item>
<spacer name="bottomSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_exitButton">
<property name="text">
<string>&amp;Exit</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="m_menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1093</width>
<height>20</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="m_actionManual"/>
<addaction name="separator"/>
<addaction name="m_actionAbout"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="m_actionTheory"/>
<addaction name="m_actionPractice"/>
</widget>
<addaction name="menuView"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="m_statusbar"/>
<action name="m_actionNewUserSession">
<property name="text">
<string>&amp;User session</string>
</property>
<property name="toolTip">
<string>User session</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="m_actionOpen">
<property name="text">
<string>&amp;Open...</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="m_actionSave">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Save</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="m_actionSaveAs">
<property name="text">
<string>Save &amp;As...</string>
</property>
</action>
<action name="m_actionOptions">
<property name="text">
<string>&amp;Options...</string>
</property>
</action>
<action name="m_actionManual">
<property name="text">
<string>&amp;Manual</string>
</property>
<property name="shortcut">
<string>Ctrl+H</string>
</property>
</action>
<action name="m_actionAbout">
<property name="text">
<string>About this &amp;program</string>
</property>
<property name="shortcut">
<string>Ctrl+A</string>
</property>
</action>
<action name="m_actionTheory">
<property name="text">
<string>&amp;Theory</string>
</property>
<property name="shortcut">
<string>Ctrl+T</string>
</property>
</action>
<action name="m_actionPractice">
<property name="text">
<string>&amp;Practice</string>
</property>
<property name="shortcut">
<string>Ctrl+P</string>
</property>
</action>
<action name="m_actionAllSessions">
<property name="text">
<string>&amp;General</string>
</property>
</action>
<action name="m_actionCurrentSessions">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Current</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>TestingWidget</class>
<extends>QWidget</extends>
<header>SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DemonstrationWidget</class>
<extends>QWidget</extends>
<header>SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TextBrowserWidget</class>
<extends>QWidget</extends>
<header>SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_tabWidget</tabstop>
<tabstop>m_exitButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>m_exitButton</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>1044</x>
<y>503</y>
</hint>
<hint type="destinationlabel">
<x>935</x>
<y>524</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,381 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TestingWidget</class>
<widget class="QWidget" name="TestingWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>716</width>
<height>545</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="leftLayout">
<item>
<widget class="QLabel" name="lblTestingWindow">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Testing window:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buddy">
<cstring>m_testingTextBrowser</cstring>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="m_testingTextBrowser">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="m_frmConfirm">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QStackedWidget" name="m_swInputData">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="m_wChoice">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="lblChoice">
<property name="text">
<string>Choose your answer:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex0">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex1">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex2">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex3">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex4">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex5">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex6">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex7">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_cbIndex8">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="m_wIntegerInput">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="lblInteger">
<property name="text">
<string>Enter an integer number:</string>
</property>
<property name="buddy">
<cstring>m_sbInteger</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="m_sbInteger"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="m_wDoubleInput">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="lblDouble">
<property name="text">
<string>Enter a fractional number:</string>
</property>
<property name="buddy">
<cstring>m_sbInteger</cstring>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="m_sbDouble"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="confirmLayout">
<item>
<widget class="QPushButton" name="m_pbConfirm">
<property name="text">
<string>Confirm answer</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="rightLayout">
<property name="spacing">
<number>7</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="m_gbTopics">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>Choosing a topic</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="m_rbAllTopics">
<property name="text">
<string>Everything</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbDiscreteMathematics">
<property name="text">
<string>Discrete mathematics</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbHashFunction">
<property name="text">
<string>Hash function</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbHashTable">
<property name="text">
<string>Hash table</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbAlgorithm">
<property name="text">
<string>Algorithm</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_gbDifficulty">
<property name="title">
<string>Choice of difficulty</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="m_rbAllDifficulties">
<property name="text">
<string>Everything</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbEasy">
<property name="text">
<string>Easy</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbMedium">
<property name="text">
<string>Medium</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="m_rbHard">
<property name="text">
<string>Hard</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_pbStart">
<property name="text">
<string>Start testing</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_pbStop">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Save &amp;&amp; Stop testing</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_testingTextBrowser</tabstop>
<tabstop>m_pbStart</tabstop>
<tabstop>m_pbStop</tabstop>
<tabstop>m_sbInteger</tabstop>
<tabstop>m_pbConfirm</tabstop>
<tabstop>m_rbAllTopics</tabstop>
<tabstop>m_rbDiscreteMathematics</tabstop>
<tabstop>m_rbHashFunction</tabstop>
<tabstop>m_rbHashTable</tabstop>
<tabstop>m_rbAlgorithm</tabstop>
<tabstop>m_rbAllDifficulties</tabstop>
<tabstop>m_rbEasy</tabstop>
<tabstop>m_rbMedium</tabstop>
<tabstop>m_rbHard</tabstop>
<tabstop>m_sbDouble</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TextBrowserWidget</class>
<widget class="QWidget" name="TextBrowserWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="textBrowserButtonsLayout">
<item>
<spacer name="leftSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_previous">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Previous</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_main">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Main</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_next">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Next</string>
</property>
</widget>
</item>
<item>
<spacer name="rightSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTextBrowser" name="m_textBrowser">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>16</pointsize>
</font>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+11
View File
@@ -0,0 +1,11 @@
#include "../SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
+17
View File
@@ -0,0 +1,17 @@
<RCC>
<qresource prefix="/">
<file>ManualHTML/info.xml</file>
<file>ManualHTML/Pages/demonstration.html</file>
<file>ManualHTML/Pages/main.html</file>
<file>ManualHTML/Pages/menubar.html</file>
<file>ManualHTML/Pages/theory.html</file>
<file>ManualHTML/Pages/theoryPage.html</file>
<file>ManualHTML/Pages/testingPage.html</file>
<file>ManualHTML/Images/demonstration.png</file>
<file>ManualHTML/Images/menubarFirst.png</file>
<file>ManualHTML/Images/menubarSecond.png</file>
<file>ManualHTML/Images/testingPage.png</file>
<file>ManualHTML/Images/theory.png</file>
<file>ManualHTML/Images/theoryPage.png</file>
</qresource>
</RCC>
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+139
View File
@@ -0,0 +1,139 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 8</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 8</b></i>
</p>
<hr />
<h1 style="text-align: center">Анализ хеш-таблиц и алгоритмов поиска</h1>
<h2 style="text-align: center">Общее описание [2, c. 285-318]</h2>
<p style="text-align: justify">
Хеш-таблица представляет собой эффективную структуру данных для реализации
словарей. Хотя на поиск элемента в хеш-таблице может в наихудшем случае
потребоваться столько же времени, сколько на поиск в связанном списке, а
именно - <i>&Theta;(n)</i>, на практике хеширование исключительно
эффективно. При вполне обоснованных допущениях среднее время поиска
элемента в хеш-таблице составляет <i>O(1)</i>.
</p>
<h2 style="text-align: center">
Таблица с прямой адресацией, как хеш-таблица
</h2>
<p style="text-align: justify">
Хеш-таблица обобщает обычный массив. Возможность прямой индексации
элементов обычного массива обеспечивает доступ к произвольной позиции в
массиве за время <i>O(1)</i>. Хеширование представляет собой исключительно
эффективную и практичную технологию: в среднем все базовые словарные
операции выполняются за время <i>O(1)</i><i>.</i>
</p>
<p style="text-align: justify">
Недостаток прямой адресации очевиден: если совокупность ключей
<i>U</i> велика, хранение таблицы <i>T</i> размером
<i>|U|</i> непрактично, а то и вовсе невозможно - в зависимости от
количества доступной памяти и размера совокупности ключей. Кроме того,
множество <i>K</i> реально сохранённых ключей может быть мало по сравнению
с совокупностью ключей <i>U</i>, а в этом случае память, выделенная для
таблицы <i>T</i>, в основном расходуется напрасно.
</p>
<p style="text-align: justify">
Когда множество <i>K</i> хранящихся в словаре ключей гораздо меньше
совокупности возможных ключей <i>U</i>, для хеш-таблицы требуется
существенно меньше места, чем для таблицы с прямой адресацией<sup>1</sup>.
Точнее говоря, требования к памяти могут быть снижены
до&nbsp;<i>&Theta;(/K/)</i>, при этом время поиска элемента в хеш-таблице
останется равным <i>O(1)</i>. Нужно только заметить, что это граница
времени поиска в среднем случае, в то время как в случае таблицы с прямой
адресацией эта граница справедлива для наихудшего случая.
</p>
<h2 style="text-align: center">Хеш-таблица с прямым связыванием</h2>
<p>
Время, необходимое для вставки в наихудшем случае, равно <i>O(1)</i>.
Процедура вставки выполняется очень быстро, в частности, потому, что
предполагается, что вставляемый элемент отсутствует в таблице. Время
работы поиска в наихудшем случае пропорционально длине списка. Удаление
элемента может быть выполнено за время <i>O(1)</i> при использовании
дважды связанных списков.
</p>
<p>
Пусть у нас есть хеш-таблица T с m ячейками, в которых хранятся n
элементов. В наихудшем случае хеширование с цепочками ведёт себя крайне
неприятно: все n ключей хешированы в одну и ту же ячейку, создав список
длиной n. Таким образом, время поиска в наихудшем случае равно&nbsp;<i
style="text-align: justify"
>&Theta;(n)</i
>
плюс время вычисления хеш-функции, что ничуть не лучше, чем в случае
использования связного списка для хранения всех n элементов. Понятно, что
использование хеш-таблиц в наихудшем случае совершенно бессмысленно.
</p>
<h3>Теорема 8.1<sup>2</sup></h3>
<p>
В хеш-таблице с разрешением коллизий методом цепочек время неудачного
поиска в среднем случае в предположении простого равномерного хеширования
составляет&nbsp;<i style="text-align: justify">&Theta;(1 + a).</i>
</p>
<h3>Теорема 8.2</h3>
<p>
В хеш-таблице с разрешением коллизий методом цепочек время успешного
поиска в среднем случае в предположении простого равномерного хеширования
в среднем равно&nbsp;<i style="text-align: justify">&Theta;(1 + a).</i>
</p>
<p style="text-align: justify">
Если количество ячеек в хеш-таблице как минимум пропорционально количеству
элементов, хранящихся в ней, то <i>n = O(m)</i> и, следовательно,
коэффициент заполнения равен <i>n/m = O(m)/m = O(1).</i>&nbsp;Таким
образом, поиск элемента в хеш-таблице в среднем требует постоянного
времени. Поскольку в худшем случае вставка элемента в хеш-таблицу занимает
O(1) времени (как и удаление элемента при использовании дважды связанных
списков), можно сделать вывод, что все словарные операции в хеш-таблице в
среднем выполняются за время O(1).
</p>
<h2 style="text-align: center">Хеш-таблица с открытой адресацией</h2>
<p style="text-align: justify">
Мы проанализируем математическое ожидание количества исследований для
хеширования с открытой адресацией в предположении равномерного хеширования
и начнём с анализа количества исследований в случае неудачного поиска.
</p>
<h3>Теорема 8.3</h3>
<p>
Математическое ожидание количества исследований при неудачном поиске в хеш
таблице с открытой адресацией и коэффициентом заполнения
<i>a = n/m &lt; 1</i> в предположении равномерного хеширования не
превышает <i>1/(1-a).</i>
</p>
<h3>Следствие 8.1</h3>
<p>
Вставка элемента в хеш-таблицу с открытой адресацией и коэффициентом
заполнения a в предположении равномерного хеширования требует в среднем не
более <i>1/(1-a)</i> исследований.
</p>
<h3>Теорема 8.4</h3>
<p>
Математическое ожидание количества исследований при удачном поиске в
хеш-таблице с открытой адресацией и коэффициентом заполнения <i>a &lt; 1</i>, в
предположении равномерного хеширования и равновероятного поиска любого из
ключей не превышает
</p>
<div style="text-align: center">
<img src="8.1.png" width="150" />
</div>
<p>&nbsp;</p>
<hr />
<p>
<sup>1</sup>В данном контексте автор, упоминая таблицу с прямой
адресацией, не применяет термин хеш, так как, предположительно, в примере
оригинальной книги не используется хеш-функция для операций поиска
элемента или все операции вставки элемента являются инъективными и не
нуждаются в решении проблем коллизий.
</p>
<p>
<sup>2</sup>Все доказательства теорем представлены в книге автора с целью
описания минимума методического материала
</p>
</body>
</html>
+149
View File
@@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 2</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 2</b></i>
</p>
<hr />
<h1 style="text-align: center">Дискретная математика</h1>
<h2 style="text-align: center">
Функция, как тип бинарных отношений [4, c. 96-100]
</h2>
<p>
Отношения эффективно применяются для описания связей между парами
элементов, выбранных из двух множеств <i>А</i> и <i>В</i>. Функции &mdash;
это частный случай бинарных отношений, на которые наложены дополнительные
ограничения.
</p>
<p>
Функцией из множества <i>А</i> в множество <i>В</i> называется бинарное
отношение, при котором <i>каждый</i> элемент множества <i>А</i> связан с
единственным элементом множества <i>В</i>. Другими словами, для каждого
<i>a&nbsp;&isin;&nbsp;A</i>&nbsp;существует ровно одна пара из отношения
вида <i>(а, b)</i>.
</p>
<p>
В графических терминах функция описывается таким графом, у которого из
каждой вершины, изображающей элементы множества <i>A</i>, выходит
<i>ровно одна</i> стрелка.
</p>
<p>
Например, на рис. 2.1 изображен граф, представляющий функцию из множества
<i>{а, b, с}</i> в <i>{1, 2}</i>, состоящую из пар <i>(а, 1),</i>
<i>(b, 1)</i> и <i>(с, 2)</i>.
<div style="text-align: center">
<img src="2.1.png" height="150" />
<p style="text-align: center">Рисунок 2.1 - функция из множества</p>
</div>
</p>
<p style="text-align: justify">
Пусть <i>f</i> - функция из множества <i>A</i> в множество <i>B</i>.
Поскольку для каждого <i>x&nbsp;&isin;&nbsp;A</i> существует единственным
образом определённый <i>y&isin;&nbsp;B</i>, такой, что
<i>(x, y) &isin; f</i>, мы будем писать: <i>y = f(x)</i>, и говорить, что
функция <i>f</i> <i>отображает </i>множество <i>A</i> в множество
<i>B</i>, а <i>f(x)</i> называть <i>образом x</i> при отображении
<i>f</i> или <i>значением</i> <i>f</i>, соответствующим аргументу
<i>x</i>.
</p>
<p style="text-align: justify">
Кроме того, можно написать <i>f : A&nbsp;&rarr;&nbsp;B</i>, чтобы
подчеркнуть, что функция <i>f</i> переводит элементы из <i>A</i> в
элементы из <i>B</i>. Множество <i>A </i>принято называть
<i>областью определения</i>, а <i>B</i> -
<i>областью значений</i> функции<sup>1</sup> <i>f</i>.
</p>
<p style="text-align: justify">
Для уточнения подмножества элементов, в которые переводятся элементы из
<i>A</i> функцией <i>f</i>, вводят понятие &quot;образ&quot; или
&quot;множество значений функции&quot;. А именно,
<i>множеством значений</i> функции <i>f</i> называется подмножество в
<i>B</i>, состоящее из образов всех
элементов&nbsp;<i>x&nbsp;&isin;&nbsp;A</i>. Оно обозначается символом
<i>f(A)</i> и формально определяется так:
</p>
<p style="text-align: center">
<i
>f(A) = {f(x) : x&nbsp;<i style="text-align: justify">&isin;&nbsp;</i
>A}</i
>
</p>
<p style="text-align: center">&nbsp;</p>
<h2 style="text-align: center">Свойства функций</h2>
<p style="text-align: justify">
Пусть <i>f : A&nbsp;&rarr;&nbsp;B</i> - функция. Мы будем называть её
<i>инъективной </i>или <i>инъекцией</i>, или <i>взаимно однозначной</i>,
если
</p>
<p style="text-align: center">
<i
>f(a<sub>1</sub>) = f(a<sub>2</sub>)&nbsp;&rArr;&nbsp;a<sub>1 </sub
>=<sub>&nbsp;</sub>a<sub>2</sub></i
>
</p>
<p style="text-align: justify">
для всех&nbsp;<i>a<sub>1</sub>,&nbsp;a<sub>2&nbsp;</sub>&isin;&nbsp;A</i>.
</p>
<p style="text-align: justify">
Это определение логически эквивалентно тому, что
</p>
<p style="text-align: center">
<i
>a<sub>1&nbsp;</sub>&ne;&nbsp;a<sub>2</sub>&nbsp;&rArr;&nbsp;f(a<sub>1</sub>)&nbsp;&ne;&nbsp;f(a<sub>2</sub>),</i
>
</p>
<p style="text-align: justify">
т.е. у инъективной функции нет повторяющихся значений. Иными словами,
разные входные данные дают различные выходные данные.
</p>
<p style="text-align: justify">
Будем называть функцию <i>f</i> <i>сюръективной </i>или <i>сюръекцией</i>,
или <i>функцией &quot;на&quot;</i>, если множество её значений совпадает с
областью значений. Это означает, что для каждого
<i>b&nbsp;&isin;&nbsp;B</i> найдётся такой <i>a&nbsp;&isin;&nbsp;A</i>,
что <i>b = f(a)</i>. Таким образом, каждый элемент области значений
является образом какого-то элемента из области определения <i>f</i> .
</p>
<p style="text-align: justify">
Мы называем <i>f</i> <i>биективной </i>функцией или просто
<i>биекцией</i>, если она как инъективна, так и сюръективна.
</p>
<p style="text-align: justify">&nbsp;</p>
<p>На рисунке 2.2 представлены различные виды функций.</p>
<div style="text-align: center">
<img src="2.2.png" height="350" />
<p style="text-align: center">Рисунок 2.2 - различные виды функций</p>
</div>
<p>Описание:</p>
<ul>
<li>
В случае (a) функция не инъективна, поскольку значение 1 соответствует
как a, так и b. Она не является и сюръективной, ввиду того, что в
элемент 2 ничего не переходит.
</li>
<li>
В случае (б) функция инъективна, так как не имеет повторяющихся
значений. Она же и сюръективна, поскольку множество ее значений
совпадает со всей областью значений.
</li>
<li>
Значение 1 эта функция в случае (в) принимает как на а, так и на Ь.
Следовательно, она не инъективна. Однако данная функция сюръективна,
поскольку в ее множество значений входят все элементы области значений.
</li>
<li>Последняя функция в случае (г) инъективна, но не сюръективна.</li>
<li>Только в случае (б) мы имеем биекцию.</li>
</ul>
<hr />
<p>
<sup>1</sup>Довольно часто говорят, что функция f определена или задана на
множестве A со значениями в множестве B. - Прим. перев.
</p>
</body>
</html>
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 6</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 6</b></i>
</p>
<hr />
<h1 style="text-align: center">Решение проблем коллизий</h1>
<h2 style="text-align: center">Метод цепочек или прямое связывание [5, c. 170-171]</h2>
<p style="text-align: justify">
В хеш таблице с прямым связыванием (рис 6.1) значения ключей (бункеры)
хранятся в специальных наборах записей, называемых <i>блоками.</i> Каждый
из них является вершиной связного списка, в котором находятся привязанные
к блоку элементы.
</p>
<div style="text-align: center">
<img src="6.1.png" height="350" />
<p style="text-align: center">Рисунок 6.1 - хеш-таблица с прямым связыванием</p>
</div>
<p style="text-align: justify">
Поиск элементов в хеш-таблице пройдёт быстрее, если связанные списки будут
содержать ключи в отсортированном порядке. В этом случае алгоритм сделает
вывод, что ключа нет, если дойдёт до значения больше ключевого и не станет
просматривать список до конца. Теоретически время его работы составит
<i>O(N/B)</i>, но на практике оно будет немного меньше.
</p>
<p style="text-align: justify">
Чтобы найти нужный элемент, программе необходимо хешировать ключ и
определить, в каком из блоков он может содержаться, а затем двигаться по
связному списку до тех пор, пока не будет достигнут его конец или не
обнаружится искомое. Если вы доберётесь до конца списка, значит,
запрашиваемого элемента в хеш-таблице нет. Как и в случае с добавлением
элемента, предстоит выполнить <i>O(N/B)</i> шагов.
</p>
<p style="text-align: justify">
Хеш-таблица с прямым связыванием может расширяться и сжиматься<sup>1</sup>
по мере необходимости, поэтому вам не нужно специально изменять её размер.
Однако если связные списки станут слишком длинными, поиск и удаление
элементов займут много времени. В этом случае вам понадобится увеличить
таблицу, чтобы создать больше блоков. Поскольку при рехешировании таблицы
не надо проводить поиск дубликатов до конца связного списка в каждом
блоке, полностью справиться с операцией можно за время <i>O(N)</i>.
</p>
<hr />
<p>
<sup>1</sup>Удаление элементов в данном методическом материале
рассматриваться не будет
</p>
</body>
</html>
+52
View File
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 3</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 3</b></i>
</p>
<hr />
<h1 style="text-align: center">Дискретная математика</h1>
<h2 style="text-align: center">Принцип Дирихле [4, c. 105]</h2>
<p>
Пусть <i>f : A&nbsp;<i style="text-align: justify">&rarr;&nbsp;</i>B</i> -
функция, причём как <i>A</i>, так и <i>B</i> - конечные множества.
Предположим, что <i>A</i> состоит из <i>n</i> элементов:
<i>a<sub>1</sub>, a<sub>2</sub>,..., a<sub>n</sub></i
>. Принцип Дирихле гласит, что если <i>|A| &gt; |B|</i>, то по крайней
мере одно значение <i>f</i> встретится более одного раза<sup>1</sup>.
Проще говоря, найдётся пара элементов
<i
>a<sub>i&nbsp;</sub><i style="text-align: center">&ne;</i
><sub>&nbsp;</sub>a<sub>j</sub></i
>, для которых <i>f(a<sub>i</sub>) = f(a<sub>j</sub>)</i>.
</p>
<p>
Чтобы убедиться в истинности принципа, предположим, что для любой пары
разных индексов
<i>i&nbsp;<i style="text-align: center">&ne;&nbsp;</i>j</i> мы имеем:
<i>f(a<sub>i</sub>)&nbsp;</i><i style="text-align: center">&ne;&nbsp;</i
><i>f(a<sub>j</sub>)</i>. Тогда множество <i>B</i> содержит по крайней
мере <i>n</i> различных элементов:
<i>f(a<sub>1</sub>), f(a<sub>2</sub>),..., f(a<sub>n</sub>)</i>. И уж во
всяком случае, <i>|B|&nbsp;&ge;&nbsp;n</i>, что противоречит
предположению: <i>n = |A| &gt; |B|</i>. Следовательно, есть хотя бы два
разных элемента
<i
>a<sub>i</sub>, a<sub>j&nbsp;</sub
><i style="text-align: justify">&isin;&nbsp;</i>A</i
>, для которых <i>f(a<sub>i</sub>) = f(a<sub>j</sub>)</i>.
</p>
<hr />
<p>
<sup>1</sup>Допуская некоторую вольность, принцип Дирихле можно
переформулировать в легко запоминающейся форме: нельзя рассадить 10 зайцев
в 9 клеток так, чтобы в каждой клетке сидел один заяц - Прим. перев.
</p>
</body>
</html>
+102
View File
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 4</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 4</b></i>
</p>
<hr />
<h1 style="text-align: center">Хеш-фукнция</h1>
<h2 style="text-align: center">Свойства хеш-функции</h2>
<p style="text-align: justify">
Хеш-функция&nbsp;(англ.&nbsp;hash function&nbsp;от&nbsp;hash&nbsp;&mdash;
&laquo;превращать в фарш&raquo;), или&nbsp;функция свёртки&nbsp;&mdash;
функция, осуществляющая преобразование&nbsp;массива&nbsp;входных данных
произвольной длины в выходную&nbsp;битовую&nbsp;строку установленной
длины, выполняемое&nbsp;определённым алгоритмом. Преобразование,
производимое хеш-функцией, называется&nbsp;хешированием. Исходные данные
называются входным массивом, &laquo;ключом&raquo; или
&laquo;сообщением&raquo;. Результат преобразования называется
&laquo;хешем&raquo;, &laquo;хеш-кодом&raquo;, &laquo;хеш-суммой&raquo;,
&laquo;сводкой&nbsp;сообщения&raquo;.[<a
href="https://ru.wikipedia.org/wiki/Хеш-таблица"
>7</a
>]
</p>
<p style="text-align: justify">Свойства хеш-функции:</p>
<ul>
<li style="text-align: justify">Должна обладать свойствами функции.</li>
<li style="text-align: justify">
Не должна обязательно являться инъективной или сюръективной.
</li>
</ul>
<p style="text-align: justify">Определения :</p>
<ul>
<li style="text-align: justify">
Если известна область определения и можно задать отображение в область
значений, мощность которого будет больше или эквивалентна мощности
области определения, при котором хеш-функция будет являться
<i>инъективной</i>, то такая хеш-функция будет являться<i
>&nbsp;идеальной хеш-функцией</i
>.
</li>
<li style="text-align: justify">
Если область определения неизвестна&nbsp;и можно задать отображение в
область значений, мощность которого будет больше или эквивалентна
мощности области определения, при котором хеш-функция будет
являться&nbsp;<i>инъективной</i>, то такая хеш-функция будет являться<i
>&nbsp;динамической идеальной хеш-функцией</i
>.
</li>
<li style="text-align: justify">
Если известна&nbsp;область определения и можно задать отображение в
область значений, мощность которого будет эквивалентна&nbsp;мощности
области определения, при котором хеш-функция будет
являться&nbsp;<i>биективной</i>, то такая хеш-функция будет являться
<i>минимальной идеальной хеш-функцией</i>.
</li>
<li style="text-align: justify">
Хеш-функция является <i>k-совершенной хеш-функцией</i>,
если&nbsp;область определения неизвестна и можно задать отображение в
область значений, любой элемент которого будет обладать не более чем k
отношениями.
</li>
</ul>
<div style="text-align: justify">
Существует несколько терминов, связанных с хеш-функцией:
</div>
<dl>
<dt style="text-align: justify"><i>Хеш</i></dt>
<dd style="text-align: justify">
элемент области значений, соотнесённый с заранее известным элементом из
области определения.
</dd>
<dt style="text-align: justify"><i>Хеширование</i></dt>
<dd style="text-align: justify">это процесс получения хеша.</dd>
<dt style="text-align: justify"><i>Коллизия</i></dt>
<dd style="text-align: justify">
ситуация, при которой нарушается условие инъективности хеш-функции.
</dd>
</dl>
<p style="text-align: justify">
Производительность хеширования в среднем случае зависит от того, насколько
хорошо хеш-функция приближена к биективной k-совершенной хеш-функции, где
разность количества отношейний любых двух элементов области значений
стремиться к нулю. Другими словами, каждый элемент области значений
обладает минимально возможным количеством отношений. Данное хеширование
автор книги [2, с. 291] Томас Кормен называет
<i>простым равномерным хешированием</i>.
</p>
<div style="text-align: justify">
Существует множество разнообразных хеш-функций, алгоритмы которых
применяются в различных ситуациях, например, когда требуется скорость
вычисления хеш-значения, но с повышенным шансом появления коллизии или
наоборот.
</div>
</body>
</html>
+120
View File
@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 5</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 5</b></i>
</p>
<hr />
<h1 style="text-align: center">Хеш-таблица</h1>
<h2 style="text-align: center">Свойства хеш-таблицы</h2>
<p style="text-align: justify">
Хеш-таблицы являются одним из способов хранения данных при помощи
ассоциативного массива [<a
href="https://ru.wikipedia.org/wiki/Ассоциативный_массив"
target="_blank"
>12</a
>].
</p>
<p style="text-align: justify">
Хеш-таблицы решают несколько главных проблем при оперировании с данными:
</p>
<ul>
<li style="text-align: justify">
<i
>Создание отношения (связи) между ключом и абсолютно любым
значением.</i
>
</li>
<li style="text-align: justify"><i>Решение проблем коллизий.</i></li>
</ul>
<p style="text-align: justify">
Для большего понимания материала требуется ознакомиться с новыми терминами
хеш-таблицы:
</p>
<dl>
<dt><i>Ключ или сообщение</i></dt>
<dd>использующийся хеш-таблицей произвольный элемент из области определения хеш-функции.</dd>
<dt><i>Бункер или корзина</i></dt>
<dd>произвольный элемент, который хранит данные хеш-таблицы.</dd>
<dt><i>Коэффициент заполнения</i></dt>
<dd>
отношение количества заполненных бункеров на количество возможных ключей.
</dd>
</dl>
<p style="text-align: justify">
Исходя из определений, бункер - это условная единица хранимой информации в
хеш-таблице (ассоциативном массиве данных).
</p>
<p>
<i
><span style="text-align: justify"
>Решение первой проблемы.&nbsp;</span
></i
>Хеш-функции в хеш-таблице, нужны по причине получения хеша в процессе
хеширования ключа, однако хеш - значение абстрактное, так как невозможно
создать такой алгоритм, который бы выдавал хеш, как набор данных,
используемый в процессе работы программы или это очень сложно.<br />
Для большего понимания нужно вспомнить пример о&nbsp;<span
style="text-align: justify"
>&quot;продавце в маленьком магазинчике&quot;, где &quot;помощница&quot;
абстрагирует понятие хеш-функции, которая выдавала для каждого товара
конкретную цену, что возможно, но трудозатратно.</span
><br />
<span style="text-align: justify"
>Для этого требуется хеш-функция, где хеш является универсальным
идентификатором конкретного бункера, в котором располагается необходимый
пользователю набор данных.</span
>
</p>
<p>
Томас Кормен говорит в книге [2, c.288], что цель хеш-функции состоит в
том, чтобы уменьшить рабочий диапазон индексов массива - размер массива
может быть равен соотносительно намного меньшему значению, чем мощность
множества всех существующих значений ключей, которые могут потенциально
использоваться в процессе работы программы.
</p>
<p style="text-align: justify">
<span style="text-align: justify"
>Из этого можно выделить несколько особенностей хеш-таблиц:</span
>
</p>
<ul>
<li style="text-align: justify">
Каждый бункер имеет&nbsp;в качестве уникального&nbsp;идентификатора
хеш-значение
</li>
<li style="text-align: justify">
Каждый ключ гарантированно имеет связь только с одним бункером.
</li>
<li style="text-align: justify">
Количество бункеров относительно количества ключей сильно ограниченно.
</li>
<li style="text-align: justify">
От хеш-функции зависит коэффициент заполнения.
</li>
<li style="text-align: justify">
По принципу Дирихле коллизия неизбежна в ситуации, когда количество ключей больше, чем количество бункеров.
</li>
</ul>
<p style="text-align: justify">
<i>Решение второй проблемы</i>. Хеш-таблицы используют в качестве
алгоритма поиска элемента контейнера (бункера) хеш-функцию, которая по
принципу Дирихле гарантированно создаст коллизии в ситуации, когда
количество ключей больше, чем количество бункеров, а обычно так бывает
всегда.
</p>
<p style="text-align: justify">
Хеш-таблицы решают данную проблему двумя способами:&nbsp;
</p>
<ul>
<li style="text-align: justify">Метод цепочек или прямым связыванием.</li>
<li style="text-align: justify">Открытой адресацией.</li>
</ul>
</body>
</html>
+116
View File
@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 1</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 1</b></i>
</p>
<hr />
<h1 style="text-align: center">Введение</h1>
<h2 style="text-align: center">Гардероб [3, с. 393-394]</h2>
<p style="text-align: justify">
Когда вы сдаете в гардероб пальто или сумку, вам выдают номерок. Когда же
вы собираетесь покинуть помещение, вы отдаете номерок, и вам возвращают
ваше пальто или сумку.
</p>
<p style="text-align: justify">
Если вдуматься, какую задачку решает данный процесс, можно увидеть, что
это задача о поиске и нахождении объекта. Ваше пальто &mdash; это объект,
который вы передаете гардеробщику; пальто сначала привязывают к
определенному номерку, а затем возвращают вам. Метод работает за счет
того, что в гардеробе находятся ряды пронумерованных вешалок для одежды и
пронумерованные отделения для сумок. Вашему номерку соответствует
определенная вешалка или определенное отделение. Гардеробщик же отвечает
за то, чтобы разместить ваш объект в нужном месте и чтобы забрать его с
помощью отданного вами номерка.
</p>
<p style="text-align: justify">
Когда речь идет о поиске, люди чаще всего представляют себе, что нужно
перебирать вещи до тех пор, пока не найдется нужная; процесс становится
проще, если вещи отсортированы так, что мы можем искать среди них более
слаженно. Гардероб же показывает, что есть и другой способ: присвоить вещи
адрес, где она будет располагаться, и затем сразу достать ее из указанного
места. В гардеробе адрес указан на номерках, и гардеробщик на самом деле
ищет не ваши вещи: он смотрит на номерок, на адрес и идет к указанной
вешалке или отделению с вашими вещами.
</p>
<p style="text-align: justify">
Весь метод в целом можно назвать определением местонахождения
<i>без поиска</i>: мы не ищем объект, а получаем адрес места, где он будет
храниться. Соотносим объект с адресом, а затем, когда хотим найти объект,
мы идем прямиком к нужному месту.
</p>
<p style="text-align: justify">
Теперь рассмотрим данный метод с точки зрения компьютерного мира, где наши
объекты представлены в виде записей, содержащих атрибуты. Мы хотим уметь
переходить напрямую от&nbsp;записи к адресу, по которому она размещена;
адресом будет число, соответствующее области в компьютерной памяти.
Главная загвоздка в такой задачке &mdash; то, как соотнести адрес с
элементом. Нам нужен быстрый и надежный способ, и мы не можем положиться
на какого-либо посредника. Когда мы ищем запись, мы ищем ее по одному или
большему числу атрибутов, которые формируют ключ записи, поэтому нам нужен
метод получения адреса из ключа записи. Так как адрес &mdash; это число,
нам нужен способ, который перенесет нас от ключей к числам. Иными словами,
мы нуждаемся в функции, скажем, <i>f(K)</i>, которая возьмет ключ K записи
R и вернет значение <i>a = f(K)</i>. Значение a представляет собой адрес,
где будет храниться запись, мы идем по нему и оставляем там нашу запись.
Каждый раз, когда нам требуется достать нашу запись с помощью ключа, мы
снова прибегаем к функции <i>f(K)</i>, которая вернет то же адресное
значение a, откуда мы и заберем нашу запись. Функция должна быть быстрой и
достаточно скоро находить нужный адрес: как минимум, не дольше, чем поиск
по записям до тех пор, пока не найдется та, которую мы ищем. В противном
случае толку от такой функции никакого. Если же мы в самом деле
обзаведемся такой функцией, то разрешим нашу задачку с местоположением
новым способом: не мы будем искать элемент, а сам элемент расскажет нам,
где его найти: расскажет с помощью нашей функции.
</p>
<h2 style="text-align: center">Продавец</h2>
<p style="text-align: justify">
Так же стоит привести введение в теоретический материал, описанное автором
книги [1, c. 100-101], где описывается пример с &quot;продавцом в
маленьком магазинчике&quot;.
</p>
<p style="text-align: justify">
В ситуации, когда клиент покупает
у&nbsp;продавца&nbsp;товар&nbsp;необходимо определить ценность предмета.
Изначально стоит отметить, что цены в магазинах на один и тот же товар
всегда одинаковый в один момент времени, поэтому необходимо хранить
информацию о ценах, например, в книге, однако данный метод оперирования
информацией будет весьма утомителен и ужасно&nbsp;неэффективен. Для
решения этой проблемы&nbsp;продавец&nbsp;нанимает помощницу, которая
безошибочно определяет цену на товар, если посмотрит на него или узнает
его название.
</p>
<p style="text-align: justify">
Автор абстрактно описывает проблему с упорядоченным контейнером данных,
где может потребоваться простой поиск, алгоритм которого обладает линейной
сложностью. В данном примере контейнер является хранилищем элементов,
каждый из которых может повторяться, но обязан иметь только один
уникальный идентификатор. Можно с уверенностью выделить две проблемы, от
которых можно избавиться в <i>идеальных </i>условиях &mdash; затраты на
хранение элементов и поиск каждого из них при помощи уникального
идентификатора. В приоритете необходимо выполнять успешный поиск элемента,
алгоритм которого будет выполняться за константное время.
</p>
<p style="text-align: justify">
Решением является использование функции [4, c. 96] из множества <i>A</i> в
множество <i>B.</i>&nbsp;Данная функция описывает бинарное отношение, при
котором <i>каждый</i>&nbsp;элемент множества <i>А</i> связан с
единственным элементом множества <i>B</i>.&nbsp; Данная функция в
программировании имеет название хеш-функция. Избавиться от необходимости в
хранении множеств элементов, чтобы сохранялась возможность определять
новые бинарные отношения, не изменяя другие очень сложно, однако это
возможно. Обычно, когда известны все элементы множества <i>А</i> и все
элементы множества <i>B</i>, реализуют функцию, при которой любой элемент
множества <i>А</i> имеет одно отношение с любым элементом из множества
<i>B</i>. Например, данную функцию можно применить в примере с продавцом и
помощницей, если каталог товаров не изменяется, но цены на разные товары
могут совпадать.
</p>
</body>
</html>
+170
View File
@@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Теоретический материал</title>
</head>
<body>
<h1 style="text-align: center">Теоретический материал</h1>
<h2 style="text-align: center">
Необходимый минимум теории по теме<br />
"Алгоритм вставки в хеш-таблицу"
</h2>
<h3>Описание страницы:</h3>
<p>
Главная страница, предоставляющая пользователю быстрый и удобный поиск
нужного разбитого по темам материала.<br />
Каждый элемент списка оглавления является гиперссылкой при нажатии на
которую можно мгновенно перейти к необходимому разделу информации.<br />
Предоставленный пользователю теоретический материал был взят из списка
использованной литературы в конце данной страницы.
</p>
<p>Оглавление:</p>
<ol>
<li>
<a href="introduction.html">Введение.</a>
</li>
<li>Дискретная математика:
<ul>
<li>
<a href="binaryRelationship.html">Функция.</a>
</li>
<li>
<a href="dirichletPrinciple.html">Принцип Дирихле.</a>
</li>
</ul>
</li>
<li>
<a href="hashFunction.html">Хеш-функция.</a>
</li>
<li>
<a href="hashTable.html">Хеш-таблица.</a>
</li>
<li>Решение проблем коллизий:
<ul>
<li>
<a href="chainMethod.html">Метод цепочек или прямое связывание.</a>
</li>
<li><a href = "openAddressing.html">Открытая и прямая адресации.</a></li>
</ul>
</li>
<li><a href = "analysis.html">Анализ хеш-таблиц и алгоритмов поиска.</a></li>
</ol>
<h3 style="text-align: center">Список использованной литературы</h3>
<ol>
<li>
<em
>Бхаргава, А. Грокаем алгоритмы. Иллюстрированное пособие для
программистов и любопытствующих&nbsp;/ Адитья Бхаргава. — СПб. :
Питер, 2017. - 288 с. : ил. — (Библиотека программиста).</em
>
</li>
<li>
<em
>Кормен, Т. Х. Алгоритмы: построение и анализ, 3-е изд / Томас Кормен ; пер. с англ. — Москва :
ООО "И. Д. Вильямс", 2013. — 1328 с. : ил. — Парал. тит. англ.</em
>
</li>
<li>
<em
>Луридас, П. Алгоритмы для начинающих : теория и практика для
разработчика / Панос Луридас ; пер. с англ. Е.М. Егоровой. — Москва :
Эксмо, 2020. — 608 с. — (Мировой компьютерный бестселлер).</em
>
</li>
<li>
<em
>Хаггарти, Р. Дискретная математика для программистов, 2-е издание, исправленное / Род
Стивенс. — Москва : ТЕХНОСФЕРА, 2019. — 400 c.</em
>
</li>
<li>
<em
>Стивенс, Р. Алгоритмы. Теория и практическое применение / Род
Стивенс. — Москва : Издательство "Э", 2016. — 544 c. — (Мировой
компьютерный бестселлер).</em
>
</li>
<li>
<em
>Хеш-таблица [Электронный ресурс]: Википедия. Свободная энциклопедия.
— URL:&nbsp;<a
href="https://ru.wikipedia.org/wiki/Хеш-таблица"
target="_blank"
>https://ru.wikipedia.org/wiki/Хеш-таблица</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-функция [Электронный ресурс]: Википедия. Свободная энциклопедия.
— URL:&nbsp;<a
href="https://ru.wikipedia.org/wiki/Хеш-функция"
target="_blank"
>https://ru.wikipedia.org/wiki/Хеш-функция</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-функция, что это такое? [Электронный ресурс]: Хабр. Сообщество
IT-специалистов. — URL:&nbsp;<a
href="https://habr.com/ru/post/534596/"
target="_blank"
>https://habr.com/ru/post/534596/</a
>
(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-таблицы [Электронный ресурс]: Хабр. Сообщество IT-специалистов. —
URL:&nbsp;<a href="https://habr.com/ru/post/509220/" target="_blank"
>https://habr.com/ru/post/509220/</a
>
(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Хеш-таблицы [Электронный ресурс]: CodeChick. Задачи по
программированию с проверкой. — URL:&nbsp;<a
href="https://codechick.io/tutorials/dsa/dsa-hash-table"
target="_blank"
>https://codechick.io/tutorials/dsa/dsa-hash-table</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>FowlerNollVo hash function [Электронный ресурс]: Википедия.
Свободная энциклопедия. — URL:&nbsp;<a
href="https://en.wikipedia.org/wiki/FowlerNollVo_hash_function"
target="_blank"
>https://en.wikipedia.org/wiki/FowlerNollVo_hash_function</a
>&nbsp;(дата обращения: 03.11.2021).</em
>
</li>
<li>
<em
>Ассоциативный массив [Электронный ресурс]: Википедия.
Свободная энциклопедия. — URL:&nbsp;<a
href="https://ru.wikipedia.org/wiki/Ассоциативный_массив"
target="_blank"
>https://ru.wikipedia.org/wiki/Ассоциативный_массив</a
>&nbsp;(дата обращения: 06.11.2021).</em
>
</li>
</ol>
</body>
</html>
+274
View File
@@ -0,0 +1,274 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Страница 7</title>
</head>
<body>
<p style="text-align: center">
<i><b>Страница 7</b></i>
</p>
<hr />
<h1 style="text-align: center">Решение проблем коллизий</h1>
<h2 style="text-align: center">
Открытая и прямая адресации [5, c. 170-179]
</h2>
<p>Оглавление:</p>
<ul>
<li><a href="#description">Описание.</a></li>
<li><a href="#linear">Линейное пробирование.</a></li>
<li><a href="#quadratic">Квадратичное пробирование.</a></li>
<li><a href="#pseudorandom">Псевдослучайное пробирование.</a></li>
<li><a href="#double">Двойное хеширование.</a></li>
</ul>
<div>
<h3 style="text-align: center"><a name="description">Описание</a></h3>
<p style="text-align: justify">
Безусловно, прямое связывание имеет свои преимущества. Основное из них
заключается в том, что общее количество значений не зависит от
количества блоков. Однако есть у таких хеш-таблиц и некоторые
недостатки. Например, если элементов в блоках накопится слишком много,
поиск нужного займет продолжительное время. Чтобы сократить временные
затраты, число блоков можно увеличить, но тогда вы рискуете получить ряд
пустых, которые потребуют места в памяти и не будут использоваться
таблицей.
</p>
<p style="text-align: justify">
Еще один способ реализации хеш-таблиц &mdash; <i>открытая адресация</i>.
В этом случае значения хранятся в массиве, а функция хеширования
представляет собой некоторые расчеты.
</p>
<p style="text-align: justify">
Хеш-таблица с <i>прямой адресацией</i> отличается от хеш-таблицы с
открытой адресацией тем, что в первом случае гарантировано должна
использоваться идеальная хеш-функция. Это обусловлено тем, что в данной
хеш-таблице должны отсутствовать коллизии, соответственно, как и методы
их разрешения. Стоит отметить, что под данное описание подходит
<i>идеальное хеширование</i> хеш-таблицы<sup>1</sup>.
</p>
<p style="text-align: justify">
В разных видах открытой адресации используются различные функции
хеширования. Неодинакова и политика разрешения коллизий, но в общем
случае она выглядит так: для каждого значения в массиве подбирается
несколько ячеек, и если первая уже занята, алгоритм пробует использовать
вторую, затем третью и так до тех пор, пока не найдет свободную или не
придет к выводу, что таковой нет.
</p>
<p style="text-align: justify">
Серия ячеек, которую алгоритм подбирает для значения, называется пробной
последовательностью. По ее средней длине хорошо оценивать наполненность
хештаблицы. В идеале пробная последовательность должна равняться 1 или
2, большие цифры говорят о полной таблице.
</p>
<p style="text-align: justify">
Иногда политика разрешения коллизий такова, что для элемента может не
найтись свободной ячейки, даже когда она есть. Если пробная
последовательность повторяет саму себя перед тем, как проверить
очередную запись, некоторые записи могут остаться неиспользованными.
</p>
<p style="text-align: justify">
Чтобы найти элемент в хеш-таблице, алгоритм следует за пробной
последовательностью, пока не произойдет одно из трех событий.
</p>
<ol>
<li style="text-align: justify">
Если пробная последовательность сумела отыскать элемент, задача
выполнена.
</li>
<li style="text-align: justify">
Если пробная последовательность находит пустую запись в массиве,
элемента нет.
</li>
<li style="text-align: justify">
Пробная последовательность проверяет <i>M</i> записей (по размеру
массива) &mdash; и алгоритм приходит к выводу, что значение
отсутствует. Последовательность может перебрать не все элементы, но
если пройдет по всем, вы будете знать, что они точно пересмотрены или
что целевой элемент не найден. Она также может проверить в цикле одну
и ту же позицию несколько раз. В любом случае значение не должно
присутствовать, поскольку иначе оно бы добавлялось к массиву с
использованием той же пробной последовательности.
</li>
</ol>
<p style="text-align: justify">
При разумном заполнении хеш-таблицы открытая адресация работает очень
быстро. Если длина пробной последовательности равна 1 или 2, добавление
и нахождение элементов выполняются за время <i>O(1)</i>. Но если массив
из N элементов существенно переполнен, производительность снижается. В
наихудшем случае алгоритм придет к выводу, что элемента в массиве нет,
за время <i>O(N)</i>. Поиск присутствующих элементов также будет
выполняться крайне медленно.
</p>
<p style="text-align: justify">
Вы можете увеличить размер массива, чтобы уменьшить коэффициент
наполненности хеш-таблицы. Для этого создайте новый массив и рехешируйте
элементы в нем. Для каждого из них операция займет <i>O(1)</i> времени,
а общая производительность алгоритма составит <i>O(N)</i>.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="linear">Линейное пробирование</a>
</h3>
<p style="text-align: justify">
В линейном пробировании политика разрешения коллизий добавляет к каждой
ячейке постоянное число (чаще всего 1), называемое шагом по индексу,
которое генерирует пробную последовательность. При каждом очередном
добавлении берется размер массива по модулю, стало быть, при
необходимости последовательность возвращается к началу массива.
</p>
<p style="text-align: justify">
Предположим, в хеш-таблице 100 элементов, а правило хеширования звучит
следующим образом: N связано с ячейкой N mod 100. Тогда пробная
последовательность для значения 2197 проверяет ячейки 97, 98, 99, 0, 1,
2 и т. д.
</p>
<p style="text-align: justify">
На рисунке 7.1 представлен массив из 10 записей, который уже содержит
несколько значений. Чтобы добавить в него новое значение 71, используя
линейную пробную последовательность, нужно связать его с ячейкой 71 mod
10 = 1. Но эта ячейка уже занята значением 61, поэтому алгоритм
переходит к ячейке 2, которая тоже заполнена. Следующей должна быть
ячейка 3 &mdash; она свободна, и алгоритм размещает там 71.
</p>
<div style="text-align: center">
<img src="7.1.png" width="800" />
<p style="text-align: center">
Рисунок 7.1 - линейная пробная последовательность
</p>
</div>
<p style="text-align: justify">
Преимущество данного метода &mdash; в его простоте. Если необходимо,
пробная последовательность пройдет по каждой ячейке массива и вставит
элемент в свободное место, если оно еще осталось. Но есть и
сопутствующий недостаток &mdash; так называемая
<i>первичная кластеризация</i>, которая проявляется в образовании
больших блоков смежных записей и приводит к длинным пробным
последовательностям. В результате при добавлении нового элемента и его
хешировании к какой-либо записи в кластере пробная последовательность
вынуждена пройти через весь кластер, чтобы найти свободную ячейку.
</p>
<p style="text-align: justify">
Чтобы понять, как формируются кластеры, рассмотрим пример пустой
хеш-таблицы. Предположим, в ней содержится <i>N</i> записей и существует
вероятность <i>1/N</i>, что она закончится в любой данной позиции при
добавлении случайного числа. А теперь представим, что <i>K</i> &mdash;
конечная позиция таблицы. Существует вероятность <i>1/N</i>, что новое
случайное число попадет в позицию K и линейное пробирование попытается
расположить элемент в позиции <i>K + 1</i>. Но та же вероятность
характерна и для случая, при котором новый элемент будет связан с
позицией <i>K + 1</i> напрямую. Значит, существует вероятность
<i>2/N</i>, что элемент займет конечную позицию <i>K + 1</i> и
сформируется малый кластер.
</p>
<p style="text-align: justify">
Через какое-то время таких кластеров станет много. Чем больше они будут,
тем больше вероятность того, что новый элемент добавится в конец одного
из них. В итоге более мелкие кластеры сольются в более крупные, массив
заполнится ими &mdash; и возникнут длинные пробные последовательности.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="quadratic">Квадратичное пробирование</a>
</h3>
<p style="text-align: justify">
Возникновение больших кластеров при линейном пробировании связано с тем,
что новые элементы связываются с ячейками, стоящими в конце группы, и
постепенно увеличивают ее. Предотвратить подобную ситуацию помогает
<i>квадратичное пробирование</i>. Для создания пробной
последовательности в качестве шага по индексу берется квадрат количества
ячеек. Другими словами, если в линейном пробировании существует
последовательность <i>K, K + 1, K + 2, K + 3,</i> ... то в квадратичном
варианте она будет выглядеть так:
<i>K, K + 12, K + 22, K + 32, ...</i> В этом случае,&nbsp;если два
элемента окажутся связанными с разными позициями в одном и том же
кластере, они не обязательно будут придерживаться одной пробной
последовательности и попадут в конец кластера.
</p>
<p style="text-align: justify">
На рисунке 7.2 показана хеш-таблица, в начале которой есть группа из
пяти элементов. Новое значение 71 получает пробную последовательность
<i>1, 1 + 12 = 2, 1 + 22 = 5, 1 + 32 = 10</i> и не добавляется к
существующему кластеру. Значение <i>93 </i>поначалу связано с тем же
кластером, но согласно собственной пробной последовательности
<i>3, 3 + 12 = 4, 3 + 22 = 7</i> также не попадает в него.
</p>
<div style="text-align: center">
<img src="7.2.png" width="800" />
<p style="text-align: center">Рисунок 7.2 - Квадратичное пробирование</p>
</div>
<p style="text-align: justify">
Квадратичное пробирование предотвращает первичную, но не
<i>вторичную кластеризацию</i>, при которой значения, связанные с
одинаковой начальной позицией в массиве, получают одну и ту же пробную
последовательность, иногда очень длинную. В результате образуется точно
такая же группа элементов, но уже не собранных вместе, а распределенных
по всему массиву.
</p>
<p style="text-align: justify">
Еще один недостаток квадратичного пробирования связан с тем, что оно
может не найти свободную позицию, даже если в хеш-таблице их несколько.
Дело в том, что с каждым разом перемещение по массиву происходит все
дальше и дальше, и незаполненная ячейка попросту пропускается.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="pseudorandom">Псевдослучайное пробирование</a>
</h3>
<p style="text-align: justify">
Это пробирование подобно линейному, за исключением того, что шаг по
индексу формирует псевдослучайная функция изначально связанной ячейки.
Предположим, что это ячейка <i>K</i>, тогда пробная последовательность
будет выглядеть следующим образом: <i>K, K + p, K + 2p, ...</i> где p
определяется псевдослучайной функцией.
</p>
<p style="text-align: justify">
Подобно квадратичному пробированию, псевдослучайное предотвращает только
первичную кластеризацию, но страдает от вторичной: значения, связанные с
одной и той же начальной позицией, размещаются в хеш-таблице согласно
одной и той же пробной последовательности. Точно так же псевдослучайное
пробирование может пропускать некоторые неиспользуемые записи.
</p>
</div>
<div>
<h3 style="text-align: center">
<a name="double">Двойное хеширование</a>
</h3>
<p style="text-align: justify">
Чтобы избавиться от вторичной кластеризации значения, связанные с одной
и той же начальной ячейкой, должны получать разные пробные
последовательности. И здесь пригодится двойное хеширование. Оно похоже
на псевдослучайное пробирование, только шаг для индекса задается не
псевдослучайной функцией начальной ячейки, а второй функцией
хеширования.
</p>
<p style="text-align: justify">
Допустим, значения <i>A</i> и <i>B</i> связаны с позицией <i>K</i>. В
псевдослучайном пробировании шаг по индексу <i>p</i> генерируется
функцией <i>F<sub>1</sub> (K)</i>, затем оба значения используют пробную
последовательность <i>K, K + p, K + 2p, K + 3p, ...</i> В двойном
хешировании для связывания начальных значений <i>А</i> и
<i>В</i> применяется функция псевдослучайного хеширования
<i>F<sub>2</sub></i
>. В итоге при одном и том же начальном <i>K</i> образуются две пробные
последовательности с различными шагами по индексу:
<i>p<sub>A</sub> = F<sub>2</sub> (A)</i> и
<i>p<sub>B</sub> = F<sub>2</sub> (B)</i> соответственно.
</p>
<p style="text-align: justify">
Несмотря на то, что двойное хеширование хорошо справляется с первичной и
вторичной кластеризациями, оно точно так же, как и псевдослучайное
пробирование, может пропускать неиспользуемые записи.
</p>
</div>
<hr />
<p>
<sup>1</sup>Данный метод хеширования хорошо описан в книге Томаса Кормена
[2]
</p>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<info>
<directory>./TheoryHTML/Pages</directory>
<directory>./TheoryHTML/Images</directory>
<order>
<page>main.html</page>
<page>introduction.html</page>
<page>binaryRelationship.html</page>
<page>dirichletPrinciple.html</page>
<page>hashFunction.html</page>
<page>hashTable.html</page>
<page>chainMethod.html</page>
<page>openAddressing.html</page>
<page>analysis.html</page>
</order>
</info>