Постановка задачи:
Реализация работы со справочником предметной области “Магазин”( с ключами Артикул, Наименование товара, ИНН поставщика,  Дата) с использованием структур данных АВЛ-дерево (по нему распределяем по ключу Наименование товара), состоящее из хеш-таблиц (по ним распределяем по ключу Дата).
Общие требования:
Оконный интерфейс (в среде разработки WinForms, но исходная реализация на C++)
Нельзя использовать универсальные классы-коллекции в System.Collections для реализации заданных структур данных
В интерфейсе отображать справочник в табличном виде и окно отладки для вывода структур данных
Какой должен быть функционал: 
Возможность задания в интерфейсе первоначального размера ХТ
Работа со справочником:
- загрузка из текстового файла / сохранение в текстовый файл
- добавление
- удаление
- поиск
- просмотр
Окно отладки (печать структур данных)
Форма использует файлы Kursovaya.cpp, MyForm.h, MyForm.cpp и hashtableform.h.
Код Kursovaya.cpp:
#include <iostream>
#include <vector>
#include <istream>
#include <fstream>
#include <list>
#include <cstring>
using namespace std;

struct VendorCode
{
    long long int vendorcode;
    bool correct = true;
    VendorCode(long long int vc) {
        long long int n = vc;
        int c = 0;
        while (n != 0)
        {
            c++;
            n /= 10;
        }
        if (c == 8)
        {
            vendorcode = vc;
        }
        else
        {
            correct = false;
            std::cerr << "Invalid vendor code. Setting default vendor code to 10000000" << std::endl;
            vendorcode = 1000000000;
        }
    }
};
struct ProductName {
    std::string productname;

