commit 49ecd4784c1acab324ff66868c48c84131462803 Author: user Date: Sun Jul 12 14:22:00 2026 +0400 Initial commit diff --git a/HashTable.pro b/HashTable.pro new file mode 100644 index 0000000..7992869 --- /dev/null +++ b/HashTable.pro @@ -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 + + diff --git a/Installer/script.iss b/Installer/script.iss new file mode 100644 index 0000000..99c8f96 --- /dev/null +++ b/Installer/script.iss @@ -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 \ No newline at end of file diff --git a/QuestionsXML/questions.xml b/QuestionsXML/questions.xml new file mode 100644 index 0000000..217421f --- /dev/null +++ b/QuestionsXML/questions.xml @@ -0,0 +1,101 @@ + + + + + Соотнесите подходящие варианты ответа с высказыванием. + Метод решения коллизий в хеш-таблице. + Прямая адрессация. + Открытая адрессация. + Регистровая адресация. + Метод цепочек. + Ничего из вышеперечисленного. + + + + Выберите несколько правильных ответов. + С какими данными оперирует хеш-функция в процессе хеширования? + Хеш-память. + Хеш-значение. + Кеш-память. + Множество ключей. + Множество значений. + + + + Выберите несколько правильных ответов. + На что влияет коэффициент заполнения? + Поиск неиспользующегося бункера, при гарантии его существования. + Поиск использующегося бункера по его ключу. + Скорость хеширования. + Количество используемых бункеров. + Количество возможных ключей. + + + + Выберите несколько правильных ответов. + Какие алгоритмы поиска бункера при решении коллизий открытой адресацией используют ровно одну хеш-функцию? + Линейное пробирование. + Квадратичное пробирование. + Псевдослучайное пробирование. + Двойное хеширование. + Ничего из перечисленного. + + + + Введите правильное целочисленое число. + Чему равна дисперсия, как мера разброса элементов хеш-таблицы от средней условной величины при идеальном хешировании? + 0 + + + + Выберите варианты ответов, которые подходят по смыслу с заданным текстом. + Сопоставьте - идеальное хеширование. + Словарь. + Прямая адрессация. + Открытая адрессация. + Регистровая адресация. + Метод цепочек. + Ничего из вышеперечисленного. + + + + Определите про какие алгоритмы поиска бункера при решении коллизий открытой адресацией идёт речь? + Политика разрешения коллизий использует шаг по индексу, который зависит от информации (позиция или данные) бункера. + Линейное пробирование. + Квадратичное пробирование. + Псевдослучайное пробирование. + Двойное хеширование. + Ничего из вышеперечисленного. + + + + Определите про какие алгоритмы поиска бункера при решении коллизий открытой адресацией идёт речь? + Политика разрешения коллизий использует шаг по индексу, который зависит от количества итераций и/или размера хеш-таблицы. + Линейное пробирование. + Квадратичное пробирование. + Псевдослучайное пробирование. + Двойное хеширование. + Ничего из вышеперечисленного. + + + + Напишите правильный ответ. + Рассмотрим хеш-функцию, которая равномерно распределяет значения по хеш-таблице. + Размер хеш-таблицы равен 20. + После какого количества вставок вероятность того, что при попытке вставить в хеш-таблицу новое значение произойдёт коллизия, превысит 0.5? + 11 + + + + Напишите правильный ответ. + Чему будет равен коэффициент заполненности, если в хеш-таблица с 25 цепочками поместить 2000 элементов? + 80 + + + + Напишите правильный ответ. + Определите коэффициет заполнения хеш-таблицы с решением коллизий методом открытой адресациии, если её размер равняется 50, но свободных бункеров - 20. + 0,60 + + + \ No newline at end of file diff --git a/SourceCode/BusinessLogic/Convert/convert.cpp b/SourceCode/BusinessLogic/Convert/convert.cpp new file mode 100644 index 0000000..ae32a71 --- /dev/null +++ b/SourceCode/BusinessLogic/Convert/convert.cpp @@ -0,0 +1,22 @@ +#include "convert.h" + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Convert) + +size_t FromStdString::operator()(const std::array &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 diff --git a/SourceCode/BusinessLogic/Convert/convert.h b/SourceCode/BusinessLogic/Convert/convert.h new file mode 100644 index 0000000..ea49c12 --- /dev/null +++ b/SourceCode/BusinessLogic/Convert/convert.h @@ -0,0 +1,24 @@ +#ifndef CONVERT_H +#define CONVERT_H + +#include "../businessLogic.h" + +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Convert) + +class FromStdString +{ +public: + size_t operator()(const std::array &, size_t) const; +}; + +END_NAMESPACE // Convert +END_NAMESPACE // BusinessLogic + +#endif // CONVERT_H diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorDoubleHashing.h b/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorDoubleHashing.h new file mode 100644 index 0000000..259ab5e --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorDoubleHashing.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 create() const override { + return std::unique_ptr(new Product(m_firstHashFunction, m_secondHashFunction)); + } +}; + +END_NAMESPACE // DoubleHashing +END_NAMESPACE // Algorithm +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !CREATOR_ALGHORITHM_DOUBLE_HASHING_H diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorFamily.h b/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorFamily.h new file mode 100644 index 0000000..8809ebd --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorFamily.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorPseudorandomProbing.h b/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorPseudorandomProbing.h new file mode 100644 index 0000000..089e2e6 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/Family/creatorPseudorandomProbing.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 create() const override { + return std::unique_ptr(new Product(m_hashFunctionNumber)); + } + +}; + +END_NAMESPACE // PseudorandomProbing +END_NAMESPACE // Algorithm +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !CREATOR_ALGHORITHM_PSEUDORANDOM_PROBING_H diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/Family/doubleHashing.h b/SourceCode/BusinessLogic/Hash/Algorithm/Family/doubleHashing.h new file mode 100644 index 0000000..89390ad --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/Family/doubleHashing.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/Family/family.h b/SourceCode/BusinessLogic/Hash/Algorithm/Family/family.h new file mode 100644 index 0000000..2f9eeed --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/Family/family.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/Family/pseudorandomProbing.h b/SourceCode/BusinessLogic/Hash/Algorithm/Family/pseudorandomProbing.h new file mode 100644 index 0000000..d790ef7 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/Family/pseudorandomProbing.h @@ -0,0 +1,44 @@ +#ifndef ALGHORITHM_PSEUDORANDOM_PROBING_H +#define ALGHORITHM_PSEUDORANDOM_PROBING_H + +#include "family.h" + +#include + +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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorLinearProbing.h b/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorLinearProbing.h new file mode 100644 index 0000000..391b99f --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorLinearProbing.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 create() const override { + return std::unique_ptr(new Product(m_coefficient)); + } + +}; + +END_NAMESPACE // LinearProbing +END_NAMESPACE // Algorithm +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !CREATOR_ALGHORITHM_LINEAR_PROBING_H diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorOne.h b/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorOne.h new file mode 100644 index 0000000..de371a4 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorOne.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorQuadraticProbing.h b/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorQuadraticProbing.h new file mode 100644 index 0000000..58c8add --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/One/creatorQuadraticProbing.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 create() const override { + return std::unique_ptr(new Product()); + } +}; + +END_NAMESPACE // LinearProbing +END_NAMESPACE // Algorithm +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !CREATOR_ALGHORITHM_QUADRATIC_PROBING_H diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/One/linearProbing.h b/SourceCode/BusinessLogic/Hash/Algorithm/One/linearProbing.h new file mode 100644 index 0000000..a686dd4 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/One/linearProbing.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/One/one.h b/SourceCode/BusinessLogic/Hash/Algorithm/One/one.h new file mode 100644 index 0000000..4878f09 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/One/one.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/One/quadraticProbing.h b/SourceCode/BusinessLogic/Hash/Algorithm/One/quadraticProbing.h new file mode 100644 index 0000000..a36e9cb --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/One/quadraticProbing.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 diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/abstract.h b/SourceCode/BusinessLogic/Hash/Algorithm/abstract.h new file mode 100644 index 0000000..5bd4297 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/abstract.h @@ -0,0 +1,101 @@ +#ifndef ALGHORITHM_ABSTRACT_H +#define ALGHORITHM_ABSTRACT_H + +#include "../../Convert/convert.h" + +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Hash) +BEGIN_NAMESPACE(Algorithm) +BEGIN_NAMESPACE(Abstract) + +class Product +{ +public: + using value_type = std::array; + +private: + const std::vector *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(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 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::max(); + } +}; + +END_NAMESPACE // Abstract +END_NAMESPACE // Algorithm +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !ALGHORITHM_ABSTRACT_H diff --git a/SourceCode/BusinessLogic/Hash/Algorithm/creatorAbstract.h b/SourceCode/BusinessLogic/Hash/Algorithm/creatorAbstract.h new file mode 100644 index 0000000..7250a43 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Algorithm/creatorAbstract.h @@ -0,0 +1,29 @@ +#ifndef CREATOR_ALGHORITHM_ABSTRACT_H +#define CREATOR_ALGHORITHM_ABSTRACT_H + +#include "../../../BusinessLogic/businessLogic.h" + +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Hash) +BEGIN_NAMESPACE(Algorithm) +BEGIN_NAMESPACE(Abstract) + +class Creator +{ +protected: + Creator() + { + } + +public: + virtual std::unique_ptr create() const = 0; +}; + +END_NAMESPACE // Abstract +END_NAMESPACE // Algorithm +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !CREATOR_ALGHORITHM_ABSTRACT_H diff --git a/SourceCode/BusinessLogic/Hash/Factory/abstract.h b/SourceCode/BusinessLogic/Hash/Factory/abstract.h new file mode 100644 index 0000000..505fb35 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Factory/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; + using AAC_type = std::shared_ptr; + +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 getAlgorithm() const = 0; +}; + +END_NAMESPACE // Factory +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !FACTORY_ABSTRACT_H \ No newline at end of file diff --git a/SourceCode/BusinessLogic/Hash/Factory/family.h b/SourceCode/BusinessLogic/Hash/Factory/family.h new file mode 100644 index 0000000..ba5857b --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Factory/family.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; + using FAC_type = std::shared_ptr; + + 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(m_functionCreator->create()); + } + virtual std::unique_ptr getAlgorithm() const override { + std::unique_ptr algorithm = m_algorithmCreator->create(); + dynamic_cast(algorithm.get())->setHashFunction(getFunction()); + return algorithm; + } +}; + +END_NAMESPACE // Factory +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !FACTORY_FAMILY_H diff --git a/SourceCode/BusinessLogic/Hash/Factory/one.h b/SourceCode/BusinessLogic/Hash/Factory/one.h new file mode 100644 index 0000000..a9b2a3f --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Factory/one.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; + using OAC_type = std::shared_ptr; + + 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(m_functionCreator->create()); + } + virtual std::unique_ptr getAlgorithm() const override { + std::unique_ptr algorithm = m_algorithmCreator->create(); + dynamic_cast(algorithm.get())->setHashFunction(getFunction()); + return algorithm; + } +}; + +END_NAMESPACE // Factory +END_NAMESPACE // Hash +END_NAMESPACE // BusinessLogic + +#endif // !FACTORY_ONE_H diff --git a/SourceCode/BusinessLogic/Hash/Function/Family/creatorFamily.h b/SourceCode/BusinessLogic/Hash/Function/Family/creatorFamily.h new file mode 100644 index 0000000..019d4cc --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/Family/creatorFamily.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 diff --git a/SourceCode/BusinessLogic/Hash/Function/Family/creatorFnv1a.h b/SourceCode/BusinessLogic/Hash/Function/Family/creatorFnv1a.h new file mode 100644 index 0000000..3ca1c90 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/Family/creatorFnv1a.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 diff --git a/SourceCode/BusinessLogic/Hash/Function/Family/family.h b/SourceCode/BusinessLogic/Hash/Function/Family/family.h new file mode 100644 index 0000000..b6d8763 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/Family/family.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; + +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 diff --git a/SourceCode/BusinessLogic/Hash/Function/Family/fnv1a.h b/SourceCode/BusinessLogic/Hash/Function/Family/fnv1a.h new file mode 100644 index 0000000..5c0f0e5 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/Family/fnv1a.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; + +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(value); + return static_cast(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 diff --git a/SourceCode/BusinessLogic/Hash/Function/One/creatorEquivalent.h b/SourceCode/BusinessLogic/Hash/Function/One/creatorEquivalent.h new file mode 100644 index 0000000..dd98a69 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/One/creatorEquivalent.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 diff --git a/SourceCode/BusinessLogic/Hash/Function/One/creatorOne.h b/SourceCode/BusinessLogic/Hash/Function/One/creatorOne.h new file mode 100644 index 0000000..3d06deb --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/One/creatorOne.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 diff --git a/SourceCode/BusinessLogic/Hash/Function/One/creatorStandart.h b/SourceCode/BusinessLogic/Hash/Function/One/creatorStandart.h new file mode 100644 index 0000000..5287f84 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/One/creatorStandart.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 diff --git a/SourceCode/BusinessLogic/Hash/Function/One/equivalent.h b/SourceCode/BusinessLogic/Hash/Function/One/equivalent.h new file mode 100644 index 0000000..9243ada --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/One/equivalent.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; + +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 diff --git a/SourceCode/BusinessLogic/Hash/Function/One/one.h b/SourceCode/BusinessLogic/Hash/Function/One/one.h new file mode 100644 index 0000000..84bd552 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/One/one.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; + +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 diff --git a/SourceCode/BusinessLogic/Hash/Function/One/standart.h b/SourceCode/BusinessLogic/Hash/Function/One/standart.h new file mode 100644 index 0000000..0d3a988 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/One/standart.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; + +class Product final : public One::Product, public Singleton +{ +private: + std::hash m_standartHashFunction; + +private: + friend const Product &Singleton::getInstance(); + Product() + : One::Product( + std::bind(&std::hash::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 diff --git a/SourceCode/BusinessLogic/Hash/Function/Pattern/creatorFamilyToOne.h b/SourceCode/BusinessLogic/Hash/Function/Pattern/creatorFamilyToOne.h new file mode 100644 index 0000000..c242dd8 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/Pattern/creatorFamilyToOne.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 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 diff --git a/SourceCode/BusinessLogic/Hash/Function/Pattern/familyToOne.h b/SourceCode/BusinessLogic/Hash/Function/Pattern/familyToOne.h new file mode 100644 index 0000000..e4380d7 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/Pattern/familyToOne.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 diff --git a/SourceCode/BusinessLogic/Hash/Function/abstract.h b/SourceCode/BusinessLogic/Hash/Function/abstract.h new file mode 100644 index 0000000..8211502 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/abstract.h @@ -0,0 +1,30 @@ +#ifndef FUNCTION_ABSTRACT_H +#define FUNCTION_ABSTRACT_H + +#include "../../businessLogic.h" +#include "../../Pattern/singleton.h" + +#include +#include + +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 diff --git a/SourceCode/BusinessLogic/Hash/Function/creatorAbstract.h b/SourceCode/BusinessLogic/Hash/Function/creatorAbstract.h new file mode 100644 index 0000000..1a7c5cd --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Function/creatorAbstract.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 diff --git a/SourceCode/BusinessLogic/Hash/Table/Pattern/subscriber.h b/SourceCode/BusinessLogic/Hash/Table/Pattern/subscriber.h new file mode 100644 index 0000000..125b5b2 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Table/Pattern/subscriber.h @@ -0,0 +1,58 @@ +#ifndef SUBSCRIBER_H +#define SUBSCRIBER_H + +#include "../../../businessLogic.h" + +#include +#include +#include +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Hash) +BEGIN_NAMESPACE(Table) +BEGIN_NAMESPACE(Pattern) + +class InterfaceSubscriber +{ +public: + virtual void successfulInsertion(const Table::Abstract *, const std::array &, std::pair, size_t) = 0; + virtual void unsuccessfulInsertion(const Table::Abstract *, const std::array &) = 0; +}; + +class Publisher +{ +private: + std::vector 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 &value, std::pair 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 &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 diff --git a/SourceCode/BusinessLogic/Hash/Table/abstract.h b/SourceCode/BusinessLogic/Hash/Table/abstract.h new file mode 100644 index 0000000..ec53e8c --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Table/abstract.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 +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Hash) +BEGIN_NAMESPACE(Table) + +class Abstract : public Pattern::Publisher +{ +public: + using value_type = std::array; + 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 diff --git a/SourceCode/BusinessLogic/Hash/Table/chains.h b/SourceCode/BusinessLogic/Hash/Table/chains.h new file mode 100644 index 0000000..dc87bcb --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Table/chains.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>; + 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::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 ¤tList = 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 diff --git a/SourceCode/BusinessLogic/Hash/Table/openAddress.h b/SourceCode/BusinessLogic/Hash/Table/openAddress.h new file mode 100644 index 0000000..88628e4 --- /dev/null +++ b/SourceCode/BusinessLogic/Hash/Table/openAddress.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; + 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 m_algorithm; + +public: + OpenAddressing(size_t size, const factory_type &factory, size_t alphabetPower = std::numeric_limits::max()) + : Abstract(alphabetPower) + , m_numberOfCollision(size, std::numeric_limits::max()) + , m_algorithm(factory.getAlgorithm()) + { + constexpr std::array 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::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::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 diff --git a/SourceCode/BusinessLogic/Pattern/singleton.h b/SourceCode/BusinessLogic/Pattern/singleton.h new file mode 100644 index 0000000..ed51914 --- /dev/null +++ b/SourceCode/BusinessLogic/Pattern/singleton.h @@ -0,0 +1,37 @@ +#ifndef SINGLETON_H +#define SINGLETON_H + +#include "../businessLogic.h" + +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Pattern) + +template +class Singleton { +private: + static std::unique_ptr m_singleton; + +public: + static const T &getInstance() { + if (m_singleton == nullptr) { + m_singleton = std::unique_ptr(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 +std::unique_ptr Singleton::m_singleton = nullptr; + +END_NAMESPACE // Pattern +END_NAMESPACE // BusinessLogic + +#endif // SINGLETON_H diff --git a/SourceCode/BusinessLogic/Statistics/dispersion.cpp b/SourceCode/BusinessLogic/Statistics/dispersion.cpp new file mode 100644 index 0000000..9268aea --- /dev/null +++ b/SourceCode/BusinessLogic/Statistics/dispersion.cpp @@ -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(size); + averageOfSquares += ( container[i] ) * ( container[i] ) / static_cast(size); + } + return averageOfSquares - average * average; +} + +END_NAMESPACE // Statistics +END_NAMESPACE // BusinessLogic diff --git a/SourceCode/BusinessLogic/Statistics/dispersion.h b/SourceCode/BusinessLogic/Statistics/dispersion.h new file mode 100644 index 0000000..bb9751d --- /dev/null +++ b/SourceCode/BusinessLogic/Statistics/dispersion.h @@ -0,0 +1,25 @@ +#ifndef DISPERSION_H +#define DISPERSION_H + +#include "../businessLogic.h" + +#include +#include +#include + +BEGIN_NAMESPACE(BusinessLogic) +BEGIN_NAMESPACE(Statistics) + +class Dispersion { +public: // Types + using value_type = size_t; + using container_type = std::vector; + +public: + long double operator()(const container_type &container, size_t size) const; +}; + +END_NAMESPACE // Statistics +END_NAMESPACE // BusinessLogic + +#endif // DISPERSION_H diff --git a/SourceCode/BusinessLogic/businessLogic.h b/SourceCode/BusinessLogic/businessLogic.h new file mode 100644 index 0000000..48f6755 --- /dev/null +++ b/SourceCode/BusinessLogic/businessLogic.h @@ -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 + class Singleton; + } + + namespace Convert + { + class FromStdString; + } + + namespace Statistics + { + class Dispersion; + } +} + +#endif // BUSINESS_LOGIC_H diff --git a/SourceCode/BusinessLogic/debug.cpp b/SourceCode/BusinessLogic/debug.cpp new file mode 100644 index 0000000..c257293 --- /dev/null +++ b/SourceCode/BusinessLogic/debug.cpp @@ -0,0 +1,197 @@ +#include "hashHeaderFiles.h" + +#include +#include +#include +#include +#include +#include + +#include "Convert/convert.h" + +using namespace BusinessLogic::Hash; +using namespace Function::Pattern; +using namespace Table::Pattern; + +using factory_ptr = std::shared_ptr; + +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(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 &, std::pair, 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 &) override { + ++m_numberOfFailures; + } + virtual void filledInPart(const Table::Abstract *) override { + m_lastCoefficients = 0; + } +}; + +void runTable(std::unique_ptr table, size_t target) { + /* 26 letters */ + constexpr char firstChar = ' '; + constexpr char endChar = '~'; + size_t progress = 0; + std::array 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(); + auto equivalent = std::make_shared(); + auto standart = std::make_shared(); + + auto doubleHashing = std::make_shared(0, 1); + auto pseudorandomProbing = std::make_shared(0); + auto linearProbing = std::make_shared(); + auto quadraticProbing = std::make_shared(); + + /* 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(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(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, quantityOfTables> results; + for(std::shared_ptr ¤t : results) { + current = std::make_shared(static_cast(numberOfInserts * alpha)); + } + +/* + * Constants +*/ + + + + std::array, quantityOfTables> tables { + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac1, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac2, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac3, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac4, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac5, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac6, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac7, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac8, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac9, alphabetPower) ), + std::unique_ptr( new Table::OpenAddressing(numberOfInserts, fac10, alphabetPower) ), + std::unique_ptr( new Table::Chains (numberOfBins, *equivalent, alphabetPower) ), + std::unique_ptr( new Table::Chains (numberOfBins, *standart, alphabetPower) ), + std::unique_ptr( new Table::Chains (numberOfBins, *simpleFNV1a, alphabetPower) ), + std::unique_ptr( 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; +} diff --git a/SourceCode/BusinessLogic/hashHeaderFiles.h b/SourceCode/BusinessLogic/hashHeaderFiles.h new file mode 100644 index 0000000..0efc586 --- /dev/null +++ b/SourceCode/BusinessLogic/hashHeaderFiles.h @@ -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 diff --git a/SourceCode/ManualHTML/Images/demonstration.png b/SourceCode/ManualHTML/Images/demonstration.png new file mode 100644 index 0000000..4759c8b Binary files /dev/null and b/SourceCode/ManualHTML/Images/demonstration.png differ diff --git a/SourceCode/ManualHTML/Images/menubarFirst.png b/SourceCode/ManualHTML/Images/menubarFirst.png new file mode 100644 index 0000000..3a28472 Binary files /dev/null and b/SourceCode/ManualHTML/Images/menubarFirst.png differ diff --git a/SourceCode/ManualHTML/Images/menubarSecond.png b/SourceCode/ManualHTML/Images/menubarSecond.png new file mode 100644 index 0000000..24e8985 Binary files /dev/null and b/SourceCode/ManualHTML/Images/menubarSecond.png differ diff --git a/SourceCode/ManualHTML/Images/testingPage.png b/SourceCode/ManualHTML/Images/testingPage.png new file mode 100644 index 0000000..0e880af Binary files /dev/null and b/SourceCode/ManualHTML/Images/testingPage.png differ diff --git a/SourceCode/ManualHTML/Images/theory.png b/SourceCode/ManualHTML/Images/theory.png new file mode 100644 index 0000000..b0fbb3a Binary files /dev/null and b/SourceCode/ManualHTML/Images/theory.png differ diff --git a/SourceCode/ManualHTML/Images/theoryPage.png b/SourceCode/ManualHTML/Images/theoryPage.png new file mode 100644 index 0000000..f409a2a Binary files /dev/null and b/SourceCode/ManualHTML/Images/theoryPage.png differ diff --git a/SourceCode/ManualHTML/Pages/demonstration.html b/SourceCode/ManualHTML/Pages/demonstration.html new file mode 100644 index 0000000..d0c2de2 --- /dev/null +++ b/SourceCode/ManualHTML/Pages/demonstration.html @@ -0,0 +1,84 @@ + + + + + + + Demonstration + + +

