/// <summary>
 /// Вставляет значение в определённый узел дерева
 /// </summary>
 /// <param name="data">Значение</param>
 /// <param name="node">Целевой узел для вставки</param>
 /// <param name="parent">Родительский узел</param>
 private void Insert(long data, BinaryTreeP node, BinaryTreeP parent)
 {
     if (node.Data == null || node.Data == data)
     {
         node.Data   = data;
         node.Parent = parent;
         return;
     }
     if (node.Data > data)
     {
         if (node.Left == null)
         {
             node.Left = new BinaryTreeP();
         }
         Insert(data, node.Left, node);
     }
     else
     {
         if (node.Right == null)
         {
             node.Right = new BinaryTreeP();
         }
         Insert(data, node.Right, node);
     }
 }
        private void FormPTree(BinaryTreeP node)
        {
            var queue = new Queue <BinaryTreeP>(); // создать новую очередь

            queue.Enqueue(node);                   // поместить в очередь первый уровень
            while (queue.Count != 0)               // пока очередь не пуста
            {
                //если у текущей ветви есть листья, их тоже добавить в очередь
                if (queue.Peek().Left != null)
                {
                    queue.Enqueue(queue.Peek().Left);
                }
                if (queue.Peek().Right != null)
                {
                    queue.Enqueue(queue.Peek().Right);
                }
                //извлечь из очереди информационное поле последнего элемента
                graph.AddVertex(queue.Peek().Data.ToString()); // убрать последний элемент очереди
                if (queue.Peek().Parent != null)
                {
                    graph.AddEdge(new Edge <string>(queue.Peek().Parent.Data.ToString(), queue.Peek().Data.ToString()));
                }
                queue.Dequeue();
            }
        }
 /// <summary>
 /// Зеркальное отражение дерева
 /// </summary>
 /// <param name="node">Корень дерева</param>
 /// <returns></returns>
 public BinaryTreeP MirrorTree(BinaryTreeP node)
 {
     if (node.Left != null && node.Right != null)
     {
         BinaryTreeP temp = new BinaryTreeP();
         temp       = node.Left;
         node.Left  = node.Right;
         node.Right = temp;
         MirrorTree(node.Right);
         MirrorTree(node.Left);
     }
     else
     {
         if (node.Left == null && node.Right != null)
         {
             return(MirrorTree(node.Right));
         }
         else if (node.Right == null && node.Left != null)
         {
             return(MirrorTree(node.Left));
         }
         else
         {
             return(null);
         }
     }
     return(null);
 }
 /// <summary>
 /// Вставляет целочисленное значение в дерево
 /// </summary>
 /// <param name="data">Значение, которое добавится в дерево</param>
 public void Insert(long data)
 {
     // Если найден свободный узел для вставки значения или значения равны
     if (Data == null || Data == data)
     {
         Data = data;
         return;
     }
     if (Data > data) // Если вставляемое значение меньше значения узла
     {
         if (Left == null)
         {
             Left = new BinaryTreeP();
         }
         Insert(data, Left, this);
     }
     else // Если вставляемое значение больше значения узла
     {
         if (Right == null)
         {
             Right = new BinaryTreeP();
         }
         Insert(data, Right, this);
     }
 }
 /// <summary>
 /// Поиск минимального значения в дереве
 /// </summary>
 /// <param name="node">Узел</param>
 /// <returns>Минимальный узел</returns>
 public BinaryTreeP FindMin(BinaryTreeP node) // Минимальное значение у самого левого
 {
     if (node.Left != null)
     {
         return(FindMin(node.Left));
     }
     return(node);
 }
 /// <summary>
 /// Поиск максимального значения в дереве
 /// </summary>
 /// <param name="node">Узел</param>
 /// <returns>Максимальный узел</returns>
 public BinaryTreeP FindMax(BinaryTreeP node) // Максимальное значение у самого правого
 {
     if (node.Right != null)
     {
         return(FindMax(node.Right));
     }
     return(node);
 }
 /// <summary>
 /// Количество узлов в дереве
 /// </summary>
 /// <param name="node">Корень дерева</param>
 /// <returns></returns>
 public int NumNodes(BinaryTreeP node)
 {
     if (node == null)
     {
         return(0);
     }
     return(NumNodes(node.Left) + 1 + NumNodes(node.Right));
 }
 /// <summary>
 /// Концевой обход (RCL -right, center, left)
 /// </summary>
 /// <param name="node">текущий "элемент дерева" (ref - передача по ссылке)</param>
 /// <param name="s">строка, в которой накапливается результат (ref - передача по ссылке)</param>
 /// <param name="detailed"></param>
 public void RCL(BinaryTreeP node, ref string s, bool detailed)
 {
     if (node != null)
     {
         RCL(node.Right, ref s, detailed); // обойти правое поддерево
         s += node.Data.ToString() + " ";  // запомнить текущее значение
         RCL(node.Left, ref s, detailed);  // обойти левое поддерево
     }
 }
        /// <summary>
        /// Считывание бинарного дерева из файла
        /// </summary>
        /// <returns></returns>
        public BinaryTreeP ReadFile()
        {
            OpenFileDialog open  = new OpenFileDialog(); // save - имя компонента SaveFileDialog
            string         Fname = "";                   // для имени файла

            // задание начальной директории
            open.InitialDirectory = @"С:\";
            // задание свойства Filter
            open.Filter = "txt files (*.txt)|*.txt";
            // задание свойства FilterIndex – выбор типа файла
            open.FilterIndex = 2;
            // свойство Title - название окна диалога выбора файла
            open.Title = "Открыть файл";

            if (open.ShowDialog() == DialogResult.OK)
            { // получаем имя файла для сохранения данных
                Fname = open.FileName;
                FileStream fs = new FileStream(Fname, FileMode.Open, FileAccess.Read);

                if (fs != null) // в случае успеха создания объекта fs
                {               // создаем объект типа StreamReader и
                  // ассоциируем его с объектом fs

                    StreamReader r = new StreamReader(fs);
                    // коллекция для данных из файла
                    List <int> array = new List <int>();
                    while (!r.EndOfStream) // пока нет конца потока
                    {
                        try
                        {
                            array.Add(Convert.ToInt32(r.ReadLine()));
                        }
                        catch (Exception)
                        {
                            MessageBox.Show("Ошибка чтения массива из файла!", "Error");
                        }
                    }
                    r.Close(); fs.Close();
                    BinaryTreeP newTree = new BinaryTreeP();
                    for (int j = 0; j < array.Count; j++)
                    {
                        newTree.Insert(array[j]);
                    }
                    return(newTree);
                }
                else
                {
                    MessageBox.Show("Ошибка чтения из файла!", "Ошибка"); return(this);
                }
            }
            else
            {
                return(this);
            }
        }
        /// <summary>
        /// Левый поворот вокруг узла node
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private BinaryTreeP RotateLeft(BinaryTreeP node)
        {
            if (node.Parent == null)
            {
                node.Right.Parent = null;
            }
            BinaryTreeP p = node.Right;

            node.Right  = p.Left;
            p.Left      = node;
            node.Parent = p;
            return(p);
        }
        /// <summary>
        /// Правый поворот вокруг узла node
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private BinaryTreeP RotateRight(BinaryTreeP node)
        {
            if (node.Parent == null)
            {
                node.Left.Parent = null;
            }
            BinaryTreeP q = node.Left;

            node.Left   = q.Right;
            q.Right     = node;
            node.Parent = q;
            return(q);
        }
        /// <summary>
        /// Количество элементов в определённом узле
        /// </summary>
        /// <param name="node">Узел для подсчета</param>
        /// <returns></returns>
        private long CountElements(BinaryTreeP node)
        {
            long count = 1;

            if (node.Right != null)
            {
                count += CountElements(node.Right);
            }
            if (node.Left != null)
            {
                count += CountElements(node.Left);
            }
            return(count);
        }
        /// <summary>
        /// Формирование графа бинарного дерева поиска на указателях
        /// </summary>
        /// <param name="node"></param>
        /// <param name="select"></param>
        private void DrawBTree(BinaryTreeP node, int?select)
        {
            if (node != null)
            {
                Mgraph.GraphAttr.NodeAttr.Shape = Shape.Circle;
                Node gnode;
                if (node.Parent == null)
                {
                    gnode = Mgraph.AddNode(node.Data.ToString());
                    if (node.Data == select)
                    {
                        gnode.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.Red;
                    }
                }
                else
                {
                    if (node.Parent.Left == node)
                    {
                        gnode = Mgraph.AddNode(node.Data.ToString());
                        if (node.Data == select)
                        {
                            gnode.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.Red;
                        }
                        Edge edge = Mgraph.AddEdge(node.Parent.Data.ToString(), "L", node.Data.ToString());
                        edge.Attr.ArrowHeadAtSource = ArrowStyle.None;
                    }

                    if (node.Parent.Right == node)
                    {
                        gnode = Mgraph.AddNode(node.Data.ToString());
                        if (node.Data == select)
                        {
                            gnode.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.Red;
                        }
                        Edge edge = Mgraph.AddEdge(node.Parent.Data.ToString(), "R", node.Data.ToString());
                        edge.Attr.ArrowHeadAtSource = ArrowStyle.None;
                    }
                }
                if (node.Left != null)
                {
                    DrawBTree(node.Left, select);
                }
                if (node.Right != null)
                {
                    DrawBTree(node.Right, select);
                }
            }
        }
 private int getWidth(BinaryTreeP root, int level)
 {
     if (root == null)
     {
         return(0);
     }
     if (level == 1)
     {
         return(1);
     }
     else if (level > 1)
     {
         return(getWidth(root.Left, level - 1) + getWidth(root.Right, level - 1));
     }
     return(0);
 }
        public int MaxWidth(BinaryTreeP root)
        {
            int maxWidth = 0;
            int width    = 0;
            int h        = Height(root);

            for (int i = 1; i < h; i++)
            {
                width = getWidth(root, i);
                if (width > maxWidth)
                {
                    maxWidth = width;
                }
            }
            return(maxWidth);
        }
 /// <summary>
 /// Определяет, в какой ветви для родительского лежит данный узел
 /// </summary>
 /// <param name="node"></param>
 /// <returns></returns>
 private BinSide?MeForParent(BinaryTreeP node)
 {
     if (node.Parent == null)
     {
         return(null);
     }
     if (node.Parent.Left == node)
     {
         return(BinSide.Left);
     }
     if (node.Parent.Right == node)
     {
         return(BinSide.Right);
     }
     return(null);
 }
 public BinaryTreeForm()
 {
     InitializeComponent();
     AVLtree                    = new AVLTree();
     errorInput                 = new ErrorProvider();
     errorOperation             = new ErrorProvider();
     errorRealisation           = new ErrorProvider();
     Mgraph                     = new Graph("Tree");
     BinaryTree                 = new BinaryTreeP();
     BinaryTreeA                = new BinaryTreeArray();
     timeAVL                    = new OperationTime();
     timeBP                     = new OperationTime();
     timeBA                     = new OperationTime();
     Operations.SelectedIndex   = 0;
     Realisations.SelectedIndex = 0;
 }
        /// <summary>
        /// Ищет значение в определённом узле
        /// </summary>
        /// <param name="data">Значение для поиска</param>
        /// <param name="node">Узел для поиска</param>
        /// <returns></returns>
        private BinaryTreeP Find(long data, BinaryTreeP node)
        {
            if (node == null)
            {
                return(null);
            }

            if (node.Data == data)
            {
                return(node);
            }
            if (node.Data > data)
            {
                return(Find(data, node.Left));
            }
            return(Find(data, node.Right));
        }
 /// <summary>
 /// Метод выполнающий балансировку
 /// </summary>
 /// <param name="node"></param>
 /// <returns></returns>
 public BinaryTreeP Balance(BinaryTreeP node)
 {
     if (BalanceFactor(node) == 2)
     {
         if (BalanceFactor(node.Right) < 0)
         {
             node.Right = RotateRight(node.Right);
         }
         return(RotateLeft(node));
     }
     if (BalanceFactor(node) == -2)
     {
         if (BalanceFactor(node.Left) > 0)
         {
             node.Left = RotateLeft(node.Left);
         }
         return(RotateRight(node));
     }
     return(node);
 }
        /// <summary>
        /// Порядок узла
        /// </summary>
        /// <param name="node">Узел</param>
        /// <param name="order">0</param>
        /// <returns>Порядок узла</returns>
        public int Height(BinaryTreeP node)
        {
            if (node == null)
            {
                return(0);
            }
            else
            {
                int lheight = Height(node.Left);
                int rheight = Height(node.Right);

                if (lheight > rheight)
                {
                    return(lheight + 1);
                }
                else
                {
                    return(rheight + 1);
                }
            }
        }
        /// <summary>
        /// Обход дерева в ширину (итерационно, используется очередь)
        /// </summary>
        /// <param name="node">текущий "элемент дерева" </param>
        /// <param name="s">строка, в которой накапливается результат (ref - передача по ссылке)</param>
        /// <param name="detailed"></param>
        public void Across(BinaryTreeP node, ref string s, bool detailed)
        {
            var queue = new Queue <BinaryTreeP>(); // создать новую очередь

            queue.Enqueue(node);                   // поместить в очередь первый уровень
            while (queue.Count != 0)               // пока очередь не пуста
            {
                //если у текущей ветви есть листья, их тоже добавить в очередь
                if (queue.Peek().Left != null)
                {
                    queue.Enqueue(queue.Peek().Left);
                }
                if (queue.Peek().Right != null)
                {
                    queue.Enqueue(queue.Peek().Right);
                }
                //извлечь из очереди информационное поле последнего элемента
                s += queue.Peek().Data.ToString() + " "; // убрать последний элемент очереди
                queue.Dequeue();
            }
        }
        /// <summary>
        /// Обработчик события смены значения в ComboBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Mgraph = new Graph("Tree");
            switch (Realisations.SelectedIndex) // Если поменялась реализация, то меняем изображение
            {
            case 0:
                AVLtree = AVLtree.ReadFile();
                DrawAVLTree(AVLtree, null);
                break;

            case 1:
                BinaryTree = BinaryTree.ReadFile();
                DrawBTree(BinaryTree, null);
                break;

            case 2:
                BinaryTreeA = BinaryTreeA.ReadFile();
                DrawBATree(1, null);
                break;
            }
            gViewer.Graph = Mgraph;
        }
 private void FileData(BinaryTreeP node, ref List <int> s)
 {
     if (node != null)
     {
         var queue = new Queue <BinaryTreeP>(); // создать новую очередь
         queue.Enqueue(node);                   // поместить в очередь первый уровень
         while (queue.Count != 0)               // пока очередь не пуста
         {
             //если у текущей ветви есть листья, их тоже добавить в очередь
             if (queue.Peek().Left != null)
             {
                 queue.Enqueue(queue.Peek().Left);
             }
             if (queue.Peek().Right != null)
             {
                 queue.Enqueue(queue.Peek().Right);
             }
             //извлечь из очереди информационное поле последнего элемента
             s.Add((int)queue.Peek().Data); // убрать последний элемент очереди
             queue.Dequeue();
         }
     }
 }
        /// <summary>
        /// Обработчик нажатия на кнопку Выполнить
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Calculate_Click(object sender, EventArgs e)
        {
            int    k      = Operations.SelectedIndex;
            int    r      = Realisations.SelectedIndex;
            string result = "";

            // Если дерево пустое, то разрешается только вставка
            if ((AVLtree.Data == null && k != 0 && r == 0) || (BinaryTree.Data == null && k != 0 && r == 1) || (BinaryTreeA.tree[1] == null && k != 0 && r == 2))
            {
                MessageBox.Show("Дерево пусто!", "Ошибка");
                return;
            }

            switch (k)
            {
            case 0:     // Вставка
                if (!CheckInput())
                {
                    return;
                }                                 // Проверка вводимых данных
                switch (r)
                {
                case 0:
                    timeAVL.TimeStart();         // запуск времени
                    AVLtree = AVLtree.Insert(Convert.ToInt32(DataInput.Text));
                    timeAVL.InsertTimeStop();    // остановка времени
                    break;

                case 1:
                    timeBP.TimeStart();         // запуск времени
                    BinaryTree.Insert(Convert.ToInt32(DataInput.Text));
                    timeBP.InsertTimeStop();    // остановка времени
                    break;

                case 2:
                    timeBA.TimeStart();         // запуск времени
                    BinaryTreeA.Insert(Convert.ToInt32(DataInput.Text));
                    timeBA.InsertTimeStop();    // остановка времени
                    break;
                }
                break;

            case 1:
                if (!CheckInput())
                {
                    return;
                }
                switch (r)     // Удаление
                {
                case 0:
                    timeAVL.TimeStart();        // запуск времени
                    AVLtree = AVLtree.Remove(Convert.ToInt32(DataInput.Text));
                    timeAVL.RemoveTimeStop();   // остановка времени
                    break;

                case 1:
                    timeBP.TimeStart();        // запуск времени
                    BinaryTree.Remove(Convert.ToInt32(DataInput.Text));
                    timeBP.RemoveTimeStop();   // остановка времени
                    break;

                case 2:
                    timeBA.TimeStart();
                    BinaryTreeA.RemoveNodeData(Convert.ToInt32(DataInput.Text));
                    timeBA.RemoveTimeStop();         // остановка времени
                    break;
                }
                break;

            case 2:
                int height = 0;
                switch (r)     // Высота дерева
                {
                case 0:
                    height = AVLtree.Height(AVLtree);
                    break;

                case 1:
                    height = BinaryTree.Height(BinaryTree);
                    break;

                case 2:
                    height = BinaryTreeA.Height(1);
                    break;
                }
                result = "Высота дерева = " + height;
                break;

            case 3:
                switch (r)     // Удаление дерева
                {
                case 0:
                    AVLtree = new AVLTree();
                    break;

                case 1:
                    BinaryTree = new BinaryTreeP();
                    break;

                case 2:
                    BinaryTreeA = new BinaryTreeArray();
                    break;
                }
                Mgraph        = new Graph("Tree");
                gViewer.Graph = Mgraph;
                break;

            case 4:
                int width = 0;
                switch (r)     // Максимальная ширина
                {
                case 0:
                    width = AVLtree.MaxWidth(AVLtree);
                    break;

                case 1:
                    width = BinaryTree.MaxWidth(BinaryTree);
                    break;

                case 2:
                    width = BinaryTreeA.MaxWidth(1);
                    break;
                }
                result = "Максимальная ширина дерева = " + width;
                break;

            case 5:
                int nodes = 0;
                switch (r)     // Количество узлов
                {
                case 0:
                    nodes = AVLtree.NumNodes(AVLtree);
                    break;

                case 1:
                    nodes = BinaryTree.NumNodes(BinaryTree);
                    break;

                case 2:
                    nodes = BinaryTreeA.CountElements();
                    break;
                }
                result = "Количество узлов в дереве = " + nodes;
                break;

            case 6:
                if (!CheckInput())
                {
                    return;
                }
                Mgraph = new Graph("Tree");
                switch (r)     // Поиск узла
                {
                case 0:
                    timeAVL.TimeStart();         // запуск времени
                    if (AVLtree.Find(Convert.ToInt32(DataInput.Text)) == null)
                    {
                        timeAVL.FindTimeStop();          // остановка времени
                        result = "Элемент не найден!";
                        DrawAVLTree(AVLtree, null);
                    }
                    else
                    {
                        timeAVL.FindTimeStop();          // остановка времени
                        result = "Элемент найден!";
                        DrawAVLTree(AVLtree, Convert.ToInt32(DataInput.Text));
                    }
                    break;

                case 1:
                    timeBP.TimeStart();         // запуск времени
                    if (BinaryTree.Find(Convert.ToInt32(DataInput.Text)) == null)
                    {
                        timeBP.FindTimeStop();          // остановка времени
                        result = "Элемент не найден!";
                        DrawBTree(BinaryTree, null);
                    }
                    else
                    {
                        timeBP.FindTimeStop();          // остановка времени
                        result = "Элемент найден!";
                        DrawBTree(BinaryTree, Convert.ToInt32(DataInput.Text));
                    }
                    break;

                case 2:
                    timeBA.TimeStart();         // запуск времени
                    if (BinaryTreeA.Find(Convert.ToInt32(DataInput.Text)) == -1)
                    {
                        timeBA.FindTimeStop();          // остановка времени
                        result = "Элемент не найден!";
                        DrawBTree(BinaryTree, null);
                    }
                    else
                    {
                        timeBA.FindTimeStop();          // остановка времени
                        result = "Элемент найден!";
                        DrawBATree(1, Convert.ToInt32(DataInput.Text));
                    }
                    break;
                }
                gViewer.Graph = Mgraph;
                break;

            case 7:
                int max = 0;
                Mgraph = new Graph("Tree");
                switch (r)     // Поиск максимального значения
                {
                case 0:
                    max = (int)AVLtree.FindMax(AVLtree).Data;
                    DrawAVLTree(AVLtree, max);
                    break;

                case 1:
                    max = (int)BinaryTree.FindMax(BinaryTree).Data;
                    DrawBTree(BinaryTree, max);
                    break;

                case 2:
                    max = (int)BinaryTreeA.tree[BinaryTreeA.FindMax(1)];
                    DrawBATree(1, max);
                    break;
                }
                gViewer.Graph = Mgraph;
                result        = "Максимальный элемент = " + max;
                break;

            case 8:
                int min = 0;
                Mgraph = new Graph("Tree");
                switch (r)     // Поиск минимального значения
                {
                case 0:
                    min = (int)AVLtree.FindMin(AVLtree).Data;
                    DrawAVLTree(AVLtree, min);
                    break;

                case 1:
                    min = (int)BinaryTree.FindMin(BinaryTree).Data;
                    DrawBTree(BinaryTree, min);
                    break;

                case 2:
                    min = (int)BinaryTreeA.tree[BinaryTreeA.FindMin(1)];
                    DrawBATree(1, min);
                    break;
                }
                gViewer.Graph = Mgraph;
                result        = "Минимальный элемент = " + min;
                break;

            case 9:
                switch (r)     // Обход в глубину
                {
                case 0:
                    AVLtree.CLR(AVLtree, ref result, false);
                    break;

                case 1:
                    BinaryTree.CLR(BinaryTree, ref result, false);
                    break;

                case 2:
                    BinaryTreeA.CLR(1, ref result, false);
                    break;
                }
                break;

            case 10:
                switch (r)     // Обход в глубину
                {
                case 0:
                    AVLtree.LCR(AVLtree, ref result, false);
                    break;

                case 1:
                    BinaryTree.LCR(BinaryTree, ref result, false);
                    break;

                case 2:
                    BinaryTreeA.LCR(1, ref result, false);
                    break;
                }
                break;

            case 11:
                switch (r)     // Обход в глубину
                {
                case 0:
                    AVLtree.RCL(AVLtree, ref result, false);
                    break;

                case 1:
                    BinaryTree.RCL(BinaryTree, ref result, false);
                    break;

                case 2:
                    BinaryTreeA.RCL(1, ref result, false);
                    break;
                }
                break;

            case 12:
                switch (r)     // Обход в ширину
                {
                case 0:
                    AVLtree.Across(AVLtree, ref result, false);
                    break;

                case 1:
                    BinaryTree.Across(BinaryTree, ref result, false);
                    break;

                case 2:
                    BinaryTreeA.Across(1, ref result, false);
                    break;
                }
                break;

            case 13:
                switch (r)     // Зеркальное отражение дерева
                {
                case 0:
                    AVLtree.MirrorTree(AVLtree);
                    break;

                case 1:
                    BinaryTree.MirrorTree(BinaryTree);
                    break;

                case 2:
                    BinaryTreeA.MirrorTree(1);
                    break;
                }
                break;

            default:
                return;
            }
            if (k == 0 || k == 1 || k == 13) // Если внешний вид дерева изменился, то перерисовываем дерево
            {
                Mgraph = new Graph("Tree");
                switch (r)
                {
                case 0:
                    DrawAVLTree(AVLtree, null);
                    break;

                case 1:
                    DrawBTree(BinaryTree, null);
                    break;

                case 2:
                    DrawBATree(1, null);
                    break;
                }
                gViewer.Graph = Mgraph;
            }
            else
            {
                Results.Text = result;
            }
        }
        /// <summary>
        /// Удаляет узел из дерева
        /// </summary>
        /// <param name="node">Удаляемый узел</param>
        public void Remove(BinaryTreeP node)
        {
            if (node == null)
            {
                return;
            }
            var me = MeForParent(node);

            //Если у узла нет дочерних элементов, его можно смело удалять
            if (node.Left == null && node.Right == null)
            {
                if (me == BinSide.Left)
                {
                    node.Parent.Left = null;
                }
                else
                {
                    node.Parent.Right = null;
                }
                return;
            }
            //Если нет левого дочернего, то правый дочерний становится на место удаляемого
            if (node.Left == null)
            {
                if (me == BinSide.Left)
                {
                    node.Parent.Left = node.Right;
                }
                else
                {
                    node.Parent.Right = node.Right;
                }

                node.Right.Parent = node.Parent;
                return;
            }
            //Если нет правого дочернего, то левый дочерний становится на место удаляемого
            if (node.Right == null)
            {
                if (me == BinSide.Left)
                {
                    node.Parent.Left = node.Left;
                }
                else
                {
                    node.Parent.Right = node.Left;
                }

                node.Left.Parent = node.Parent;
                return;
            }

            //Если присутствуют оба дочерних узла
            //то правый ставим на место удаляемого
            //а левый вставляем в правый

            if (me == BinSide.Left)
            {
                node.Parent.Left = node.Right;
            }
            if (me == BinSide.Right)
            {
                node.Parent.Right = node.Right;
            }
            if (me == null)
            {
                var bufLeft       = node.Left;
                var bufRightLeft  = node.Right.Left;
                var bufRightRight = node.Right.Right;
                node.Data  = node.Right.Data;
                node.Right = bufRightRight;
                node.Left  = bufRightLeft;
                Insert(bufLeft, node, node);
            }
            else
            {
                node.Right.Parent = node.Parent;
                Insert(node.Left, node.Right, node.Right);
            }
        }
 /// <summary>
 /// Вычисляет фактор баланса для заданного узла
 /// </summary>
 /// <param name="node"></param>
 /// <returns></returns>
 private int BalanceFactor(BinaryTreeP node)
 {
     return(Height(node.Right) - Height(node.Left));
 }