    ProductName(std::string pn) : productname(pn) {}
};
struct TIN
{
    long long int tin;
    bool correct = true;
    TIN(long long int t) {
        long long int n = t;
        int c = 0;
        while (n != 0)
        {
            c++;
            n /= 10;
        }
        if (c == 10)
        {
            tin = t;
        }
        else
        {
            correct = false;
            std::cerr << "Invalid TIN. Setting default TIN to 1000000000" << std::endl;
            tin = 1000000000;
        }
    }
};
struct Date {
    int day;
    int month;
    int year;
    bool correct = true;
    Date(int d, int m, int y) {
        if (y > 2024 || y < 2000)
            correct = false;
        else
        {
            switch (m)
            {
            case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                if (d < 1 || d > 31)
                    correct = false;
                break;
            case 4: case 6: case 9: case 11:
                if (d < 1 || d > 30)
                    correct = false;
                break;
            case 2:
                if (d < 1 || d > 28)
                    correct = false;
                break;
            default:
                correct = false;
                break;
            }
        }
        if (correct)
        {
            day = d;
            month = m;
            year = y;
        }
        else
        {
            std::cerr << "Invalid date. Setting default date to 1.1.2000." << std::endl;
            day = 1;
            month = 1;
            year = 2000;
        }
    }
};
struct Sorts {
    VendorCode vendorcodes;
    ProductName productnames;
    TIN tins;
    Date dates;
    int firstHash;
    Sorts(const VendorCode& vc, const ProductName& pn, const TIN& t, const Date& d) : vendorcodes(vc), productnames(pn), tins(t), dates(d), firstHash(0) {}
};
struct Cell {
    Sorts sorts;
    int flag;
    int firstHash;
    Cell() : sorts(VendorCode(0), ProductName(""), TIN(100000000000), Date(1, 1, 2000)), flag(0), firstHash(0) {}
};
class HashTable
{
private:
    std::vector<Sorts> readFromFile(const std::string& filename) {
        std::vector<Sorts> sorts;
        std::ifstream file(filename);

        if (file.is_open()) {
            int vc;
            std::string pn;
            int t;
            int day;
            int month;
            int year;


            while (file >> vc >> pn >> t >> day >> month >> year) {
                VendorCode vendorcode(vc);
                ProductName productname(pn);
                TIN tin(t);
                Date date(day, month, year);

                sorts.push_back(Sorts(vendorcode, productname, tin, date));
            }

            file.close();
        }
        else {
            std::cerr << "Enable open file" << filename << std::endl;
        }

        return sorts;
    }
    int digitsCount(int n)
    {
        int c = 0;
        while (n != 0)
        {
            c++;
            n /= 10;
        }
        return c;
    }
    int hash1(int key1, int key2, int key3, int n)
    {
        int d = digitsCount(n - 1);

        int l = digitsCount(key1);
        int e = (2 * l - d) / 2;
        int r = pow(10, e);
        int h1 = (key1 * key1) / r;
        int mod = pow(10, d);
        h1 %= mod;

        l = digitsCount(key2);
        e = (2 * l - d) / 2;
        r = pow(10, e);
        int h2 = (key2 * key2) / r;
        mod = pow(10, d);
        h2 %= mod;

        l = digitsCount(key3);
        e = (2 * l - d) / 2;
        r = pow(10, e);
        int h3 = (key3 * key3) / r;
        mod = pow(10, d);
        h3 %= mod;

        int h = (h1 + h2 + h3) % n;
        return h;
    }
    int hash2(int key1, int key2, int key3, int j, int k, int n)
    {
        int hash = (hash1(key1, key2, key3, n) + j * k) % n;

        return hash;
    }
    int collisionInsert(int key1, int key2, int key3, int n, int hash)
    {
        int h = hash;
        int j = 0;
        int k = 3;
        do
        {
            if (table[h].sorts.dates.day == key1 && table[h].sorts.dates.month == key2 && table[h].sorts.dates.year == key3)
                return -2;
            if (table[h].flag != 1)
            {
                return h;
            }
            else
            {
                h = hash2(key1, key2, key3, j, k, n);
                ++j;
            }
        } while (j != n);
        return -1;
    }
    int collisionSearch(int key1, int key2, int key3, int n, int hash)
    {
        int h = hash;
        int j = 0;
        int k = 3;
        do
        {
            if (table[h].sorts.dates.day == key1 && table[h].sorts.dates.month == key2 && table[h].sorts.dates.year == key3)
            {
                return h;
            }
            else
            {
                h = hash2(key1, key2, key3, j, k, n);
                ++j;
            }
        } while (j != n);
        return -1;
    }
public:
    std::vector <Cell> table;
    bool isEmpty()
    {
        for (int i = 0; i < table.size(); i++)
        {
            if (table[i].flag == 1)
                return false;
        }
        return true;
    }
    int insertItem(Sorts s)
    {
        int n = table.size();
        int key1 = s.dates.day;
        int key2 = s.dates.month;
        int key3 = s.dates.year;
        int hash = hash1(key1, key2, key3, n);
        s.firstHash = hash;
        if (table[hash].flag != 1)
        {
            table[hash].sorts = s;
            table[hash].firstHash = s.firstHash;
            table[hash].flag = 1;
            return 0;
        }
        else
        {
            int secondhash = collisionInsert(key1, key2, key3, n, hash);
            if (secondhash == -2)
            {
                std::cout << "Item is already in the table." << std::endl;
                return -2;
            }
            else if (secondhash == -1)
            {
                std::cout << "Can't insert, table is full." << std::endl;
                return -1;
            }
            else
            {
                for (int i = 0; i < table.size(); i++)
                {
                    if (table[i].sorts.dates.day == key1 && table[i].sorts.dates.month == key2 && table[i].sorts.dates.year == key3)
                        return -2;
                }
                table[secondhash].sorts = s;
                table[secondhash].firstHash = s.firstHash;
                table[secondhash].flag = 1;
                return 1;
            }
        }
    }
    int removeItem(int key1, int key2, int key3)
    {
        int n = table.size();
        int hash = hash1(key1, key2, key3, n);
        if (table[hash].sorts.dates.day == key1 && table[hash].sorts.dates.month == key2 && table[hash].sorts.dates.year == key3)
        {
            table[hash].flag = 2;
            std::cout << "Removed" << std::endl;
            return 0;
        }
        else
        {
            int secondhash = collisionSearch(key1, key2, key3, n, hash);
            if (secondhash != -1)
            {
                if (table[secondhash].flag == 1)
                {
                    table[secondhash].flag = 2;
                    std::cout << "Removed" << std::endl;
                    return 1;
                }
            }
            std::cout << "Item is not in the table." << std::endl;
            return -1;
        }
    }
    HashTable(const std::string readFile, int n)
    {
        table.resize(n);
        std::vector <Sorts> sorts = readFromFile(readFile);

        for (int i = 0; i < n; i++)
        {
            if (i < sorts.size())
                insertItem(sorts[i]);
        }
    }
    HashTable()
    {

    }
    void changeSize(int hashtablesize)
    {
        table.resize(hashtablesize);
    }
    int getSize()
    {
        return table.size();
    }
    ~HashTable()
    {
        table.clear();
    }
    int searchItem(int key1, int key2, int key3, int searchsteps)
    {
        int n = table.size();
        int hash = hash1(key1, key2, key3, n);
        searchsteps++;
        if (table[hash].flag == 1 && table[hash].sorts.dates.day == key1 && table[hash].sorts.dates.month == key2 && table[hash].sorts.dates.year == key3)
        {
            std::cout << "Found: " << hash << " | " << table[hash].sorts.vendorcodes.vendorcode << " " << table[hash].sorts.productnames.productname << " " << table[hash].sorts.tins.tin << " " << table[hash].sorts.dates.day << "." << table[hash].sorts.dates.month << "." << table[hash].sorts.dates.year << " | first hash: " << table[hash].firstHash << " | flag: " << table[hash].flag << std::endl;
            return searchsteps;
        }
        else
        {
            searchsteps++;
            int secondhash = collisionSearch(key1, key2, key3, n, hash);
            if (secondhash != -1)
            {
                if (table[secondhash].flag == 1)
                {
                    std::cout << "Found: " << hash << " | " << table[hash].sorts.vendorcodes.vendorcode << " " << table[hash].sorts.productnames.productname << " " << table[hash].sorts.tins.tin << " " << table[hash].sorts.dates.day << "." << table[hash].sorts.dates.month << "." << table[hash].sorts.dates.year << " | first hash: " << table[hash].firstHash << " | flag: " << table[hash].flag << std::endl;
                    return searchsteps;
                }
            }
            std::cout << "Item is not in the table." << std::endl;
            return -1;
        }
    }
    void printTable(std::string key)
    {
        std::cout << key << ": " << std::endl;
        for (int i = 0; i < table.size(); i++)
        {
            if (table[i].flag != 1)
                std::cout << i << " | flag: " << table[i].flag << std::endl;
            else
                std::cout << i << " | " << table[i].sorts.vendorcodes.vendorcode << " " << table[i].sorts.productnames.productname << " " << table[i].sorts.tins.tin << " " << table[i].sorts.dates.day << "." << table[i].sorts.dates.month << "." << table[i].sorts.dates.year << " | first hash: " << table[i].firstHash << " | flag: " << table[i].flag << std::endl;
        }
        std::cout << std::endl;

    }
    void writeFile(std::ofstream& out, std::string key)
    {
        out << key << ": " << std::endl;
        for (int i = 0; i < table.size(); i++)
        {
            if (table[i].flag != 1)
                out << i << " | flag: " << table[i].flag << std::endl;
            else
                out << i << " | " << table[i].sorts.vendorcodes.vendorcode << " " << table[i].sorts.productnames.productname << " " << table[i].sorts.tins.tin << " " << table[i].sorts.dates.day << "." << table[i].sorts.dates.month << "." << table[i].sorts.dates.year << " | first hash: " << table[i].firstHash << " | flag: " << table[i].flag << std::endl;
        }
        out << std::endl;
    }
};