Руководство пользователя

+

Система демонстрации

+

+ Данный раздел - описание существующих возможностей взаимодействия с + системой демонстрации изученного материала.
+ На рисунке 3.1 виден весь основной интерфейс пользователя, необходимый для + полноценного комфортного взаимодействия с данной системой. +

+
+ +

+ Рисунок 2.1 - система демонстрации вставки элемента в хеш-таблицу +

+
+

+ Каждая цифра указывает на определённый интерфейс пользователя, где даётся + его описание: +

+
    +
  1. + Табличное представление модели, которое заполняется ранее + вставленными в хеш-таблицу элементами в порядке их хранения в самой + хей-таблице. +
  2. +
  3. + График, показывающий тенденцию изменения коэффициента простого + равномерного хеширования на протяжении процесса вставки элементов в + хеш-таблицу. +
  4. +
  5. + График, показывающий тенденцию изменения количества коллизий на + протяжении процесса вставки элементов в хеш-таблицу. +
  6. +
  7. + Группирующий блок, позволяющий изменять способ решения проблем + коллизий хеш-таблицы. +
  8. +
  9. + Группирующий блок, позволяющий изменять применяемую в процессе вставки + элемента хеш-функцию. +
  10. +
  11. + Группирующий блок, позволяющий изменять применяемую в процессе вставки + элемента алгоритм, применяемый в попытке решения колизии на основе + таблицы с открытой адрессацией. +
  12. +
  13. + Сгруппированный интерфейс, позволяющий создать новую хеш-таблицу с + указанием размера первоначального контейнера, сбросить действительную + хеш-таблицу, запросить последнюю статистику по операциям вставки + элементов +
  14. +
  15. + Сгруппированный интерфейс, позволяющий создавать инструкции по вставке + новых элементов в хеш таблицу несколькими способами: n-ое количество + элементов разных элементов и один единственный, где задаётся первый + элемент. Так же существует возможность поиска первого несуществующего + элемента хеш-таблице, остановки процесса вставки элементов в + хеш-таблцицу, фокусирования графиков для полного отображения информации. + Каждая функция соответствует своей кнопке данного сгруппированного + интерфейса. +
  16. +
  17. + Вывод информации о действиях пользователя и результатах хеширования + элементов. +
  18. +
  19. + Масштабирование всех видов, вплоть до освобождения места для + определённого вида с целью его более детального рассмотрения. + Существвует возможность полного масштабирования одного вида, взамен + скрытия всех остальных. +
  20. +
