#c# #tree
#c# #дерево
Вопрос:
У меня есть (недвоичное) дерево, содержащее записи со строками.
Я хотел бы создать массивы записей (или указателей на записи), содержащие данные, следующим образом…
Я сделал этот иллюстрированный пример:
ABCDEFGHIJKL
/ |
ABC DE FGHIJKL
/ / |
AB C FGH IJK L
/
I JK
Результат должен быть:
(7 массивов, содержащих записи с этими данными)
- ABCDEFGHIJKL
- ABC, DE, FGHIJKL
- ABC, DE, FGH, I, JK, L
- ABC, DE, FGH, IJK, L
- AB, C, DE, FGHIJKL
- AB, C, DE, FGH, I, JK, L
- AB, C, DE, FGH, IJK, L
Некоторые примечания:
- Меня не волнует порядок результатов (1-7), пока я получаю их все.
- Я работаю с C#
- В этом примере есть 4 уровня с 7 путями, но в реальной жизни это может быть любое количество уровней.
- Шаблон здесь создается
"ABCDEFGHIJKL"
из всех моих комбинаций слева направо.
У кого-нибудь есть предложения?
Комментарии:
1. Существует ли определенный шаблон для данных, которые вы пытаетесь извлечь? Кроме того, ваши массивы # 3 и # 5 идентичны.
2. У вас есть елка или вы хотите ее сделать? И у меня проблемы с определением логики в этих 9 примерах, можете ли вы выразить это словами?
3. Привет! у меня уже есть дерево. и Джим, ты прав … 3 и 5 идентичны, это моя ошибка … пока вы можете видеть схему создания «ABCDEFGHIJKL» из всех его частей, слева направо.
4. Я могу различить 4 уровня и 7 путей, но не ваши 9 результатов. Пожалуйста, перепроверьте, исправьте и опишите, что вы хотите.
5. у меня есть 2 дубликата… поэтому я удалил его … Теперь это правильно. извините!
Ответ №1:
Идея проста. Создайте список, содержащий только корневой узел, затем замените его дочерними элементами. Затем рекурсивно замените каждый узел в этом списке и добавьте этот список в коллекцию результатов при каждой операции замены.
Таким образом, мы получим повторяющиеся результаты в некоторых ветвях, поэтому мы передадим коллекцию результатов через рекурсию и проверим, есть ли уже список текущих узлов. Если это так, то и его производные списки тоже, так что просто верните.
Допустим, у нас есть класс Tree
с узлами класса Node
(у каждого узла есть Children
). Корень дерева есть Root
. Затем вы можете реализовать свою функцию следующим образом (внутри Tree
класса):
public List<List<Node>> GetLevels() {
List<Node> nodes = new List<Node>();
nodes.Add(Root);
List<List<Node>> result = new List<List<Node>>();
GetLevelsCore(nodes, result);
return resu<
}
void GetLevelsCore(List<Node> nodes, List<List<Node>> result) {
if(result.Any(list => list.SequenceEqual(nodes))) return;
result.Add(nodes);
foreach(Node node in nodes) {
if(node.Children.Count != 0) {
List<Node> replacedNodes = new List<Node>(nodes);
int index = replacedNodes.IndexOf(node);
replacedNodes.RemoveAt(index);
replacedNodes.InsertRange(index, node.Children);
GetLevelsCore(replacedNodes, result);
}
}
}
Результаты, которые я получил:
List<List<Node>> result = tree.GetLevels();
List<string> strings = new List<string>(result.Select(nodes => string.Join(", ", nodes.Select(node => node.Value))));
strings
:
- «ABCDEFGHIJKL»
- «ABC, DE, FGHIJKL»
- «AB, C, DE, FGHIJKL»
- «AB, C, DE, FGH, IJK, L»
- «AB, C, DE, FGH, I, JK, L»
- «ABC, DE, FGH, IJK, L»
- «ABC, DE, FGH, I, JK, L»
UPD: замененный содержит проверку с помощью Any(), теперь нет необходимости в средствах сравнения равенства.
Комментарии:
1. Привет, Дмитрий, он здесь не компилируется …. можете ли вы как-нибудь прислать мне исходный код для этого . . я буду признателен. mndlee094@yahoo.com
2. Конечно, отправил его. Может быть, это . Чистая версия или просто использование.
Ответ №2:
Если я вас понимаю, ваше дерево выглядит (потенциально) примерно так, где a .
указывает на узел с дочерними элементами, но без «содержимого», и AB
указывает на узел с текстовым содержимым «AB».
.
/ |
. DE .
/ / |
AB C FGH . L
/
I JK
т. е.: Один корневой узел с 3 дочерними узлами (1 — лист, содержащий текст «DE»).
Я предполагаю, что у вас уже есть ваша структура данных, которая будет представлять собой дерево, где каждый узел может иметь 3 дочерних узла, один родительский и необязательное текстовое поле. Что — то вроде:
class Node
{
// NB: I would not implement the class exactly like this - for illustrative purposes only.
Node Left;
Node Mid;
Node Right;
string Text;
}
Чего вы хотите добиться, так это пройти по дереву и объединить весь текст на определенном уровне или ниже определенного уровня?
Итак, что-то вроде,
- уровень 4: I JK = «IJK»
- уровень 3: AB C FGH (I JK) L = «ABCDFGHIJKL»
- уровень 2: (AB C) DE (FGH (I JK) L) = «ABCDEFGHIJKL»
Чтобы работать с деревьями таким образом, вам, вероятно, придется использовать рекурсию. Вам нужно будет написать рекурсивную функцию для поиска нужных вам узлов, Отслеживания глубины и т. Д. И Выполнения операций с текстом / данными, которые вы хотите.
Полезной помощью для этого было бы заставить каждый узел сохранять свою глубину в дереве при вставке, если у вас есть контроль над ним.
Например, очень простая рекурсивная функция, которая просто находит вам текст всех узлов определенного уровня, может выглядеть примерно так:
//NB: Comes with no warrentee and untested :).
public string TextAtLevel(Node root, int maxLevel, int currentLevel)
{
currentlevel = 1;
if(currentLevel == maxLevel)
{
// stop the recursion, return text of this node
return root.Text;
}
else
{
//Recurse into the child nodes. Left to right, depth first.
return TextAtLevel(root.Left, maxLevel, currentLevel)
TextAtLevel(root.Mid, maxLevel, currentLevel)
TextAtLevel(root.Right, maxLevel, currentLevel)
}
}
Node treeRoot = LoadData(); // imagine tree being populated as per diagram.
string textAtLevel4 = TextAtLevel(treeRoot, 4, 0); // returns "IJK"
Надеюсь, это поможет вам начать работу.
Комментарии:
1. Привет, Xan, все мои узлы содержат данные. и 3 дочерних элемента для некоторых узлов — это просто для простоты… это может быть также меньше или больше. я внимательно изучаю ваш ответ, чтобы найти свои подсказки, чтобы продолжить его. Спасибо.