struct Node
{
    std::string key;
    HashTable ht;
    Node* left;
    Node* right;
    int balance;
};

class Tree
{
private:
    int hashTableSize = 10;
    std::vector<Sorts> readFromFile(const std::string& filename) {
        std::vector<Sorts> sorts;
        std::ifstream file(filename);

        if (file.is_open()) {
            int vc;
            std::string pn;
            long long int t;
            int day;
            int month;
            int year;


            while (file >> vc >> pn >> t >> day >> month >> year) {
                VendorCode vendorcode(vc);
                ProductName productname(pn);
                TIN tin(t);
                Date date(day, month, year);

                sorts.push_back(Sorts(vendorcode, productname, tin, date));
            }

            file.close();
        }
        else {
            std::cerr << "Enable open file" << filename << std::endl;
        }

        return sorts;
    }
    void add(int vc, std::string pn, long long int t, int d, int m, int y, Node*& p, bool& h) // поиск и добавление элемента
    {
        VendorCode vendorcode(vc);
        ProductName productname(pn);
        TIN tin(t);
        Date date(d, m, y);
        Sorts s(vendorcode, productname, tin, date);
        if (p == NULL) // слова нет в дереве; включить его
        {
            p = new Node;
            h = true;
            p->key = s.productnames.productname;
            p->ht.changeSize(hashTableSize);
            p->ht.insertItem(s);
            p->balance = 0;
            p->left = NULL;
            p->right = NULL;
        }
        else if (pn < p->key)
        {
            add(vc, pn, t, d, m, y, p->left, h);
            if (h) // выросла левая ветвь
            {
                switch (p->balance)
                {
                case 1:
                    p->balance = 0;
                    h = false;
                    break;
                case 0:
                    p->balance = -1;
                    break;
                case -1: // балансировка
                    Node * p1 = p->left;
                    if (p1->balance == -1) // L-поворот
                    {
                        p->left = p1->right;
                        p1->right = p;
                        p->balance = 0;
                        p = p1;
                    }
                    else // LR-поворот
                    {
                        Node* p2 = p1->right;
                        p1->right = p2->left;
                        p2->left = p1;
                        p->left = p2->right;
                        p2->right = p;
                        if (p2->balance == -1)
                            p->balance = 1;
                        else
                            p->balance = 0;
                        if (p2->balance == 1)
                            p1->balance = -1;
                        else
                            p1->balance = 0;
                        p = p2;
                    }
                    p->balance = 0;
                    h = false;
                    break;
                }
            }
        }
        else if (pn > p->key)
        {
            add(vc, pn, t, d, m, y, p->right, h);
            if (h == true) // выросла правая ветвь
            {
                switch (p->balance)
                {
                case -1:
                    p->balance = 0;
                    h = false;
                    break;
                case 0:
                    p->balance = 1;
                    break;
                case 1: // балансировка
                    Node * p1 = p->right;
                    if (p1->balance == 1) //R-поворот
                    {
                        p->right = p1->left;
                        p1->left = p;
                        p->balance = 0;
                        p = p1;
                    }
                    else // RL-поворот
                    {
                        Node* p2 = p1->left;
                        p1->left = p2->right;
                        p2->right = p1;
                        p->right = p2->left;
                        p2->left = p;
                        if (p2->balance == 1)
                            p->balance = -1;
                        else
                            p->balance = 0;
                        if (p2->balance == -1)
                            p1->balance = 1;
                        else
                            p1->balance = 0;
                        p = p2;
                    }
                    p->balance = 0;
                    h = false;
                    break;
                }
            }
        }
        else
        {
            p->ht.insertItem(s);
            h = false;
        }
    }
    void balance1(Node* p, bool& h)
    {
        Node* p1, * p2;
        short b1, b2;
        if (p == NULL)
            return;
        switch (p->balance)
        {
        case -1:
            p->balance = 0;
            break;
        case 0:
            p->balance = 1;
            h = true;
            break;
        case 1: // балансировка
            p1 = p->right;
            b1 = p1->balance;
            if (b1 >= 0) // R-поворот
            {
                p->right = p1->left;
                p1->left = p;
                if (b1 == 0)
                {
                    p->balance = 1;
                    p1->balance = -1;
                    h = false;
                }
                else
                {
                    p->balance = 0;
                    p1->balance = 0;
                }
                p = p1;
            }
            else // RL-поворот
            {
                p2 = p1->left;
                b2 = p2->balance;
                p1->left = p2->right;
                p2->right = p1;
                p->right = p2->left;
                p2->left = p;
                if (b2 == 1)
                    p->balance = -1;
                else
                    p->balance = 0;
                if (b2 == -1)
                    p1->balance = 1;
                else
                    p1->balance = 0;
                p = p2;
                p2->balance = 0;
            }
        }
    }
    void balance2(Node* p, bool& h)
    {
        Node* p1, * p2;
        short b1, b2;
        switch (p->balance)
        {
        case 1:
            p->balance = 0;
            break;
        case 0:
            p->balance = -1;
            h = true;
            break;
        case -1:
            p1 = p->left;
            b1 = p1->balance;
            if (b1 <= 0) // L-поворот
            {
                p->left = p1->right;
                p1->right = p;
                if (b1 == 0)
                {
                    p->balance = -1;
                    p1->balance = 1;
                    h = false;
                }
                else
                {
                    p->balance = 0;
                    p1->balance = 0;
                }
                p = p1;
            }
            else // LR-поворот
            {
                p2 = p1->right;
                b2 = p2->balance;
                p1->right = p2->left;
                p2->left = p1;
                p->left = p2->right;
                p2->right = p;
                if (b2 == -1)
                    p->balance = 1;
                else
                    p->balance = 0;
                if (b2 == 1)
                    p1->balance = -1;
                else
                    p1->balance = 0;
                p = p2;
                p2->balance = 0;
            }
        }
    }

