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

struct VendorCode
{
    int vendorcode;

    VendorCode(int vc) : vendorcode(vc) {}
};
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 == 12)
        {
            tin = t;
        }
        else
        {
            correct = false;
            std::cerr << "Invalid TIN. Setting default TIN to 100000000000" << std::endl;
            tin = 100000000000;
        }
    }
};
struct Date {
    int day;
    int month;
    int year;
    bool correct = true;
    Date(int d, int m, int y) {
        if (y > 2024 || y < 1900)
            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);
        }
    }
    void search(std::string pn, int d, int m, int y, Node*& p, bool& h, int 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::string file)
    {
        std::ofstream out(file);
        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 "HashTableForm.h"

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>
	/// Сводка для MyForm
	/// </summary>
	public ref class MyForm : public System::Windows::Forms::Form
	{
	public:
		MyForm(void)
		{
			InitializeComponent();
			//
			//TODO: добавьте код конструктора
			//
			tree = new Tree();
			hashTableForm = gcnew HashTableForm(GetTree());
			hashTableForm->Show();
		}
	public:
		Tree* GetTree() 
		{
			return tree; // где tree - указатель на дерево в MyForm
		}
	protected:
		/// <summary>
		/// Освободить все используемые ресурсы.
		/// </summary>
		~MyForm()
		{
			if (components)
			{
				delete components;
				delete tree;
			}
		}
	private: System::Windows::Forms::Button^ btnAdd;
	protected:
	private: System::Windows::Forms::Button^ btnRemove;
	private: System::Windows::Forms::TextBox^ textBoxHTSize;
	private: System::Windows::Forms::Label^ HTsize;
	private: System::Windows::Forms::Button^ LoadFile;
	private: System::Windows::Forms::Button^ SaveFile;
	private: HashTableForm^ hashTableForm;


	protected:

	protected:

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

	private: System::Windows::Forms::TextBox^ textBoxVendorCode;
	private: System::Windows::Forms::TextBox^ textBoxProductName;
	private: System::Windows::Forms::TextBox^ textBoxTIN;
	private: System::Windows::Forms::TextBox^ textBoxDay;
	private: System::Windows::Forms::TextBox^ textBoxMonth;
	private: System::Windows::Forms::TextBox^ textBoxYear;






	private: System::Windows::Forms::Label^ label1;
	private: System::Windows::Forms::Label^ label2;
	private: System::Windows::Forms::Label^ label3;
	private: System::Windows::Forms::Label^ label4;
	private: System::Windows::Forms::Label^ label5;
	private: System::Windows::Forms::Label^ label6;
	private: System::Windows::Forms::DataGridViewTextBoxColumn^ ProductName;
		   Tree* tree;

#pragma region Windows Form Designer generated code
		   /// <summary>
		   /// Требуемый метод для поддержки конструктора — не изменяйте 
		   /// содержимое этого метода с помощью редактора кода.
		   /// </summary>
		   void InitializeComponent(void)
		   {
			   this->btnAdd = (gcnew System::Windows::Forms::Button());
			   this->btnRemove = (gcnew System::Windows::Forms::Button());
			   this->textBoxHTSize = (gcnew System::Windows::Forms::TextBox());
			   this->HTsize = (gcnew System::Windows::Forms::Label());
			   this->LoadFile = (gcnew System::Windows::Forms::Button());
			   this->SaveFile = (gcnew System::Windows::Forms::Button());
			   this->dataGridView1 = (gcnew System::Windows::Forms::DataGridView());
			   this->textBoxVendorCode = (gcnew System::Windows::Forms::TextBox());
			   this->textBoxProductName = (gcnew System::Windows::Forms::TextBox());
			   this->textBoxTIN = (gcnew System::Windows::Forms::TextBox());
			   this->textBoxDay = (gcnew System::Windows::Forms::TextBox());
			   this->textBoxMonth = (gcnew System::Windows::Forms::TextBox());
			   this->textBoxYear = (gcnew System::Windows::Forms::TextBox());
			   this->label1 = (gcnew System::Windows::Forms::Label());
			   this->label2 = (gcnew System::Windows::Forms::Label());
			   this->label3 = (gcnew System::Windows::Forms::Label());
			   this->label4 = (gcnew System::Windows::Forms::Label());
			   this->label5 = (gcnew System::Windows::Forms::Label());
			   this->label6 = (gcnew System::Windows::Forms::Label());
			   this->ProductName = (gcnew System::Windows::Forms::DataGridViewTextBoxColumn());
			   (cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->BeginInit();
			   this->SuspendLayout();
			   // 
			   // btnAdd
			   // 
			   this->btnAdd->Location = System::Drawing::Point(238, 12);
			   this->btnAdd->Name = L"btnAdd";
			   this->btnAdd->Size = System::Drawing::Size(107, 45);
			   this->btnAdd->TabIndex = 0;
			   this->btnAdd->Text = L"Add";
			   this->btnAdd->UseVisualStyleBackColor = true;
			   this->btnAdd->Click += gcnew System::EventHandler(this, &MyForm::btnAdd_Click);
			   // 
			   // btnRemove
			   // 
			   this->btnRemove->Location = System::Drawing::Point(351, 12);
			   this->btnRemove->Name = L"btnRemove";
			   this->btnRemove->Size = System::Drawing::Size(107, 45);
			   this->btnRemove->TabIndex = 1;
			   this->btnRemove->Text = L"Remove";
			   this->btnRemove->UseVisualStyleBackColor = true;
			   this->btnRemove->Click += gcnew System::EventHandler(this, &MyForm::btnRemove_Click);
			   // 
			   // textBoxHTSize
			   // 
			   this->textBoxHTSize->Location = System::Drawing::Point(790, 23);
			   this->textBoxHTSize->Name = L"textBoxHTSize";
			   this->textBoxHTSize->Size = System::Drawing::Size(53, 22);
			   this->textBoxHTSize->TabIndex = 2;
			   this->textBoxHTSize->TextChanged += gcnew System::EventHandler(this, &MyForm::textBoxHTSize_TextChanged);
			   // 
			   // HTsize
			   // 
			   this->HTsize->AutoSize = true;
			   this->HTsize->Location = System::Drawing::Point(787, 3);
			   this->HTsize->Name = L"HTsize";
			   this->HTsize->Size = System::Drawing::Size(56, 17);
			   this->HTsize->TabIndex = 3;
			   this->HTsize->Text = L"HT size";
			   // 
			   // LoadFile
			   // 
			   this->LoadFile->Location = System::Drawing::Point(12, 12);
			   this->LoadFile->Name = L"LoadFile";
			   this->LoadFile->Size = System::Drawing::Size(107, 45);
			   this->LoadFile->TabIndex = 4;
			   this->LoadFile->Text = L"Load File";
			   this->LoadFile->UseVisualStyleBackColor = true;
			   // 
			   // SaveFile
			   // 
			   this->SaveFile->Location = System::Drawing::Point(125, 12);
			   this->SaveFile->Name = L"SaveFile";
			   this->SaveFile->Size = System::Drawing::Size(107, 45);
			   this->SaveFile->TabIndex = 5;
			   this->SaveFile->Text = L"Save File";
			   this->SaveFile->UseVisualStyleBackColor = true;
			   // 
			   // dataGridView1
			   // 
			   this->dataGridView1->ColumnHeadersHeightSizeMode = System::Windows::Forms::DataGridViewColumnHeadersHeightSizeMode::AutoSize;
			   this->dataGridView1->Columns->AddRange(gcnew cli::array< System::Windows::Forms::DataGridViewColumn^  >(1) { this->ProductName });
			   this->dataGridView1->Location = System::Drawing::Point(227, 190);
			   this->dataGridView1->Name = L"dataGridView1";
			   this->dataGridView1->RowHeadersWidth = 51;
			   this->dataGridView1->RowTemplate->Height = 24;
			   this->dataGridView1->Size = System::Drawing::Size(421, 290);
			   this->dataGridView1->TabIndex = 6;
			   this->dataGridView1->CellClick += gcnew System::Windows::Forms::DataGridViewCellEventHandler(this, &MyForm::dataGridView1_CellClick);
			   // 
			   // textBoxVendorCode
			   // 
			   this->textBoxVendorCode->Location = System::Drawing::Point(31, 93);
			   this->textBoxVendorCode->Name = L"textBoxVendorCode";
			   this->textBoxVendorCode->Size = System::Drawing::Size(117, 22);
			   this->textBoxVendorCode->TabIndex = 7;
			   // 
			   // textBoxProductName
			   // 
			   this->textBoxProductName->Location = System::Drawing::Point(154, 93);
			   this->textBoxProductName->Name = L"textBoxProductName";
			   this->textBoxProductName->Size = System::Drawing::Size(130, 22);
			   this->textBoxProductName->TabIndex = 8;
			   // 
			   // textBoxTIN
			   // 
			   this->textBoxTIN->Location = System::Drawing::Point(290, 93);
			   this->textBoxTIN->Name = L"textBoxTIN";
			   this->textBoxTIN->Size = System::Drawing::Size(115, 22);
			   this->textBoxTIN->TabIndex = 9;
			   // 
			   // textBoxDay
			   // 
			   this->textBoxDay->Location = System::Drawing::Point(411, 93);
			   this->textBoxDay->Name = L"textBoxDay";
			   this->textBoxDay->Size = System::Drawing::Size(33, 22);
			   this->textBoxDay->TabIndex = 10;
			   // 
			   // textBoxMonth
			   // 
			   this->textBoxMonth->Location = System::Drawing::Point(450, 93);
			   this->textBoxMonth->Name = L"textBoxMonth";
			   this->textBoxMonth->Size = System::Drawing::Size(33, 22);
			   this->textBoxMonth->TabIndex = 11;
			   // 
			   // textBoxYear
			   // 
			   this->textBoxYear->Location = System::Drawing::Point(489, 93);
			   this->textBoxYear->Name = L"textBoxYear";
			   this->textBoxYear->Size = System::Drawing::Size(56, 22);
			   this->textBoxYear->TabIndex = 12;
			   // 
			   // label1
			   // 
			   this->label1->AutoSize = true;
			   this->label1->Location = System::Drawing::Point(40, 118);
			   this->label1->Name = L"label1";
			   this->label1->Size = System::Drawing::Size(91, 17);
			   this->label1->TabIndex = 13;
			   this->label1->Text = L"Vendor Code";
			   // 
			   // label2
			   // 
			   this->label2->AutoSize = true;
			   this->label2->Location = System::Drawing::Point(169, 118);
			   this->label2->Name = L"label2";
			   this->label2->Size = System::Drawing::Size(98, 17);
			   this->label2->TabIndex = 14;
			   this->label2->Text = L"Product Name";
			   // 
			   // label3
			   // 
			   this->label3->AutoSize = true;
			   this->label3->Location = System::Drawing::Point(331, 118);
			   this->label3->Name = L"label3";
			   this->label3->Size = System::Drawing::Size(30, 17);
			   this->label3->TabIndex = 15;
			   this->label3->Text = L"TIN";
			   // 
			   // label4
			   // 
			   this->label4->AutoSize = true;
			   this->label4->Location = System::Drawing::Point(408, 118);
			   this->label4->Name = L"label4";
			   this->label4->Size = System::Drawing::Size(33, 17);
			   this->label4->TabIndex = 16;
			   this->label4->Text = L"Day";
			   // 
			   // label5
			   // 
			   this->label5->AutoSize = true;
			   this->label5->Location = System::Drawing::Point(447, 118);
			   this->label5->Name = L"label5";
			   this->label5->Size = System::Drawing::Size(47, 17);
			   this->label5->TabIndex = 17;
			   this->label5->Text = L"Month";
			   // 
			   // label6
			   // 
			   this->label6->AutoSize = true;
			   this->label6->Location = System::Drawing::Point(500, 118);
			   this->label6->Name = L"label6";
			   this->label6->Size = System::Drawing::Size(38, 17);
			   this->label6->TabIndex = 18;
			   this->label6->Text = L"Year";
			   // 
			   // ProductName
			   // 
			   this->ProductName->HeaderText = L"Product Name";
			   this->ProductName->MinimumWidth = 6;
			   this->ProductName->Name = L"ProductName";
			   this->ProductName->ReadOnly = true;
			   this->ProductName->Width = 125;
			   // 
			   // MyForm
			   // 
			   this->AutoScaleDimensions = System::Drawing::SizeF(8, 16);
			   this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			   this->ClientSize = System::Drawing::Size(924, 502);
			   this->Controls->Add(this->label6);
			   this->Controls->Add(this->label5);
			   this->Controls->Add(this->label4);
			   this->Controls->Add(this->label3);
			   this->Controls->Add(this->label2);
			   this->Controls->Add(this->label1);
			   this->Controls->Add(this->textBoxYear);
			   this->Controls->Add(this->textBoxMonth);
			   this->Controls->Add(this->textBoxDay);
			   this->Controls->Add(this->textBoxTIN);
			   this->Controls->Add(this->textBoxProductName);
			   this->Controls->Add(this->textBoxVendorCode);
			   this->Controls->Add(this->dataGridView1);
			   this->Controls->Add(this->SaveFile);
			   this->Controls->Add(this->LoadFile);
			   this->Controls->Add(this->HTsize);
			   this->Controls->Add(this->textBoxHTSize);
			   this->Controls->Add(this->btnRemove);
			   this->Controls->Add(this->btnAdd);
			   this->Name = L"MyForm";
			   this->Text = L"MyForm";
			   (cli::safe_cast<System::ComponentModel::ISupportInitialize^>(this->dataGridView1))->EndInit();
			   this->ResumeLayout(false);
			   this->PerformLayout();

		   }
#pragma endregion
	private: void FillTable(Node* node)
	{
		if (node != nullptr)
		{
			FillTable(node->left);

			// Добавить данные о продукте в таблицу
			String^ productName = gcnew String(node->key.c_str());
			dataGridView1->Rows->Add(productName);

			FillTable(node->right);
		}
	}
	private: void PopulateTableFromTree()
	{
		// Очистить таблицу перед загрузкой новых данных
		dataGridView1->Rows->Clear();

		// Начать обход дерева с корня
		FillTable(tree->root);
	}

	private: void UpdateTableAfterAddRemove()
	{
		// Обновить таблицу после добавления или удаления элемента из tree
		PopulateTableFromTree();
	}

	private: System::Void btnAdd_Click(System::Object^ sender, System::EventArgs^ e) {
		// Очистить таблицу перед загрузкой новых данных
		dataGridView1->Rows->Clear();

		int newVC;
		std::string newPN;
		long long int newTIN;
		int newDay;
		int newMonth;
		int newYear;
		if (Int32::TryParse(textBoxVendorCode->Text, newVC) && !System::String::IsNullOrWhiteSpace(textBoxProductName->Text) && Int64::TryParse(textBoxTIN->Text, newTIN) && Int32::TryParse(textBoxDay->Text, newDay) && Int32::TryParse(textBoxMonth->Text, newMonth) && Int32::TryParse(textBoxYear->Text, newYear))
		{
			if (newVC > 0 && TIN(newTIN).correct && Date(newDay, newMonth, newYear).correct)
			{
				std::string newPN = msclr::interop::marshal_as<std::string>(textBoxProductName->Text);
				tree->addItem(newVC, newPN, newTIN, newDay, newMonth, newYear);
				UpdateTableAfterAddRemove();
			}
		}
		int size = tree->getSize();

		UpdateTableAfterAddRemove();
	}
	private: System::Void btnRemove_Click(System::Object^ sender, System::EventArgs^ e) {
	}
	private: System::Void textBoxHTSize_TextChanged(System::Object^ sender, System::EventArgs^ e) {
		int newSize;
		if (Int32::TryParse(textBoxHTSize->Text, newSize))
		{
			if (newSize >= 5)
			{
				if (tree->isEmpty())
					tree->setHashTableSize(newSize);
				else
					MessageBox::Show("Tree is not empty.");
			}
		}
	}
	private: System::Void dataGridView1_CellClick(System::Object^ sender, System::Windows::Forms::DataGridViewCellEventArgs^ e)
	{
		if (e->RowIndex >= 0) // Проверяем, что нажата валидная строка
		{
			String^ productName = dataGridView1->Rows[e->RowIndex]->Cells[0]->Value->ToString(); // Получаем название продукта

			if (hashTableForm != nullptr) // Проверяем, что форма HashTableForm уже создана
			{
				hashTableForm->FillHashTableTable(productName);
				hashTableForm->Show(); // Показываем форму HashTableForm
			}
		}
	}
};
}
Код 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) {}

	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(929, 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(979, 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
					}
				}
			}
		}


	};
}

При нажатии на ячейку основной таблицы оконного интерфейса ошибка: "Ссылка на объект не указывает на экземпляр объекта". При отладке обнаружил, что ошибка происходит на строке dataGridView1->Rows->Clear(); метода public: void FillHashTableTable(String^ productName)
Нужно исправить код. Каждая ячейка таблицы интерфейса MyForm должна содержать свою таблицу HashTableForm. Лучше их создавать ещё при добавлении элемента в дерева (Add), и при нажатии только показывать? Ну и при добавлении элемента с тем же именем - обновлять, естественно.