public async void BoruvkaAlgorithmVisAsync()
        {
            if (!graph.IsConnected)
            {
                visualisator.Print("Остовное дерево не может быть построено. Граф не связен!");
                visualisator.ApEndLog("Остовное дерево не может быть построено. Граф не связен!");
                return;
            }
            form.BlockTabControl();
            int order             = graph.Order;
            Graph <VisVertex> mst = new Graph <VisVertex>(graph.VerticesClone);
            //Создаем МОД с вершинами графа
            DisjointSetB dsu = new DisjointSetB(order);
            //Создаем DSU_B для поиска компонеты, включающей элемент и хранения нового адреса списка
            var asl = GetAdjLists(graph);

            //Создаем массив сортированных списков смежности для вершин графа
            bool[] isUsed;//Отмечаем в массиве элементы использованные на текущей итерации
            int    currentIndex = 0;
            //Индекс для помещения объединенного списка смежности в начало массива
            bool HasEdge2Add = true;
            //Переменная для выхода из цикла при отсутствии ребер для добавления в МОД

            int stepCounter      = 1;
            int componentCounter = order;

            SetVerticesDifferentColors();
            visualisator.Print("Маркировка вершин");
            visualisator.ApEndLog("МОД сотоит из отдельных вершин - компонент связности, " +
                                  "маркированных различными цветами" +
                                  "\nДля каждой компоненты найдем наименьшее по весу ребро, " +
                                  "соединяющее ее с другой компонентой.");
            visualisator.PrintDataStructuresBoruvka(asl, dsu, colors);
            await Task.Delay(SleepInterval);

            while (mst.EdgesCount < order - 1 && HasEdge2Add)
            {
                visualisator.ApEndLog($"Шаг {stepCounter++}. " +
                                      $"Количество компонент связности {componentCounter}.");
                componentCounter = 0;
                isUsed           = new bool[order];
                //Для каждой итерации отмечаем все компоненты, как неиспользованные
                HasEdge2Add = false;
                //Обновляем флаг для проверки наличия ребер
                currentIndex = 0;
                //Обновляем индекс для помещения объединенных списков в начало массива
                for (int i = 0; i < order && asl[i] != null; i++)
                //Для каждой компоненты связности
                {
                    if (asl[i].IsEmpty || isUsed[i])
                    {
                        visualisator.ApEndLog(
                            $"    Компонента №{++componentCounter} уже использована.");
                        continue;
                    }
                    int listAddress2 = dsu.GetIndex(asl[i].MinWeightEdge.V2Id);
                    HasEdge2Add = true;
                    isUsed[i]   = true;
                    //Отмечаем компонету, как использованную
                    Edge <VisVertex> edge2Add = asl[i].ExtractMinWeightEdge();
                    //Извлекаем минимальное ребро текущей компоненты
                    visualisator.ApEndLog($"    Для компоненты №{++componentCounter} " +
                                          $"добавляем в МОД ребро {edge2Add}. Объединяем компоненты");
                    mst.AddEdge(edge2Add);
                    //Добавляем извлеченное ребро в МОД
                    if (isUsed[listAddress2])
                    //Если компонента с которой планируется объединение
                    //уже была объединена на этой итерации
                    {
                        dsu.UnionSets(edge2Add.V1Id, edge2Add.V2Id, listAddress2);
                        //Объединяем текущую компонету и присоединенную извлеченным ребром
                        asl[listAddress2] = asl[i].Union(asl[listAddress2], dsu);
                        //Объединяем сортированные списки смежности объединенных компонент
                        continue;
                    }
                    dsu.UnionSets(edge2Add.V1Id, edge2Add.V2Id, currentIndex);
                    //Объединяем текущую компонету и присоединенную извлеченным ребром
                    asl[currentIndex++] = asl[i].Union(asl[listAddress2], dsu);
                    //Объединяем сортированные списки смежности объединенных компонент
                    //Объединенный список помещаем в начало массива, за последним объединенным,
                    //отмечаем элементы как использованные,указываем индекс объединенного списка
                }
                if (currentIndex < order)
                {
                    asl[currentIndex] = null;
                }
                //После последнего объединенного списка вставляем null,
                //чтобы на следующей итерации не проходить дальше
                componentCounter = currentIndex + 1;
                RefreshColors(dsu, mst);
                visualisator.Print(
                    $"Объединение компонент связности. Всего ребер {mst.EdgesCount}." +
                    $" Общий вес {mst.TotalWeight}.");
                visualisator.PrintDataStructuresBoruvka(asl, dsu, colors);
                await Task.Delay(SleepInterval);
            }
            if (mst.EdgesCount < order - 1)
            {
                throw new Exception("Ошибка МОД не найдено");
            }
            else
            {
                visualisator.Print($"Минимальное остовное дерево построено. " +
                                   $"Общий вес {mst.TotalWeight}.");
                visualisator.ApEndLog($"Минимальное остовное дерево построено. " +
                                      $"Общий вес {mst.TotalWeight}.");
                visualisator.PrintDataStructuresBoruvka(asl, dsu, colors);
            }
            form.UnBlockTabControl();
        }
        public static Graph <VisVertex> GetMST_Boruvka(Graph <VisVertex> graph)
        {
            int order             = graph.Order;
            Graph <VisVertex> mst = new Graph <VisVertex>(graph.VerticesClone);
            //Создаем МОД с вершинами графа
            DisjointSetB dsu = new DisjointSetB(order);
            //Создаем DSU_B для поиска компонеты, включающей элемент и хранения нового адреса списка
            var asl = GetAdjLists(graph);

            //Создаем массив сортированных списков смежности для вершин графа
            bool[] isUsed;
            //Отмечаем в массиве элементы использованные на текущей итерации
            int currentIndex = 0;
            //Индекс для помещения объединенного списка смежности в начало массива
            bool HasEdge2Add = true;

            //Переменная для выхода из цикла при отсутствии ребер для добавления в МОД
            while (mst.EdgesCount < order - 1 && HasEdge2Add)
            {
                isUsed = new bool[order];
                //Для каждой итерации отмечаем все компоненты, как неиспользованные
                HasEdge2Add = false;
                //Обновляем флаг для проверки наличия ребер
                currentIndex = 0;
                //Обновляем индекс для помещения объединенных списков в начало массива
                for (int i = 0; i < order && asl[i] != null; i++)//Для каждой компоненты связности
                {
                    if (asl[i].IsEmpty || isUsed[i])
                    {
                        continue;
                    }
                    int listAddress2 = dsu.GetIndex(asl[i].MinWeightEdge.V2Id);
                    HasEdge2Add = true;
                    isUsed[i]   = true;//Отмечаем компонету, как использованную
                    Edge <VisVertex> edge2Add = asl[i].ExtractMinWeightEdge();
                    //Извлекаем минимальное ребро текущей компоненты
                    mst.AddEdge(edge2Add);//Добавляем извлеченное ребро в МОД
                    if (isUsed[listAddress2])
                    //Если компонента с которой планируется объединение уже
                    //была объединена на этой итерации
                    {
                        dsu.UnionSets(edge2Add.V1Id, edge2Add.V2Id, listAddress2);
                        //Объединяем текущую компонету и присоединенную извлеченным ребром
                        asl[listAddress2] = asl[i].Union(asl[listAddress2], dsu);
                        //Объединяем сортированные списки смежности объединенных компонент
                        continue;
                    }
                    dsu.UnionSets(edge2Add.V1Id, edge2Add.V2Id, currentIndex);
                    //Объединяем текущую компонету и присоединенную извлеченным ребром
                    asl[currentIndex++] = asl[i].Union(asl[listAddress2], dsu);
                    //Объединяем сортированные списки смежности объединенных компонент
                    //Объединенный список помещаем в начало массива, за последним объединенным,
                    //отмечаем элементы как использованные,указываем индекс объединенного списка
                }
                if (currentIndex < order)
                {
                    asl[currentIndex] = null;
                }
                //После последнего объединенного списка вставляем null,
                //чтобы на следующей итерации не проходить дальше
            }
            if (mst.EdgesCount < order - 1)
            {
                throw new Exception("Ошибка МОД не найдено");
            }
            return(mst);
        }