    void delet(std::string pn, int d, int m, int y, Node*& p, bool& h) // удаление элемента, выше вспомогательные подпрограммы
    {
        Node* q;
        if (p == NULL)
        {
            h = false;
        }
        else if (pn < p->key)
        {
            delet(pn, d, m, y, p->left, h);
            if (h)
                balance1(p, h); // вызов функции балансировки
        }
        else if (pn > p->key)
        {
            delet(pn, d, m, y, p->right, h);
            if (h)
                balance2(p, h);
        }
        else
        {
            if (p->left == NULL && p->right == NULL)
            {
                p->ht.removeItem(d, m, y);
                if (p->ht.isEmpty())
                {
                    delete p;
                    p = NULL;
                    h = true;
                }
            }
            else if (p->left != NULL && p->right == NULL)
            {
                p->ht.removeItem(d, m, y);
                if (p->ht.isEmpty())
                {
                    Node* temp = p->left;
                    delete p;
                    p = temp;
                    h = true;
                }
            }
            else if (p->left == NULL && p->right != NULL)
            {
                p->ht.removeItem(d, m, y);
                if (p->ht.isEmpty())
                {
                    Node* temp = p->right;
                    delete p;
                    p = temp;
                    h = true;
                }
            }
            else
            {
                p->ht.removeItem(d, m, y);
                if (p->ht.isEmpty())
                {
                    Node* temp = p->left;
                    Node* parent = p;
                    while (temp->right != NULL)
                    {
                        parent = temp;
                        temp = temp->right;
                    }
                    if (parent != p)
                        parent->right = temp->left;
                    else
                        parent->left = temp->left;
                    p->key = temp->key;
                    p->ht = temp->ht;
                    delete temp;
                    h = true;
                }
            }

            if (h)
                balance1(p, h); // вызов функции балансировки
        }
    }
    void print(Node* t, short hh) // печать дерева
    {
        if (t != NULL)
        {
            print(t->right, hh + 1);
            for (int i = 1; i <= hh; i++)
                cout << "   ";
            t->ht.printTable(t->key);
            std::cout << std::endl;
            print(t->left, hh + 1);
        }
    }
    void walk(Node* t, short hh, std::ofstream& out) // обход дерева справа налево и вывод в файл
    {
        if (t != NULL)
        {
            walk(t->right, hh + 1, out);
            t->ht.writeFile(out, t->key);
            walk(t->left, hh + 1, out);
        }
    }
    int search(std::string pn, int d, int m, int y, Node*& p, bool& h, int searchsteps) // поиск элемента
    {
        searchsteps++;
        Node* q;
        if (p == NULL)
        {
            cout << "Haven't found." << endl;
            h = false;
        }
        else if (pn < p->key)
        {
            searchsteps++;
            search(pn, d, m, y, p->left, h, searchsteps);
        }
        else if (pn > p->key)
        {
            searchsteps++;
            search(pn, d, m, y, p->right, h, searchsteps);
        }
        else
        {
            searchsteps = p->ht.searchItem(d, m, y, searchsteps);
            if (searchsteps == -1)
                std::cout << "Haven't found." << std::endl;
            else
                std::cout << "Found in " << searchsteps << " steps." << std::endl;
            h = false;
        }
    }
    int getSizeHelper(Node* p)
    {
        if (p == NULL) {
            return 0;
        }
        else {
            return 1 + getSizeHelper(p->left) + getSizeHelper(p->right);
        }
    }
public:
    Node* root = NULL;
    int getSize()
    {
        return getSizeHelper(root);
    }
    void setHashTableSize(int size)
    {
        hashTableSize = size;
    }
    Node* findbyname(std::string pn, Node*& p)
    {
        Node* q;
        if (p == NULL)
        {
            return nullptr;
        }
        else if (pn < p->key)
        {
            return findbyname(pn, p->left);
        }
        else if (pn > p->key)
        {
            return findbyname(pn, p->right);
        }
        else
        {
            return p;
        }
    }

