/// <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)); }