+ + diff --git a/SourceCode/ManualHTML/Pages/main.html b/SourceCode/ManualHTML/Pages/main.html new file mode 100644 index 0000000..407a2d3 --- /dev/null +++ b/SourceCode/ManualHTML/Pages/main.html @@ -0,0 +1,33 @@ + + + + + + + Main + + +

Руководство пользователя

+

+ Предоставление помощи пользователю
+ в использовании демонстрационной программы:
+ "Алгоритм вставки в хеш-таблицу" +

+

+ Данное руководство предназначено пользователю для лучшего понимания работы + программы и взаимодействия с ней. +

+

Оглавление:

+
    +
  1. + Раздел теории + +
  2. +
  3. Раздел тестирования
  4. +
  5. Полоса или строка меню
  6. +
+ + diff --git a/SourceCode/ManualHTML/Pages/menubar.html b/SourceCode/ManualHTML/Pages/menubar.html new file mode 100644 index 0000000..cf33894 --- /dev/null +++ b/SourceCode/ManualHTML/Pages/menubar.html @@ -0,0 +1,57 @@ + + + + + + + Menubar + + +

Руководство пользователя

+

Полоска или строка меню

+

+ Данный раздел - описание существующих возможностей взаимодействия с + посолкой или строкой меню данной программы.
+ На рисунке 5.1 и 5.2 отображены подменю, каждое из которых группирует + определённые действия. +

+
+ +

+ Рисунок 5.1 - подменю выбора текущего раздела +

+

+ +

+

Рисунок 5.2 - подменю предоставления помощи

+
+

+ Первое подменю (см. рис. 5.1) необходимо для переключения разделов - + раздел теории, который включает две системы (система теории и система + демонстрации) и раздел тестирования. +

+

+ Каждая цифра указывает на определённый интерфейс пользователя, где даётся + его описание: +

+
    +
  1. + Действие подменю, необходимое для переключения вида на раздел теории. +
  2. +
  3. + Действие подменю, необходимое для переключения вида на раздел практики. +
  4. +
  5. + Действие подменю, необходимое для открытия модального диалогового окна - + руководства пользователя. +
  6. +
  7. + Действие подменю, необходимое для открытия модального диалогового окна, + которое содержит информацию об использующимся программой фреймворке + Qt. +
  8. +
+ + diff --git a/SourceCode/ManualHTML/Pages/testingPage.html b/SourceCode/ManualHTML/Pages/testingPage.html new file mode 100644 index 0000000..25eb3f6 --- /dev/null +++ b/SourceCode/ManualHTML/Pages/testingPage.html @@ -0,0 +1,67 @@ + + + + + + + PracticPage + + +

Руководство пользователя

+

Система тестирования

+

+ Данный раздел - описание существующих возможностей взаимодействия с + системой тестирования.
+ На рисунке 4.1 виден весь основной интерфейс пользователя, необходимый для + полноценного комфортного взаимодействия с данной системой. +

+
+ +

Рисунок 4.1 - система тестирования

+
+

+ Каждая цифра указывает на определённый интерфейс пользователя, где даётся + его описание: +

+
    +
  1. + Отображаемый текст, как текущий вопрос с описанием ввода правильного + ответа и самого тестового задания. +
  2. +
  3. + Панель ввода правильного ответа. Может представлять + определённое количество флагов для указания множественного + ответа из множества альтернатив (от 5-и до 9-и), поле ввода целого + числа или числа с плавающей точкой. +
  4. +
  5. + Нажимная кнопка для подтверждения ответа и проверки его на корректность. +
  6. +
  7. + Выходная информация, как способ идентификации успешного / безуспешного + начала тестирования с указанием конкретной ошибки, завершения + тестирования и успешного / безуспешного ответа на предыдущий вопрос. +
  8. +
  9. + Нажимная кнопка, реализующая начало тестирования. +
  10. +
  11. + Нажимная кнопка, реализующая предварительное завершение тестирования. +
  12. +
  13. + Группирующий интерфейс необходимый для выбора типа предоставляемых + вопросов в процессе тестирования. +
  14. +
  15. + Группирующий интерфейс необходимый для выбора сложности + предоставляемых вопросов в процессе тестирования. +
  16. +
+

+ Стоит отметить, что результат тестирования сохраняется в бинарном файле + (формат записи смотри в технической документации), когда тестирование + завершается после окончания подходящих под критерии вопросов или решения + пользователя, при нажатии соответствующей кнопки. +

+ + diff --git a/SourceCode/ManualHTML/Pages/theory.html b/SourceCode/ManualHTML/Pages/theory.html new file mode 100644 index 0000000..494e169 --- /dev/null +++ b/SourceCode/ManualHTML/Pages/theory.html @@ -0,0 +1,63 @@ + + + + + + + Theory + + +

Руководство пользователя

+

Система теории

+

+ Данный раздел - описание существующих возможностей взаимодействия с + системой изучения теоретического материала.
+ На рисунке 2.1 виден весь основной интерфейс пользователя, необходимый для + полноценного комфортного взаимодействия с данной системой. +

+
+ +

+ Рисунок 2.1 - система изучения теоретического материала +

+
+

+ Каждая цифра указывает на определённый интерфейс пользователя, где даётся + его описание: +

+
    +
  1. + Нажимная кнопка, при нажатии которой пользователь переходит на следующую + страницу теоретического материала. Доступна, если отображается не + главная и не последняя страницы. +
  2. +
  3. + Нажимная кнопка, при нажатии которой пользователь переходит на главную + страницу теоретического материала. Доступна, если не отображается + главная страница. +
  4. +
  5. + Нажимная кнопка, при нажатии которой пользователь переходит на + предыдущую страницу теоретического материала. Доступна, если + отображается не главная и не первая страницы. +
  6. +
  7. + Нажимная кнопка, позволяющая отобразить предыдущую небольшую + доступную часть отображаемой страницы. +
  8. +
  9. + Ползунок, при перемещении которого можно перейти к любой части + отображаемой страницы. +
  10. +
  11. + Нажимная кнопка, позволяющая отобразить следующую небольшую + доступную часть отображаемой страницы. +
  12. +
  13. + Гиперссылка оглавления, при нажатии на которую пользователь может + перейти к любой интересующей его теме, которая описывается в отдельной + страцице. +
  14. +
+ + diff --git a/SourceCode/ManualHTML/Pages/theoryPage.html b/SourceCode/ManualHTML/Pages/theoryPage.html new file mode 100644 index 0000000..bad99ce --- /dev/null +++ b/SourceCode/ManualHTML/Pages/theoryPage.html @@ -0,0 +1,50 @@ + + + + + + + TheoryPage + + +

Руководство пользователя

+

Раздел теории

+

+ Данный раздел - первое, что видит пользователь, при первом запуске + программы.
+ На рисунке 1.1 виден весь основной интерфейс пользователя, необходимый для + перехода в ту или иную систему. +

+
+ +

Рисунок 1.1 - раздел теории и практики

+
+

Всего существует три системы:

+
    +
  • Теории.
  • +
  • Демонстрации.
  • +
  • Тестирования.
  • +
+

+ Основой графического интерфейса пользователя являются нажимаемые кнопки, + переключающие между собой вкладки, флажки множественного или одиночного + выборов, и другие элементы, которые будут обсуждаться по мере описания + данного руководства. Каждая цифра указывает на определённый интерфейс + пользователя, где даётся его описание: +

+
    +
  1. + Раздел изучения теоретического материала, необходимый для понимания темы + "Алгоритм вставки элемента в хеш-таблицу". +
  2. +
  3. + Раздел демонстрации вставки элемента в хеш-таблицу.  +
  4. +
  5. + Полоса или строка меню, как единственный способ переключения фокуса + между системами теории, которая подразумевает включение системы + демонстрации, и тестирования. +
  6. +