    bool isEmpty()
    {
        if (root == NULL)
            return true;
        else
            return false;
    }

    void addItem(int vc, std::string pn, long long int t, int d, int m, int y)
    {
        bool h = false;
        add(vc, pn, t, d, m, y, root, h);
    }

    void removeItem(std::string pn, int d, int m, int y)
    {
        bool h = false;
        delet(pn, d, m, y, root, h);
    }

    void searchItem(std::string pn, int d, int m, int y)
    {
        bool h = false;
        search(pn, d, m, y, root, h, 0);
    }

    void printTree()
    {
        print(root, 0);
    }

    void writeFile()
    {
        std::ofstream out("OutputFile.txt");
        walk(root, 0, out);
    }

    Tree(){}
    void readFile(const std::string readFile, int n)
    {
        std::vector <Sorts> sorts = readFromFile(readFile);

        for (int i = 0; i < n; i++)
        {
            if (i < sorts.size())
                addItem(sorts[i].vendorcodes.vendorcode, sorts[i].productnames.productname, sorts[i].tins.tin, sorts[i].dates.day, sorts[i].dates.month, sorts[i].dates.year);
        }
    }
};
Код MyForm.h:
#pragma once
#include <msclr/marshal_cppstd.h>
#include "Kursovaya.cpp"

namespace KursovayaCLR {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Сводка для HashTableForm
	/// </summary>
	public ref class HashTableForm : public System::Windows::Forms::Form
	{
	private:
		Tree* treePointer;
	public:
		HashTableForm(Tree* tree) : treePointer(tree) 
		{
			InitializeComponent();
		}

	protected:
		/// <summary>
		/// Освободить все используемые ресурсы.
		/// </summary>
		~HashTableForm()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::DataGridView^ dataGridView1;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Hash;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ VendorCode;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ ProductName;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ TIN;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Day;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Month;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Year;
	protected:







	private:
		/// <summary>
		/// Обязательная переменная конструктора.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Требуемый метод для поддержки конструктора — не изменяйте 
		/// содержимое этого метода с помощью редактора кода.
		/// </summary>
		void InitializeComponent(void)
		{
			this->dataGridView1 = (gcnew System::Windows::Forms::DataGridView());
			this->Hash = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->VendorCode = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->ProductName = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->TIN = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Day = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Month = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Year = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->BeginInit();
			this->SuspendLayout();
			// 
			// dataGridView1
			// 
			this->dataGridView1->ColumnHeadersHeightSizeMode = System::Windows::Forms::DataGridViewColumnHeadersHeightSizeMode::AutoSize;
			this->dataGridView1->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewColumn^  >(7) {
				this->Hash, this->VendorCode,
					this->ProductName, this->TIN, this->Day, this->Month, this->Year
			});
			this->dataGridView1->Location = System::Drawing::Point(12, 75);
			this->dataGridView1->Name = L"dataGridView1";
			this->dataGridView1->RowHeadersWidth = 51;
			this->dataGridView1->RowTemplate->Height = 24;
			this->dataGridView1->Size = System::Drawing::Size(950, 307);
			this->dataGridView1->TabIndex = 0;
			// 
			// Hash
			// 
			this->Hash->HeaderText = L"Hash";
			this->Hash->MinimumWidth = 6;
			this->Hash->Name = L"Hash";
			this->Hash->ReadOnly = true;
			this->Hash->Width = 125;
			// 
			// VendorCode
			// 
			this->VendorCode->HeaderText = L"Vendor Code";
			this->VendorCode->MinimumWidth = 6;
			this->VendorCode->Name = L"VendorCode";
			this->VendorCode->ReadOnly = true;
			this->VendorCode->Width = 125;
			// 
			// ProductName
			// 
			this->ProductName->HeaderText = L"Product Name";
			this->ProductName->MinimumWidth = 6;
			this->ProductName->Name = L"ProductName";
			this->ProductName->ReadOnly = true;
			this->ProductName->Width = 125;
			// 
			// TIN
			// 
			this->TIN->HeaderText = L"TIN";
			this->TIN->MinimumWidth = 6;
			this->TIN->Name = L"TIN";
			this->TIN->ReadOnly = true;
			this->TIN->Width = 125;
			// 
			// Day
			// 
			this->Day->HeaderText = L"Day";
			this->Day->MinimumWidth = 6;
			this->Day->Name = L"Day";
			this->Day->ReadOnly = true;
			this->Day->Width = 125;
			// 
			// Month
			// 
			this->Month->HeaderText = L"Month";
			this->Month->MinimumWidth = 6;
			this->Month->Name = L"Month";
			this->Month->ReadOnly = true;
			this->Month->Width = 125;
			// 
			// Year
			// 
			this->Year->HeaderText = L"Year";
			this->Year->MinimumWidth = 6;
			this->Year->Name = L"Year";
			this->Year->ReadOnly = true;
			this->Year->Width = 125;
			// 
			// HashTableForm
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(8, 16);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(1042, 468);
			this->Controls->Add(this->dataGridView1);
			this->Name = L"HashTableForm";
			this->Text = L"HashTableForm";
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->EndInit();
			this->ResumeLayout(false);

		}
#pragma endregion
		public: void FillHashTableTable(String^ productName)
		{
			dataGridView1->Rows->Clear();

			// Найти узел по имени продукта
			std::string productNameStr = msclr::interop::marshal_as<std::string>(productName);
			Node* targetNode = treePointer->findbyname(productNameStr, treePointer->root);

			if (targetNode != nullptr) {
				// Создание строк в DataGridView в количестве HTSize
				for (int i = 0; i < targetNode->ht.getSize(); i++)
				{
					dataGridView1->Rows->Add(); // Создание строки в DataGridView

					// Заполнение данных в строке i из хеш-таблицы targetNode->ht
					dataGridView1->Rows[i]->Cells[0]->Value = i; // Хеш
					if (targetNode->ht.table[i].flag == 1)
					{
						dataGridView1->Rows[i]->Cells[1]->Value = targetNode->ht.table[i].sorts.vendorcodes.vendorcode; // VendorCode
						dataGridView1->Rows[i]->Cells[2]->Value = gcnew String(targetNode->ht.table[i].sorts.productnames.productname.c_str()); // ProductName
						dataGridView1->Rows[i]->Cells[3]->Value = targetNode->ht.table[i].sorts.tins.tin; // TIN
						dataGridView1->Rows[i]->Cells[4]->Value = targetNode->ht.table[i].sorts.dates.day; // Day
						dataGridView1->Rows[i]->Cells[5]->Value = targetNode->ht.table[i].sorts.dates.month; // Month
						dataGridView1->Rows[i]->Cells[6]->Value = targetNode->ht.table[i].sorts.dates.year; // Year
					}
				}
			}
		}


	};
}
Код MyForm.cpp:
#include "MyForm.h"