+ + diff --git a/SourceCode/ManualHTML/info.xml b/SourceCode/ManualHTML/info.xml new file mode 100644 index 0000000..5ed8729 --- /dev/null +++ b/SourceCode/ManualHTML/info.xml @@ -0,0 +1,13 @@ + + + :/ManualHTML/Pages + :/ManualHTML/Images + + main.html + theoryPage.html + theory.html + demonstration.html + testingPage.html + menubar.html + + diff --git a/SourceCode/UserInterface/ClassesUI/Validator/validator.h b/SourceCode/UserInterface/ClassesUI/Validator/validator.h new file mode 100644 index 0000000..cc99f55 --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Validator/validator.h @@ -0,0 +1,21 @@ +#ifndef LATIN_VALIDATOR_H +#define LATIN_VALIDATOR_H + +#include + +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 diff --git a/SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.cpp b/SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.cpp new file mode 100644 index 0000000..a10b9ab --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.cpp @@ -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(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 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(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(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( + progress * static_cast(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") + + "
" + + getColorTextHTML(QString("Failed inserts    : %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 factory; + bool functionTypeIsFamily = + getCurrentFunctionType() == RelationshipType::Family; + if (getCurrentAlgorythmType() == RelationshipType::One) { + factory = std::make_unique( + functionTypeIsFamily + ? m_complicatedFunction // The complicated function must be prepared + : std::dynamic_pointer_cast(m_pFunction), + std::dynamic_pointer_cast(m_pAlgorithm)); + } else if (functionTypeIsFamily) { + factory = std::make_unique( + std::dynamic_pointer_cast(m_pFunction), + std::dynamic_pointer_cast(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(); + } else if (m_rbStandart->isChecked()) { + m_pFunction = std::make_shared(); + } else { // m_rbFNV1a32bit->isChecked() + m_pFunction = std::make_shared(); + } +} + +inline void DemonstrationWidget::updateAlgorithmCreator() { + using namespace BusinessLogic::Hash::Algorithm; + if (m_rbLinearProbing->isChecked()) { + m_pAlgorithm = std::make_shared(); + } else if (m_rbQuadraticProbing->isChecked()) { + m_pAlgorithm = std::make_shared(); + } else if (m_rbPseudorandomProbing->isChecked()) { + m_pAlgorithm = std::make_shared( + m_sbFirstInputData->value()); + } else { // m_rbDoubleHashing->isChecked() + m_pAlgorithm = std::make_shared( + 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( + std::dynamic_pointer_cast(m_pFunction), + m_sbFirstInputData->value()); + } + + size_t bucketQuantity = m_sbBucketQuantity->value(); + try { + if (tableTypeIsChain) { + m_pTable = std::make_unique( + bucketQuantity, + functionTypeIsFamily + ? *m_complicatedFunction + : *std::dynamic_pointer_cast(m_pFunction), + m_alphabetPower); + } else { + auto factory = getCurrentFactory(); + m_pTable = std::make_unique( + 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{ + 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{ + m_leFrom, m_sbQuantity, m_pbMakeItems, m_leInsert, m_pbInsert, + m_pbReset, m_pbStatistics, m_pbFindFree}) { + widget->setEnabled(flag); + } + m_pbStop->setDisabled(flag); +} diff --git a/SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.h b/SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.h new file mode 100644 index 0000000..d274746 --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.h @@ -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 +#include +#include +#include + +#include +#include +#include +#include + +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 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(target); + QChart *chart = view->chart(); + + switch (event->type()) { + case QEvent::Wheel: { + QWheelEvent *currentEvent = dynamic_cast(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 m_pFunction; + std::shared_ptr + m_complicatedFunction; + std::shared_ptr + m_pAlgorithm; + size_t m_alphabetPower; + std::unique_ptr m_pTable; + TableInformation m_tableInformation; + + /* + * HTML tags + */ + static constexpr auto m_fontBeginColorHTML = R"()"; + static constexpr auto m_fontEndHTML = R"()"; + +public: + DemonstrationWidget(QWidget *pWidget = nullptr); + +public: // Custom slots + virtual void successfulInsertion(const table_type *, const value_type &, + std::pair, 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(""); + auto children = splitter->children(); + QList sizes{dynamic_cast(children[0])->minimumHeight(), + dynamic_cast(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 diff --git a/SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.cpp b/SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.cpp new file mode 100644 index 0000000..0eacc6f --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.cpp @@ -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(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(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(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("

%1

").arg(element.text())); + } break; + case TagXML::Text: { + currentQuestion.append(QString(R"( +

+ + + %2 + + +

+ )") + .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(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 &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(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(); +} diff --git a/SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.h b/SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.h new file mode 100644 index 0000000..b674109 --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.h @@ -0,0 +1,71 @@ +#ifndef TESTING_WIDGET_H +#define TESTING_WIDGET_H + +#include "ui_testingWidget.h" + +#include + +#include +#include +#include + +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> 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 diff --git a/SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.cpp b/SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.cpp new file mode 100644 index 0000000..7fd8842 --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.cpp @@ -0,0 +1,112 @@ +#include "textBrowserWidget.h" + +TextBrowserWidget::TextBrowserWidget(const QString &xmlFile, QWidget *pWidget) + : QWidget(pWidget) +{ + setupUi(dynamic_cast(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]); + } +} diff --git a/SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.h b/SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.h new file mode 100644 index 0000000..3dbe0c4 --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.h @@ -0,0 +1,50 @@ +#ifndef THEORY_WIDGET_H +#define THEORY_WIDGET_H + +#include "ui_textBrowserWidget.h" + +#include +#include +#include + +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 diff --git a/SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.cpp b/SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.cpp new file mode 100644 index 0000000..97e1fe5 --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.cpp @@ -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 newData; + for(const auto &value : std::initializer_list>{ + {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( 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(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(); + }); +} diff --git a/SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.h b/SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.h new file mode 100644 index 0000000..ded194d --- /dev/null +++ b/SourceCode/UserInterface/ClassesUI/Windows/MainWindow/mainWindow.h @@ -0,0 +1,29 @@ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#include "ui_mainWindow.h" + +#include +#include +#include +#include + +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 diff --git a/SourceCode/UserInterface/FilesUI/demonstrationWidget.ui b/SourceCode/UserInterface/FilesUI/demonstrationWidget.ui new file mode 100644 index 0000000..2b163f1 --- /dev/null +++ b/SourceCode/UserInterface/FilesUI/demonstrationWidget.ui @@ -0,0 +1,972 @@ + + + DemonstrationWidget + + + + 0 + 0 + 805 + 460 + + + + + 0 + 0 + + + + Form + + + + + 0 + 0 + 0 + 0 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Plain + + + 1 + + + + + + + 0 + 0 + + + + Progress of inserting elements: + + + + + + + true + + + + 0 + 0 + + + + + 50 + false + false + false + false + true + + + + 100000 + + + 0 + + + + + + + + + 501 + 0 + 250 + 250 + + + + + 0 + 0 + + + + + 250 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + + + 0 + 0 + 234 + 1020 + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + Resolution of collisions + + + + + + true + + + + 0 + 0 + + + + Chains + + + true + + + + + + + Open addressing + + + + + + + + + + + 0 + 0 + + + + Function + + + + + + Equivalent + + + true + + + + + + + Standart + + + false + + + + + + + + 0 + 0 + + + + FNV1a 32 bit + + + + + + + + + + false + + + + 0 + 0 + + + + Algorithm + + + + + + + 0 + 0 + + + + Linear probing + + + true + + + + + + + + 0 + 0 + + + + Pseudorandom probing + + + + + + + + 0 + 0 + + + + Quadratic probing + + + + + + + + 0 + 0 + + + + Double hashing + + + + + + + + + + + 0 + 0 + + + + Additional input data + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Coefficient of the first family function: + + + true + + + m_sbFirstInputData + + + + + + + true + + + + 0 + 0 + + + + 100000000 + + + 1 + + + QAbstractSpinBox::DefaultStepType + + + 0 + + + 16 + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Coefficient of the second family function: + + + true + + + m_sbSecondInputData + + + + + + + true + + + + 0 + 0 + + + + 100000000 + + + 1 + + + QAbstractSpinBox::DefaultStepType + + + 1 + + + 16 + + + + + + + + + + + + + + 0 + 0 + + + + Hash table + + + + + + + 0 + 0 + + + + Bucket quantity: + + + m_sbBucketQuantity + + + + + + + + 0 + 0 + + + + 1 + + + 10000 + + + 1 + + + + + + + + 0 + 0 + + + + Reset + + + + + + + + 0 + 0 + + + + Apply + + + + + + + false + + + + 0 + 0 + + + + Statistics + + + + + + + + + + false + + + + 0 + 0 + + + + Load table + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + From: + + + m_leFrom + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + Quantity: + + + m_sbQuantity + + + + + + + + 0 + 0 + + + + 1 + + + 10000 + + + 1 + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Qt::ImhNone + + + 4 + + + + + + + + + + 0 + 0 + + + + Make items + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + Value: + + + m_leInsert + + + + + + + + 0 + 0 + + + + 4 + + + + + + + + + + 0 + 0 + + + + Insert + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + + Find free + + + + + + + false + + + Stop + + + + + + + + + Focus + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Plain + + + 1 + + + 0 + + + + + + + 0 + 0 + + + + Output messages: + + + + + + + + 0 + 0 + + + + + Consolas + 10 + 75 + true + + + + Qt::DefaultContextMenu + + + false + + + + + + Qt::ImhNone + + + QFrame::Box + + + QFrame::Plain + + + 1 + + + 0 + + + + + + Qt::RichText + + + true + + + 0 + + + Qt::NoTextInteraction + + + + + + + + + + + + + 0 + 0 + 500 + 250 + + + + + 0 + 0 + + + + + 300 + 200 + + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + Qt::SolidLine + + + false + + + false + + + + + m_tableView + m_rightScrollArea + m_rbChains + m_rbOpenAdressing + m_rbEquivalent + m_rbStandart + m_rbFNV1a32bit + m_rbLinearProbing + m_rbPseudorandomProbing + m_rbQuadraticProbing + m_rbDoubleHashing + m_sbFirstInputData + m_sbSecondInputData + m_sbBucketQuantity + m_pbReset + m_pbApply + m_pbStatistics + m_leFrom + m_sbQuantity + m_pbMakeItems + m_leInsert + m_pbInsert + m_pbFindFree + m_pbStop + m_pbFocus + + + + + m_rbChains + clicked(bool) + m_gbAlgorithm + setDisabled(bool) + + + 861 + 45 + + + 858 + 225 + + + + + m_rbOpenAdressing + clicked(bool) + m_gbAlgorithm + setEnabled(bool) + + + 887 + 78 + + + 892 + 219 + + + + + diff --git a/SourceCode/UserInterface/FilesUI/mainWindow.ui b/SourceCode/UserInterface/FilesUI/mainWindow.ui new file mode 100644 index 0000000..c2c2b40 --- /dev/null +++ b/SourceCode/UserInterface/FilesUI/mainWindow.ui @@ -0,0 +1,261 @@ + + + MainWindow + + + + 0 + 0 + 1093 + 548 + + + + Hash tables + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Plain + + + 1 + + + 0 + + + + + + + + 0 + 0 + + + + 0 + + + + Theory + + + + + Demonstration + + + + + + + + + true + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Exit + + + + + + + + + + + 0 + 0 + 1093 + 20 + + + + + 0 + 0 + + + + + &Help + + + + + + + + &View + + + + + + + + + + + &User session + + + User session + + + Ctrl+N + + + + + &Open... + + + Ctrl+O + + + + + true + + + &Save + + + Ctrl+S + + + + + Save &As... + + + + + &Options... + + + + + &Manual + + + Ctrl+H + + + + + About this &program + + + Ctrl+A + + + + + &Theory + + + Ctrl+T + + + + + &Practice + + + Ctrl+P + + + + + &General + + + + + false + + + &Current + + + + + + TestingWidget + QWidget +
SourceCode/UserInterface/ClassesUI/Widgets/Testing/testingWidget.h
+ 1 +
+ + DemonstrationWidget + QWidget +
SourceCode/UserInterface/ClassesUI/Widgets/Demonstration/demonstrationWidget.h
+ 1 +
+ + TextBrowserWidget + QWidget +
SourceCode/UserInterface/ClassesUI/Widgets/TextBrowser/textBrowserWidget.h
+ 1 +
+
+ + m_tabWidget + m_exitButton + + + + + m_exitButton + clicked() + MainWindow + close() + + + 1044 + 503 + + + 935 + 524 + + + + +
diff --git a/SourceCode/UserInterface/FilesUI/testingWidget.ui b/SourceCode/UserInterface/FilesUI/testingWidget.ui new file mode 100644 index 0000000..43f26f3 --- /dev/null +++ b/SourceCode/UserInterface/FilesUI/testingWidget.ui @@ -0,0 +1,381 @@ + + + TestingWidget + + + + 0 + 0 + 716 + 545 + + + + Form + + + + + + + + <html><head/><body><p><span style=" font-size:10pt;">Testing window:</span></p></body></html> + + + m_testingTextBrowser + + + + + + + + 0 + 0 + + + + + 16 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 1 + + + 0 + + + + + + + Choose your answer: + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + CheckBox + + + + + + + + + + + Enter an integer number: + + + m_sbInteger + + + + + + + + + + + + + + Enter a fractional number: + + + m_sbInteger + + + + + + + + + + + + + + + + Confirm answer + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 7 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Choosing a topic + + + + + + Everything + + + true + + + + + + + Discrete mathematics + + + false + + + + + + + Hash function + + + + + + + Hash table + + + + + + + Algorithm + + + + + + + + + + Choice of difficulty + + + + + + Everything + + + true + + + + + + + Easy + + + + + + + Medium + + + + + + + Hard + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Start testing + + + + + + + false + + + Save && Stop testing + + + + + + + + + m_testingTextBrowser + m_pbStart + m_pbStop + m_sbInteger + m_pbConfirm + m_rbAllTopics + m_rbDiscreteMathematics + m_rbHashFunction + m_rbHashTable + m_rbAlgorithm + m_rbAllDifficulties + m_rbEasy + m_rbMedium + m_rbHard + m_sbDouble + + + + diff --git a/SourceCode/UserInterface/FilesUI/textBrowserWidget.ui b/SourceCode/UserInterface/FilesUI/textBrowserWidget.ui new file mode 100644 index 0000000..00a05c7 --- /dev/null +++ b/SourceCode/UserInterface/FilesUI/textBrowserWidget.ui @@ -0,0 +1,91 @@ + + + TextBrowserWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Previous + + + + + + + false + + + Main + + + + + + + false + + + Next + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Times New Roman + 16 + + + + + + + + + diff --git a/SourceCode/main.cpp b/SourceCode/main.cpp new file mode 100644 index 0000000..531ee0d --- /dev/null +++ b/SourceCode/main.cpp @@ -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(); +} diff --git a/SourceCode/resources.qrc b/SourceCode/resources.qrc new file mode 100644 index 0000000..bb6e571 --- /dev/null +++ b/SourceCode/resources.qrc @@ -0,0 +1,17 @@ + + + ManualHTML/info.xml + ManualHTML/Pages/demonstration.html + ManualHTML/Pages/main.html + ManualHTML/Pages/menubar.html + ManualHTML/Pages/theory.html + ManualHTML/Pages/theoryPage.html + ManualHTML/Pages/testingPage.html + ManualHTML/Images/demonstration.png + ManualHTML/Images/menubarFirst.png + ManualHTML/Images/menubarSecond.png + ManualHTML/Images/testingPage.png + ManualHTML/Images/theory.png + ManualHTML/Images/theoryPage.png + + diff --git a/TheoryHTML/Images/2.1.png b/TheoryHTML/Images/2.1.png new file mode 100644 index 0000000..9192e82 Binary files /dev/null and b/TheoryHTML/Images/2.1.png differ diff --git a/TheoryHTML/Images/2.2.png b/TheoryHTML/Images/2.2.png new file mode 100644 index 0000000..1eb085c Binary files /dev/null and b/TheoryHTML/Images/2.2.png differ diff --git a/TheoryHTML/Images/6.1.png b/TheoryHTML/Images/6.1.png new file mode 100644 index 0000000..c4b92ab Binary files /dev/null and b/TheoryHTML/Images/6.1.png differ diff --git a/TheoryHTML/Images/7.1.png b/TheoryHTML/Images/7.1.png new file mode 100644 index 0000000..c77346f Binary files /dev/null and b/TheoryHTML/Images/7.1.png differ diff --git a/TheoryHTML/Images/7.2.png b/TheoryHTML/Images/7.2.png new file mode 100644 index 0000000..a5e9f03 Binary files /dev/null and b/TheoryHTML/Images/7.2.png differ diff --git a/TheoryHTML/Images/8.1.png b/TheoryHTML/Images/8.1.png new file mode 100644 index 0000000..5343bb5 Binary files /dev/null and b/TheoryHTML/Images/8.1.png differ diff --git a/TheoryHTML/Pages/analysis.html b/TheoryHTML/Pages/analysis.html new file mode 100644 index 0000000..7c97a8b --- /dev/null +++ b/TheoryHTML/Pages/analysis.html @@ -0,0 +1,139 @@ + + + + + + + Страница 8 + + +

+ Страница 8 +

+
+

Анализ хеш-таблиц и алгоритмов поиска

+

Общее описание [2, c. 285-318]

+

+ Хеш-таблица представляет собой эффективную структуру данных для реализации + словарей. Хотя на поиск элемента в хеш-таблице может в наихудшем случае + потребоваться столько же времени, сколько на поиск в связанном списке, а + именно - Θ(n), на практике хеширование исключительно + эффективно. При вполне обоснованных допущениях среднее время поиска + элемента в хеш-таблице составляет O(1). +

+

+ Таблица с прямой адресацией, как хеш-таблица +

+

+ Хеш-таблица обобщает обычный массив. Возможность прямой индексации + элементов обычного массива обеспечивает доступ к произвольной позиции в + массиве за время O(1). Хеширование представляет собой исключительно + эффективную и практичную технологию: в среднем все базовые словарные + операции выполняются за время O(1). +

+

+ Недостаток прямой адресации очевиден: если совокупность ключей + U велика, хранение таблицы T размером + |U| непрактично, а то и вовсе невозможно - в зависимости от + количества доступной памяти и размера совокупности ключей. Кроме того, + множество K реально сохранённых ключей может быть мало по сравнению + с совокупностью ключей U, а в этом случае память, выделенная для + таблицы T, в основном расходуется напрасно. +

+

+ Когда множество K хранящихся в словаре ключей гораздо меньше + совокупности возможных ключей U, для хеш-таблицы требуется + существенно меньше места, чем для таблицы с прямой адресацией1. + Точнее говоря, требования к памяти могут быть снижены + до Θ(/K/), при этом время поиска элемента в хеш-таблице + останется равным O(1). Нужно только заметить, что это граница + времени поиска в среднем случае, в то время как в случае таблицы с прямой + адресацией эта граница справедлива для наихудшего случая. +

+

Хеш-таблица с прямым связыванием

+

+ Время, необходимое для вставки в наихудшем случае, равно O(1). + Процедура вставки выполняется очень быстро, в частности, потому, что + предполагается, что вставляемый элемент отсутствует в таблице. Время + работы поиска в наихудшем случае пропорционально длине списка. Удаление + элемента может быть выполнено за время O(1) при использовании + дважды связанных списков. +

+

+ Пусть у нас есть хеш-таблица T с m ячейками, в которых хранятся n + элементов. В наихудшем случае хеширование с цепочками ведёт себя крайне + неприятно: все n ключей хешированы в одну и ту же ячейку, создав список + длиной n. Таким образом, время поиска в наихудшем случае равно Θ(n) + плюс время вычисления хеш-функции, что ничуть не лучше, чем в случае + использования связного списка для хранения всех n элементов. Понятно, что + использование хеш-таблиц в наихудшем случае совершенно бессмысленно. +

+

Теорема 8.12

+

+ В хеш-таблице с разрешением коллизий методом цепочек время неудачного + поиска в среднем случае в предположении простого равномерного хеширования + составляет Θ(1 + a). +

+

Теорема 8.2

+

+ В хеш-таблице с разрешением коллизий методом цепочек время успешного + поиска в среднем случае в предположении простого равномерного хеширования + в среднем равно Θ(1 + a). +

+

+ Если количество ячеек в хеш-таблице как минимум пропорционально количеству + элементов, хранящихся в ней, то n = O(m) и, следовательно, + коэффициент заполнения равен n/m = O(m)/m = O(1). Таким + образом, поиск элемента в хеш-таблице в среднем требует постоянного + времени. Поскольку в худшем случае вставка элемента в хеш-таблицу занимает + O(1) времени (как и удаление элемента при использовании дважды связанных + списков), можно сделать вывод, что все словарные операции в хеш-таблице в + среднем выполняются за время O(1). +

+

Хеш-таблица с открытой адресацией

+

+ Мы проанализируем математическое ожидание количества исследований для + хеширования с открытой адресацией в предположении равномерного хеширования + и начнём с анализа количества исследований в случае неудачного поиска. +

+

Теорема 8.3

+

+ Математическое ожидание количества исследований при неудачном поиске в хеш + таблице с открытой адресацией и коэффициентом заполнения + a = n/m < 1 в предположении равномерного хеширования не + превышает 1/(1-a). +

+

Следствие 8.1

+

+ Вставка элемента в хеш-таблицу с открытой адресацией и коэффициентом + заполнения a в предположении равномерного хеширования требует в среднем не + более 1/(1-a) исследований. +

+

Теорема 8.4

+

+ Математическое ожидание количества исследований при удачном поиске в + хеш-таблице с открытой адресацией и коэффициентом заполнения a < 1, в + предположении равномерного хеширования и равновероятного поиска любого из + ключей не превышает +

+
+ +
+

 

+
+

+ 1В данном контексте автор, упоминая таблицу с прямой + адресацией, не применяет термин хеш, так как, предположительно, в примере + оригинальной книги не используется хеш-функция для операций поиска + элемента или все операции вставки элемента являются инъективными и не + нуждаются в решении проблем коллизий. +

+

+ 2Все доказательства теорем представлены в книге автора с целью + описания минимума методического материала +

+ + diff --git a/TheoryHTML/Pages/binaryRelationship.html b/TheoryHTML/Pages/binaryRelationship.html new file mode 100644 index 0000000..37fe6c4 --- /dev/null +++ b/TheoryHTML/Pages/binaryRelationship.html @@ -0,0 +1,149 @@ + + + + + + + Страница 2 + + +

+ Страница 2 +

+
+

Дискретная математика

+

+ Функция, как тип бинарных отношений [4, c. 96-100] +

+

+ Отношения эффективно применяются для описания связей между парами + элементов, выбранных из двух множеств А и В. Функции — + это частный случай бинарных отношений, на которые наложены дополнительные + ограничения. +

+

+ Функцией из множества А в множество В называется бинарное + отношение, при котором каждый элемент множества А связан с + единственным элементом множества В. Другими словами, для каждого + a ∈ A существует ровно одна пара из отношения + вида (а, b). +

+

+ В графических терминах функция описывается таким графом, у которого из + каждой вершины, изображающей элементы множества A, выходит + ровно одна стрелка. +

+

+ Например, на рис. 2.1 изображен граф, представляющий функцию из множества + {а, b, с} в {1, 2}, состоящую из пар (а, 1), + (b, 1) и (с, 2). +

+ +

Рисунок 2.1 - функция из множества

+
+

+

+ Пусть f - функция из множества A в множество B. + Поскольку для каждого x ∈ A существует единственным + образом определённый y∈ B, такой, что + (x, y) ∈ f, мы будем писать: y = f(x), и говорить, что + функция f отображает множество A в множество + B, а f(x) называть образом x при отображении + f или значением f, соответствующим аргументу + x. +

+

+ Кроме того, можно написать f : A → B, чтобы + подчеркнуть, что функция f переводит элементы из A в + элементы из B. Множество A принято называть + областью определения, а B - + областью значений функции1 f. +

+

+ Для уточнения подмножества элементов, в которые переводятся элементы из + A функцией f, вводят понятие "образ" или + "множество значений функции". А именно, + множеством значений функции f называется подмножество в + B, состоящее из образов всех + элементов x ∈ A. Оно обозначается символом + f(A) и формально определяется так: +

+

+ f(A) = {f(x) : x ∈ A} +

+

 

+

Свойства функций

+

+ Пусть f : A → B - функция. Мы будем называть её + инъективной или инъекцией, или взаимно однозначной, + если +

+

+ f(a1) = f(a2) ⇒ a1 = a2 +

+

+ для всех a1, a∈ A. +

+

+ Это определение логически эквивалентно тому, что +

+

+ a≠ a2 ⇒ f(a1) ≠ f(a2), +

+

+ т.е. у инъективной функции нет повторяющихся значений. Иными словами, + разные входные данные дают различные выходные данные. +

+

+ Будем называть функцию f сюръективной или сюръекцией, + или функцией "на", если множество её значений совпадает с + областью значений. Это означает, что для каждого + b ∈ B найдётся такой a ∈ A, + что b = f(a). Таким образом, каждый элемент области значений + является образом какого-то элемента из области определения f . +

+

+ Мы называем f биективной функцией или просто + биекцией, если она как инъективна, так и сюръективна. +

+

 

+

На рисунке 2.2 представлены различные виды функций.

+
+ +

Рисунок 2.2 - различные виды функций

+
+

Описание:

+
    +
  • + В случае (a) функция не инъективна, поскольку значение 1 соответствует + как a, так и b. Она не является и сюръективной, ввиду того, что в + элемент 2 ничего не переходит. +
  • +
  • + В случае (б) функция инъективна, так как не имеет повторяющихся + значений. Она же и сюръективна, поскольку множество ее значений + совпадает со всей областью значений. +
  • +
  • + Значение 1 эта функция в случае (в) принимает как на а, так и на Ь. + Следовательно, она не инъективна. Однако данная функция сюръективна, + поскольку в ее множество значений входят все элементы области значений. +
  • +
  • Последняя функция в случае (г) инъективна, но не сюръективна.
  • +
  • Только в случае (б) мы имеем биекцию.
  • +
+
+

+ 1Довольно часто говорят, что функция f определена или задана на + множестве A со значениями в множестве B. - Прим. перев. +

+ + diff --git a/TheoryHTML/Pages/chainMethod.html b/TheoryHTML/Pages/chainMethod.html new file mode 100644 index 0000000..c514c5f --- /dev/null +++ b/TheoryHTML/Pages/chainMethod.html @@ -0,0 +1,56 @@ + + + + + + + Страница 6 + + +

+ Страница 6 +

+
+

Решение проблем коллизий

+

Метод цепочек или прямое связывание [5, c. 170-171]

+

+ В хеш таблице с прямым связыванием (рис 6.1) значения ключей (бункеры) + хранятся в специальных наборах записей, называемых блоками. Каждый + из них является вершиной связного списка, в котором находятся привязанные + к блоку элементы. +

+
+ +

Рисунок 6.1 - хеш-таблица с прямым связыванием

+
+

+ Поиск элементов в хеш-таблице пройдёт быстрее, если связанные списки будут + содержать ключи в отсортированном порядке. В этом случае алгоритм сделает + вывод, что ключа нет, если дойдёт до значения больше ключевого и не станет + просматривать список до конца. Теоретически время его работы составит + O(N/B), но на практике оно будет немного меньше. +

+

+ Чтобы найти нужный элемент, программе необходимо хешировать ключ и + определить, в каком из блоков он может содержаться, а затем двигаться по + связному списку до тех пор, пока не будет достигнут его конец или не + обнаружится искомое. Если вы доберётесь до конца списка, значит, + запрашиваемого элемента в хеш-таблице нет. Как и в случае с добавлением + элемента, предстоит выполнить O(N/B) шагов. +

+

+ Хеш-таблица с прямым связыванием может расширяться и сжиматься1 + по мере необходимости, поэтому вам не нужно специально изменять её размер. + Однако если связные списки станут слишком длинными, поиск и удаление + элементов займут много времени. В этом случае вам понадобится увеличить + таблицу, чтобы создать больше блоков. Поскольку при рехешировании таблицы + не надо проводить поиск дубликатов до конца связного списка в каждом + блоке, полностью справиться с операцией можно за время O(N). +

+
+

+ 1Удаление элементов в данном методическом материале + рассматриваться не будет +

+ + diff --git a/TheoryHTML/Pages/dirichletPrinciple.html b/TheoryHTML/Pages/dirichletPrinciple.html new file mode 100644 index 0000000..644bfec --- /dev/null +++ b/TheoryHTML/Pages/dirichletPrinciple.html @@ -0,0 +1,52 @@ + + + + + + + Страница 3 + + +

+ Страница 3 +

+
+

Дискретная математика

+

Принцип Дирихле [4, c. 105]

+

+ Пусть f : A → B - + функция, причём как A, так и B - конечные множества. + Предположим, что A состоит из n элементов: + a1, a2,..., an. Принцип Дирихле гласит, что если |A| > |B|, то по крайней + мере одно значение f встретится более одного раза1. + Проще говоря, найдётся пара элементов + a aj, для которых f(ai) = f(aj). +

+

+ Чтобы убедиться в истинности принципа, предположим, что для любой пары + разных индексов + ≠ j мы имеем: + f(ai≠ f(aj). Тогда множество B содержит по крайней + мере n различных элементов: + f(a1), f(a2),..., f(an). И уж во + всяком случае, |B| ≥ n, что противоречит + предположению: n = |A| > |B|. Следовательно, есть хотя бы два + разных элемента + ai, a∈ A, для которых f(ai) = f(aj). +

+
+

+ 1Допуская некоторую вольность, принцип Дирихле можно + переформулировать в легко запоминающейся форме: нельзя рассадить 10 зайцев + в 9 клеток так, чтобы в каждой клетке сидел один заяц - Прим. перев. +

+ + diff --git a/TheoryHTML/Pages/hashFunction.html b/TheoryHTML/Pages/hashFunction.html new file mode 100644 index 0000000..c50ec6a --- /dev/null +++ b/TheoryHTML/Pages/hashFunction.html @@ -0,0 +1,102 @@ + + + + + + + Страница 4 + + +

+ Страница 4 +

+
+

Хеш-фукнция

+

Свойства хеш-функции

+

+ Хеш-функция (англ. hash function от hash — + «превращать в фарш»), или функция свёртки — + функция, осуществляющая преобразование массива входных данных + произвольной длины в выходную битовую строку установленной + длины, выполняемое определённым алгоритмом. Преобразование, + производимое хеш-функцией, называется хешированием. Исходные данные + называются входным массивом, «ключом» или + «сообщением». Результат преобразования называется + «хешем», «хеш-кодом», «хеш-суммой», + «сводкой сообщения».[7] +

+

Свойства хеш-функции:

+
    +
  • Должна обладать свойствами функции.
  • +
  • + Не должна обязательно являться инъективной или сюръективной. +
  • +
+

Определения :

+
    +
  • + Если известна область определения и можно задать отображение в область + значений, мощность которого будет больше или эквивалентна мощности + области определения, при котором хеш-функция будет являться + инъективной, то такая хеш-функция будет являться идеальной хеш-функцией. +
  • +
  • + Если область определения неизвестна и можно задать отображение в + область значений, мощность которого будет больше или эквивалентна + мощности области определения, при котором хеш-функция будет + являться инъективной, то такая хеш-функция будет являться динамической идеальной хеш-функцией. +
  • +
  • + Если известна область определения и можно задать отображение в + область значений, мощность которого будет эквивалентна мощности + области определения, при котором хеш-функция будет + являться биективной, то такая хеш-функция будет являться + минимальной идеальной хеш-функцией. +
  • +
  • + Хеш-функция является k-совершенной хеш-функцией, + если область определения неизвестна и можно задать отображение в + область значений, любой элемент которого будет обладать не более чем k + отношениями. +
  • +
+
+ Существует несколько терминов, связанных с хеш-функцией: +
+
+
Хеш
+
+ элемент области значений, соотнесённый с заранее известным элементом из + области определения. +
+
Хеширование
+
это процесс получения хеша.
+
Коллизия
+
+ ситуация, при которой нарушается условие инъективности хеш-функции. +
+
+

+ Производительность хеширования в среднем случае зависит от того, насколько + хорошо хеш-функция приближена к биективной k-совершенной хеш-функции, где + разность количества отношейний любых двух элементов области значений + стремиться к нулю. Другими словами, каждый элемент области значений + обладает минимально возможным количеством отношений. Данное хеширование + автор книги [2, с. 291] Томас Кормен называет + простым равномерным хешированием. +

+
+ Существует множество разнообразных хеш-функций, алгоритмы которых + применяются в различных ситуациях, например, когда требуется скорость + вычисления хеш-значения, но с повышенным шансом появления коллизии или + наоборот. +
+ + diff --git a/TheoryHTML/Pages/hashTable.html b/TheoryHTML/Pages/hashTable.html new file mode 100644 index 0000000..39ad099 --- /dev/null +++ b/TheoryHTML/Pages/hashTable.html @@ -0,0 +1,120 @@ + + + + + + + Страница 5 + + +

+ Страница 5 +

+
+

Хеш-таблица

+

Свойства хеш-таблицы

+

+ Хеш-таблицы являются одним из способов хранения данных при помощи + ассоциативного массива [12]. +

+

+ Хеш-таблицы решают несколько главных проблем при оперировании с данными: +

+
    +
  • + Создание отношения (связи) между ключом и абсолютно любым + значением. +
  • +
  • Решение проблем коллизий.
  • +
+

+ Для большего понимания материала требуется ознакомиться с новыми терминами + хеш-таблицы: +

+
+
Ключ или сообщение
+
использующийся хеш-таблицей произвольный элемент из области определения хеш-функции.
+
Бункер или корзина
+
произвольный элемент, который хранит данные хеш-таблицы.
+
Коэффициент заполнения
+
+ отношение количества заполненных бункеров на количество возможных ключей. +
+
+

+ Исходя из определений, бункер - это условная единица хранимой информации в + хеш-таблице (ассоциативном массиве данных). +

+

+ Решение первой проблемы. Хеш-функции в хеш-таблице, нужны по причине получения хеша в процессе + хеширования ключа, однако хеш - значение абстрактное, так как невозможно + создать такой алгоритм, который бы выдавал хеш, как набор данных, + используемый в процессе работы программы или это очень сложно.
+ Для большего понимания нужно вспомнить пример о "продавце в маленьком магазинчике", где "помощница" + абстрагирует понятие хеш-функции, которая выдавала для каждого товара + конкретную цену, что возможно, но трудозатратно.
+ Для этого требуется хеш-функция, где хеш является универсальным + идентификатором конкретного бункера, в котором располагается необходимый + пользователю набор данных. +

+

+ Томас Кормен говорит в книге [2, c.288], что цель хеш-функции состоит в + том, чтобы уменьшить рабочий диапазон индексов массива - размер массива + может быть равен соотносительно намного меньшему значению, чем мощность + множества всех существующих значений ключей, которые могут потенциально + использоваться в процессе работы программы. +

+

+ Из этого можно выделить несколько особенностей хеш-таблиц: +

+
    +
  • + Каждый бункер имеет в качестве уникального идентификатора + хеш-значение +
  • +
  • + Каждый ключ гарантированно имеет связь только с одним бункером. +
  • +
  • + Количество бункеров относительно количества ключей сильно ограниченно. +
  • +
  • + От хеш-функции зависит коэффициент заполнения. +
  • +
  • + По принципу Дирихле коллизия неизбежна в ситуации, когда количество ключей больше, чем количество бункеров. +
  • +
+

+ Решение второй проблемы. Хеш-таблицы используют в качестве + алгоритма поиска элемента контейнера (бункера) хеш-функцию, которая по + принципу Дирихле гарантированно создаст коллизии в ситуации, когда + количество ключей больше, чем количество бункеров, а обычно так бывает + всегда. +

+

+ Хеш-таблицы решают данную проблему двумя способами:  +

+
    +
  • Метод цепочек или прямым связыванием.
  • +
  • Открытой адресацией.
  • +
+ + diff --git a/TheoryHTML/Pages/introduction.html b/TheoryHTML/Pages/introduction.html new file mode 100644 index 0000000..1ae6bce --- /dev/null +++ b/TheoryHTML/Pages/introduction.html @@ -0,0 +1,116 @@ + + + + + + + Страница 1 + + +

+ Страница 1 +

+
+

Введение

+

Гардероб [3, с. 393-394]

+

+ Когда вы сдаете в гардероб пальто или сумку, вам выдают номерок. Когда же + вы собираетесь покинуть помещение, вы отдаете номерок, и вам возвращают + ваше пальто или сумку. +

+

+ Если вдуматься, какую задачку решает данный процесс, можно увидеть, что + это задача о поиске и нахождении объекта. Ваше пальто — это объект, + который вы передаете гардеробщику; пальто сначала привязывают к + определенному номерку, а затем возвращают вам. Метод работает за счет + того, что в гардеробе находятся ряды пронумерованных вешалок для одежды и + пронумерованные отделения для сумок. Вашему номерку соответствует + определенная вешалка или определенное отделение. Гардеробщик же отвечает + за то, чтобы разместить ваш объект в нужном месте и чтобы забрать его с + помощью отданного вами номерка. +

+

+ Когда речь идет о поиске, люди чаще всего представляют себе, что нужно + перебирать вещи до тех пор, пока не найдется нужная; процесс становится + проще, если вещи отсортированы так, что мы можем искать среди них более + слаженно. Гардероб же показывает, что есть и другой способ: присвоить вещи + адрес, где она будет располагаться, и затем сразу достать ее из указанного + места. В гардеробе адрес указан на номерках, и гардеробщик на самом деле + ищет не ваши вещи: он смотрит на номерок, на адрес и идет к указанной + вешалке или отделению с вашими вещами. +

+

+ Весь метод в целом можно назвать определением местонахождения + без поиска: мы не ищем объект, а получаем адрес места, где он будет + храниться. Соотносим объект с адресом, а затем, когда хотим найти объект, + мы идем прямиком к нужному месту. +

+

+ Теперь рассмотрим данный метод с точки зрения компьютерного мира, где наши + объекты представлены в виде записей, содержащих атрибуты. Мы хотим уметь + переходить напрямую от записи к адресу, по которому она размещена; + адресом будет число, соответствующее области в компьютерной памяти. + Главная загвоздка в такой задачке — то, как соотнести адрес с + элементом. Нам нужен быстрый и надежный способ, и мы не можем положиться + на какого-либо посредника. Когда мы ищем запись, мы ищем ее по одному или + большему числу атрибутов, которые формируют ключ записи, поэтому нам нужен + метод получения адреса из ключа записи. Так как адрес — это число, + нам нужен способ, который перенесет нас от ключей к числам. Иными словами, + мы нуждаемся в функции, скажем, f(K), которая возьмет ключ K записи + R и вернет значение a = f(K). Значение a представляет собой адрес, + где будет храниться запись, мы идем по нему и оставляем там нашу запись. + Каждый раз, когда нам требуется достать нашу запись с помощью ключа, мы + снова прибегаем к функции f(K), которая вернет то же адресное + значение a, откуда мы и заберем нашу запись. Функция должна быть быстрой и + достаточно скоро находить нужный адрес: как минимум, не дольше, чем поиск + по записям до тех пор, пока не найдется та, которую мы ищем. В противном + случае толку от такой функции никакого. Если же мы в самом деле + обзаведемся такой функцией, то разрешим нашу задачку с местоположением + новым способом: не мы будем искать элемент, а сам элемент расскажет нам, + где его найти: расскажет с помощью нашей функции. +

+

Продавец

+

+ Так же стоит привести введение в теоретический материал, описанное автором + книги [1, c. 100-101], где описывается пример с "продавцом в + маленьком магазинчике". +

+

+ В ситуации, когда клиент покупает + у продавца товар необходимо определить ценность предмета. + Изначально стоит отметить, что цены в магазинах на один и тот же товар + всегда одинаковый в один момент времени, поэтому необходимо хранить + информацию о ценах, например, в книге, однако данный метод оперирования + информацией будет весьма утомителен и ужасно неэффективен. Для + решения этой проблемы продавец нанимает помощницу, которая + безошибочно определяет цену на товар, если посмотрит на него или узнает + его название. +

+

+ Автор абстрактно описывает проблему с упорядоченным контейнером данных, + где может потребоваться простой поиск, алгоритм которого обладает линейной + сложностью. В данном примере контейнер является хранилищем элементов, + каждый из которых может повторяться, но обязан иметь только один + уникальный идентификатор. Можно с уверенностью выделить две проблемы, от + которых можно избавиться в идеальных условиях — затраты на + хранение элементов и поиск каждого из них при помощи уникального + идентификатора. В приоритете необходимо выполнять успешный поиск элемента, + алгоритм которого будет выполняться за константное время. +

+

+ Решением является использование функции [4, c. 96] из множества A в + множество B. Данная функция описывает бинарное отношение, при + котором каждый элемент множества А связан с + единственным элементом множества B.  Данная функция в + программировании имеет название хеш-функция. Избавиться от необходимости в + хранении множеств элементов, чтобы сохранялась возможность определять + новые бинарные отношения, не изменяя другие очень сложно, однако это + возможно. Обычно, когда известны все элементы множества А и все + элементы множества B, реализуют функцию, при которой любой элемент + множества А имеет одно отношение с любым элементом из множества + B. Например, данную функцию можно применить в примере с продавцом и + помощницей, если каталог товаров не изменяется, но цены на разные товары + могут совпадать. +

+ + diff --git a/TheoryHTML/Pages/main.html b/TheoryHTML/Pages/main.html new file mode 100644 index 0000000..a53dde1 --- /dev/null +++ b/TheoryHTML/Pages/main.html @@ -0,0 +1,170 @@ + + + + + + + Теоретический материал + + +

Теоретический материал

+ +

+ Необходимый минимум теории по теме
+ "Алгоритм вставки в хеш-таблицу" +

+ +

Описание страницы:

+ +

+ Главная страница, предоставляющая пользователю быстрый и удобный поиск + нужного разбитого по темам материала.
+ Каждый элемент списка оглавления является гиперссылкой при нажатии на + которую можно мгновенно перейти к необходимому разделу информации.
+ Предоставленный пользователю теоретический материал был взят из списка + использованной литературы в конце данной страницы. +

+ +

Оглавление:

+ +
    +
  1. + Введение. +
  2. +
  3. Дискретная математика: + +
  4. +
  5. + Хеш-функция. +
  6. + +
  7. + Хеш-таблица. +
  8. +
  9. Решение проблем коллизий: + +
  10. +
  11. Анализ хеш-таблиц и алгоритмов поиска.
  12. +
+ +

Список использованной литературы

+ +
    +
  1. + Бхаргава, А. Грокаем алгоритмы. Иллюстрированное пособие для + программистов и любопытствующих / Адитья Бхаргава. — СПб. : + Питер, 2017. - 288 с. : ил. — (Библиотека программиста). +
  2. +
  3. + Кормен, Т. Х. Алгоритмы: построение и анализ, 3-е изд / Томас Кормен ; пер. с англ. — Москва : + ООО "И. Д. Вильямс", 2013. — 1328 с. : ил. — Парал. тит. англ. +
  4. +
  5. + Луридас, П. Алгоритмы для начинающих : теория и практика для + разработчика / Панос Луридас ; пер. с англ. Е.М. Егоровой. — Москва : + Эксмо, 2020. — 608 с. — (Мировой компьютерный бестселлер). +
  6. +
  7. + Хаггарти, Р. Дискретная математика для программистов, 2-е издание, исправленное / Род + Стивенс. — Москва : ТЕХНОСФЕРА, 2019. — 400 c. +
  8. +
  9. + Стивенс, Р. Алгоритмы. Теория и практическое применение / Род + Стивенс. — Москва : Издательство "Э", 2016. — 544 c. — (Мировой + компьютерный бестселлер). +
  10. +
  11. + Хеш-таблица [Электронный ресурс]: Википедия. Свободная энциклопедия. + — URL: https://ru.wikipedia.org/wiki/Хеш-таблица (дата обращения: 03.11.2021). +
  12. +
  13. + Хеш-функция [Электронный ресурс]: Википедия. Свободная энциклопедия. + — URL: https://ru.wikipedia.org/wiki/Хеш-функция (дата обращения: 03.11.2021). +
  14. +
  15. + Хеш-функция, что это такое? [Электронный ресурс]: Хабр. Сообщество + IT-специалистов. — URL: https://habr.com/ru/post/534596/ + (дата обращения: 03.11.2021). +
  16. +
  17. + Хеш-таблицы [Электронный ресурс]: Хабр. Сообщество IT-специалистов. — + URL: https://habr.com/ru/post/509220/ + (дата обращения: 03.11.2021). +
  18. +
  19. + Хеш-таблицы [Электронный ресурс]: CodeChick. Задачи по + программированию с проверкой. — URL: https://codechick.io/tutorials/dsa/dsa-hash-table (дата обращения: 03.11.2021). +
  20. +
  21. + Fowler–Noll–Vo hash function [Электронный ресурс]: Википедия. + Свободная энциклопедия. — URL: https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function (дата обращения: 03.11.2021). +
  22. +
  23. + Ассоциативный массив [Электронный ресурс]: Википедия. + Свободная энциклопедия. — URL: https://ru.wikipedia.org/wiki/Ассоциативный_массив (дата обращения: 06.11.2021). +
  24. +
+ + diff --git a/TheoryHTML/Pages/openAddressing.html b/TheoryHTML/Pages/openAddressing.html new file mode 100644 index 0000000..3b608a8 --- /dev/null +++ b/TheoryHTML/Pages/openAddressing.html @@ -0,0 +1,274 @@ + + + + + + + Страница 7 + + +

+ Страница 7 +

+
+

Решение проблем коллизий

+

+ Открытая и прямая адресации [5, c. 170-179] +

+

Оглавление:

+ +
+

Описание

+

+ Безусловно, прямое связывание имеет свои преимущества. Основное из них + заключается в том, что общее количество значений не зависит от + количества блоков. Однако есть у таких хеш-таблиц и некоторые + недостатки. Например, если элементов в блоках накопится слишком много, + поиск нужного займет продолжительное время. Чтобы сократить временные + затраты, число блоков можно увеличить, но тогда вы рискуете получить ряд + пустых, которые потребуют места в памяти и не будут использоваться + таблицей. +

+

+ Еще один способ реализации хеш-таблиц — открытая адресация. + В этом случае значения хранятся в массиве, а функция хеширования + представляет собой некоторые расчеты. +

+

+ Хеш-таблица с прямой адресацией отличается от хеш-таблицы с + открытой адресацией тем, что в первом случае гарантировано должна + использоваться идеальная хеш-функция. Это обусловлено тем, что в данной + хеш-таблице должны отсутствовать коллизии, соответственно, как и методы + их разрешения. Стоит отметить, что под данное описание подходит + идеальное хеширование хеш-таблицы1. +

+

+ В разных видах открытой адресации используются различные функции + хеширования. Неодинакова и политика разрешения коллизий, но в общем + случае она выглядит так: для каждого значения в массиве подбирается + несколько ячеек, и если первая уже занята, алгоритм пробует использовать + вторую, затем третью и так до тех пор, пока не найдет свободную или не + придет к выводу, что таковой нет. +

+

+ Серия ячеек, которую алгоритм подбирает для значения, называется пробной + последовательностью. По ее средней длине хорошо оценивать наполненность + хештаблицы. В идеале пробная последовательность должна равняться 1 или + 2, большие цифры говорят о полной таблице. +

+

+ Иногда политика разрешения коллизий такова, что для элемента может не + найтись свободной ячейки, даже когда она есть. Если пробная + последовательность повторяет саму себя перед тем, как проверить + очередную запись, некоторые записи могут остаться неиспользованными. +

+

+ Чтобы найти элемент в хеш-таблице, алгоритм следует за пробной + последовательностью, пока не произойдет одно из трех событий. +

+
    +
  1. + Если пробная последовательность сумела отыскать элемент, задача + выполнена. +
  2. +
  3. + Если пробная последовательность находит пустую запись в массиве, + элемента нет. +
  4. +
  5. + Пробная последовательность проверяет M записей (по размеру + массива) — и алгоритм приходит к выводу, что значение + отсутствует. Последовательность может перебрать не все элементы, но + если пройдет по всем, вы будете знать, что они точно пересмотрены или + что целевой элемент не найден. Она также может проверить в цикле одну + и ту же позицию несколько раз. В любом случае значение не должно + присутствовать, поскольку иначе оно бы добавлялось к массиву с + использованием той же пробной последовательности. +
  6. +
+

+ При разумном заполнении хеш-таблицы открытая адресация работает очень + быстро. Если длина пробной последовательности равна 1 или 2, добавление + и нахождение элементов выполняются за время O(1). Но если массив + из N элементов существенно переполнен, производительность снижается. В + наихудшем случае алгоритм придет к выводу, что элемента в массиве нет, + за время O(N). Поиск присутствующих элементов также будет + выполняться крайне медленно. +

+

+ Вы можете увеличить размер массива, чтобы уменьшить коэффициент + наполненности хеш-таблицы. Для этого создайте новый массив и рехешируйте + элементы в нем. Для каждого из них операция займет O(1) времени, + а общая производительность алгоритма составит O(N). +

+
+
+

+ Линейное пробирование +

+

+ В линейном пробировании политика разрешения коллизий добавляет к каждой + ячейке постоянное число (чаще всего 1), называемое шагом по индексу, + которое генерирует пробную последовательность. При каждом очередном + добавлении берется размер массива по модулю, стало быть, при + необходимости последовательность возвращается к началу массива. +

+

+ Предположим, в хеш-таблице 100 элементов, а правило хеширования звучит + следующим образом: N связано с ячейкой N mod 100. Тогда пробная + последовательность для значения 2197 проверяет ячейки 97, 98, 99, 0, 1, + 2 и т. д. +

+

+ На рисунке 7.1 представлен массив из 10 записей, который уже содержит + несколько значений. Чтобы добавить в него новое значение 71, используя + линейную пробную последовательность, нужно связать его с ячейкой 71 mod + 10 = 1. Но эта ячейка уже занята значением 61, поэтому алгоритм + переходит к ячейке 2, которая тоже заполнена. Следующей должна быть + ячейка 3 — она свободна, и алгоритм размещает там 71. +

+
+ +

+ Рисунок 7.1 - линейная пробная последовательность +

+
+

+ Преимущество данного метода — в его простоте. Если необходимо, + пробная последовательность пройдет по каждой ячейке массива и вставит + элемент в свободное место, если оно еще осталось. Но есть и + сопутствующий недостаток — так называемая + первичная кластеризация, которая проявляется в образовании + больших блоков смежных записей и приводит к длинным пробным + последовательностям. В результате при добавлении нового элемента и его + хешировании к какой-либо записи в кластере пробная последовательность + вынуждена пройти через весь кластер, чтобы найти свободную ячейку. +

+

+ Чтобы понять, как формируются кластеры, рассмотрим пример пустой + хеш-таблицы. Предположим, в ней содержится N записей и существует + вероятность 1/N, что она закончится в любой данной позиции при + добавлении случайного числа. А теперь представим, что K — + конечная позиция таблицы. Существует вероятность 1/N, что новое + случайное число попадет в позицию K и линейное пробирование попытается + расположить элемент в позиции K + 1. Но та же вероятность + характерна и для случая, при котором новый элемент будет связан с + позицией K + 1 напрямую. Значит, существует вероятность + 2/N, что элемент займет конечную позицию K + 1 и + сформируется малый кластер. +

+

+ Через какое-то время таких кластеров станет много. Чем больше они будут, + тем больше вероятность того, что новый элемент добавится в конец одного + из них. В итоге более мелкие кластеры сольются в более крупные, массив + заполнится ими — и возникнут длинные пробные последовательности. +

+
+
+

+ Квадратичное пробирование +

+

+ Возникновение больших кластеров при линейном пробировании связано с тем, + что новые элементы связываются с ячейками, стоящими в конце группы, и + постепенно увеличивают ее. Предотвратить подобную ситуацию помогает + квадратичное пробирование. Для создания пробной + последовательности в качестве шага по индексу берется квадрат количества + ячеек. Другими словами, если в линейном пробировании существует + последовательность K, K + 1, K + 2, K + 3, ... то в квадратичном + варианте она будет выглядеть так: + K, K + 12, K + 22, K + 32, ... В этом случае, если два + элемента окажутся связанными с разными позициями в одном и том же + кластере, они не обязательно будут придерживаться одной пробной + последовательности и попадут в конец кластера. +

+

+ На рисунке 7.2 показана хеш-таблица, в начале которой есть группа из + пяти элементов. Новое значение 71 получает пробную последовательность + 1, 1 + 12 = 2, 1 + 22 = 5, 1 + 32 = 10 и не добавляется к + существующему кластеру. Значение 93 поначалу связано с тем же + кластером, но согласно собственной пробной последовательности + 3, 3 + 12 = 4, 3 + 22 = 7 также не попадает в него. +

+
+ +

Рисунок 7.2 - Квадратичное пробирование

+
+

+ Квадратичное пробирование предотвращает первичную, но не + вторичную кластеризацию, при которой значения, связанные с + одинаковой начальной позицией в массиве, получают одну и ту же пробную + последовательность, иногда очень длинную. В результате образуется точно + такая же группа элементов, но уже не собранных вместе, а распределенных + по всему массиву. +

+

+ Еще один недостаток квадратичного пробирования связан с тем, что оно + может не найти свободную позицию, даже если в хеш-таблице их несколько. + Дело в том, что с каждым разом перемещение по массиву происходит все + дальше и дальше, и незаполненная ячейка попросту пропускается. +

+
+
+

+ Псевдослучайное пробирование +

+

+ Это пробирование подобно линейному, за исключением того, что шаг по + индексу формирует псевдослучайная функция изначально связанной ячейки. + Предположим, что это ячейка K, тогда пробная последовательность + будет выглядеть следующим образом: K, K + p, K + 2p, ... где p + определяется псевдослучайной функцией. +

+

+ Подобно квадратичному пробированию, псевдослучайное предотвращает только + первичную кластеризацию, но страдает от вторичной: значения, связанные с + одной и той же начальной позицией, размещаются в хеш-таблице согласно + одной и той же пробной последовательности. Точно так же псевдослучайное + пробирование может пропускать некоторые неиспользуемые записи. +

+
+
+

+ Двойное хеширование +

+

+ Чтобы избавиться от вторичной кластеризации значения, связанные с одной + и той же начальной ячейкой, должны получать разные пробные + последовательности. И здесь пригодится двойное хеширование. Оно похоже + на псевдослучайное пробирование, только шаг для индекса задается не + псевдослучайной функцией начальной ячейки, а второй функцией + хеширования. +

+

+ Допустим, значения A и B связаны с позицией K. В + псевдослучайном пробировании шаг по индексу p генерируется + функцией F1 (K), затем оба значения используют пробную + последовательность K, K + p, K + 2p, K + 3p, ... В двойном + хешировании для связывания начальных значений А и + В применяется функция псевдослучайного хеширования + F2. В итоге при одном и том же начальном K образуются две пробные + последовательности с различными шагами по индексу: + pA = F2 (A) и + pB = F2 (B) соответственно. +

+

+ Несмотря на то, что двойное хеширование хорошо справляется с первичной и + вторичной кластеризациями, оно точно так же, как и псевдослучайное + пробирование, может пропускать неиспользуемые записи. +

+
+
+

+ 1Данный метод хеширования хорошо описан в книге Томаса Кормена + [2] +

+ + diff --git a/TheoryHTML/info.xml b/TheoryHTML/info.xml new file mode 100644 index 0000000..4115598 --- /dev/null +++ b/TheoryHTML/info.xml @@ -0,0 +1,16 @@ + + + ./TheoryHTML/Pages + ./TheoryHTML/Images + + main.html + introduction.html + binaryRelationship.html + dirichletPrinciple.html + hashFunction.html + hashTable.html + chainMethod.html + openAddressing.html + analysis.html + + \ No newline at end of file