using namespace System;
using namespace System::Windows::Forms;

[STAThreadAttribute]
int main()
{
	Application::SetCompatibleTextRenderingDefault(false);
	Application::EnableVisualStyles();
	KursovayaCLR::MyForm form;
	Application::Run(% form);
}
Код HashTableForm.h:
#pragma once
#include <msclr/marshal_cppstd.h>
#include "Kursovaya.cpp"

namespace KursovayaCLR {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Сводка для HashTableForm
	/// </summary>
	public ref class HashTableForm : public System::Windows::Forms::Form
	{
	private:
		Tree* treePointer;
	public:
		HashTableForm(Tree* tree) : treePointer(tree) 
		{
			InitializeComponent();
		}

	protected:
		/// <summary>
		/// Освободить все используемые ресурсы.
		/// </summary>
		~HashTableForm()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::DataGridView^ dataGridView1;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Hash;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ VendorCode;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ ProductName;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ TIN;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Day;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Month;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ Year;
	protected:







	private:
		/// <summary>
		/// Обязательная переменная конструктора.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Требуемый метод для поддержки конструктора — не изменяйте 
		/// содержимое этого метода с помощью редактора кода.
		/// </summary>
		void InitializeComponent(void)
		{
			this->dataGridView1 = (gcnew System::Windows::Forms::DataGridView());
			this->Hash = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->VendorCode = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->ProductName = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->TIN = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Day = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Month = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			this->Year = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->BeginInit();
			this->SuspendLayout();
			// 
			// dataGridView1
			// 
			this->dataGridView1->ColumnHeadersHeightSizeMode = System::Windows::Forms::DataGridViewColumnHeadersHeightSizeMode::AutoSize;
			this->dataGridView1->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewColumn^  >(7) {
				this->Hash, this->VendorCode,
					this->ProductName, this->TIN, this->Day, this->Month, this->Year
			});
			this->dataGridView1->Location = System::Drawing::Point(12, 75);
			this->dataGridView1->Name = L"dataGridView1";
			this->dataGridView1->RowHeadersWidth = 51;
			this->dataGridView1->RowTemplate->Height = 24;
			this->dataGridView1->Size = System::Drawing::Size(950, 307);
			this->dataGridView1->TabIndex = 0;
			// 
			// Hash
			// 
			this->Hash->HeaderText = L"Hash";
			this->Hash->MinimumWidth = 6;
			this->Hash->Name = L"Hash";
			this->Hash->ReadOnly = true;
			this->Hash->Width = 125;
			// 
			// VendorCode
			// 
			this->VendorCode->HeaderText = L"Vendor Code";
			this->VendorCode->MinimumWidth = 6;
			this->VendorCode->Name = L"VendorCode";
			this->VendorCode->ReadOnly = true;
			this->VendorCode->Width = 125;
			// 
			// ProductName
			// 
			this->ProductName->HeaderText = L"Product Name";
			this->ProductName->MinimumWidth = 6;
			this->ProductName->Name = L"ProductName";
			this->ProductName->ReadOnly = true;
			this->ProductName->Width = 125;
			// 
			// TIN
			// 
			this->TIN->HeaderText = L"TIN";
			this->TIN->MinimumWidth = 6;
			this->TIN->Name = L"TIN";
			this->TIN->ReadOnly = true;
			this->TIN->Width = 125;
			// 
			// Day
			// 
			this->Day->HeaderText = L"Day";
			this->Day->MinimumWidth = 6;
			this->Day->Name = L"Day";
			this->Day->ReadOnly = true;
			this->Day->Width = 125;
			// 
			// Month
			// 
			this->Month->HeaderText = L"Month";
			this->Month->MinimumWidth = 6;
			this->Month->Name = L"Month";
			this->Month->ReadOnly = true;
			this->Month->Width = 125;
			// 
			// Year
			// 
			this->Year->HeaderText = L"Year";
			this->Year->MinimumWidth = 6;
			this->Year->Name = L"Year";
			this->Year->ReadOnly = true;
			this->Year->Width = 125;
			// 
			// HashTableForm
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(8, 16);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(1042, 468);
			this->Controls->Add(this->dataGridView1);
			this->Name = L"HashTableForm";
			this->Text = L"HashTableForm";
			(cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->EndInit();
			this->ResumeLayout(false);

		}
#pragma endregion
		public: void FillHashTableTable(String^ productName)
		{
			dataGridView1->Rows->Clear();

			// Найти узел по имени продукта
			std::string productNameStr = msclr::interop::marshal_as<std::string>(productName);
			Node* targetNode = treePointer->findbyname(productNameStr, treePointer->root);

			if (targetNode != nullptr) {
				// Создание строк в DataGridView в количестве HTSize
				for (int i = 0; i < targetNode->ht.getSize(); i++)
				{
					dataGridView1->Rows->Add(); // Создание строки в DataGridView

					// Заполнение данных в строке i из хеш-таблицы targetNode->ht
					dataGridView1->Rows[i]->Cells[0]->Value = i; // Хеш
					if (targetNode->ht.table[i].flag == 1)
					{
						dataGridView1->Rows[i]->Cells[1]->Value = targetNode->ht.table[i].sorts.vendorcodes.vendorcode; // VendorCode
						dataGridView1->Rows[i]->Cells[2]->Value = gcnew String(targetNode->ht.table[i].sorts.productnames.productname.c_str()); // ProductName
						dataGridView1->Rows[i]->Cells[3]->Value = targetNode->ht.table[i].sorts.tins.tin; // TIN
						dataGridView1->Rows[i]->Cells[4]->Value = targetNode->ht.table[i].sorts.dates.day; // Day
						dataGridView1->Rows[i]->Cells[5]->Value = targetNode->ht.table[i].sorts.dates.month; // Month
						dataGridView1->Rows[i]->Cells[6]->Value = targetNode->ht.table[i].sorts.dates.year; // Year
					}
				}
			}
		}


	};
}

Какие в коде Kursovaya.cpp реализованы требования к уникальности ключей?