Итак, важно то, что здесь важно упорядочить узлы по глубине, а затем их первоначальным порядком слева направо.
Поскольку вы не определить Node
класс, я использовал следующие шахтное:
public class Node
{
public Node()
{
Children = new List<Node>();
}
public string Value { get; set; }
public List<Node> Children { get; set; }
}
Первое, что мы хотим сделать, это создать метод для обхода дерева. Нам нужны все листовые узлы (без каких-либо нелистовых узлов), и мы также хотим знать глубину каждого узла. Это достаточно просто изменить традиционный алгоритм обхода соответственно:
public static IEnumerable<Tuple<Node, int>> TraverseLeavesWithDepth(Node root)
{
var queue = new Queue<Tuple<Node, int>>();
queue.Enqueue(Tuple.Create(root, 0));
while (queue.Any())
{
var next = queue.Dequeue();
foreach (var child in next.Item1.Children)
{
queue.Enqueue(Tuple.Create(child, next.Item2 + 1));
}
if (!next.Item1.Children.Any())
yield return next;
}
}
Теперь это ширина первого поиска, что означает, что они на самом деле в обратном порядке глубины, но мы исправим это позже.
Теперь, чтобы создать новое дерево.Мы можем взять результаты нашего предыдущего метода и просто упорядочить по глубине (по убыванию), чтобы получить нужные нам предметы в том порядке, в котором они нам нужны.
Оттуда мы просто перебираем результаты, беря каждый лист, связывая его с предыдущим узлом, а затем создаем нового родителя для представления этой пары (а затем используя этот родительский элемент как новый «предыдущий» узел).
public static Node Straighten(Node root)
{
var nodes = TraverseLeavesWithDepth(root)
.OrderByDescending(pair => pair.Item2)
.Select(pair => pair.Item1);
using (var iterator = nodes.GetEnumerator())
{
if (!iterator.MoveNext())
return null;
var previous = iterator.Current;
while (iterator.MoveNext())
{
var next = iterator.Current;
var parent = new Node();
parent.Value = new string(previous.Value
.AsEnumerable().Concat(next.Value)
.OrderBy(c => c)
.ToArray());
parent.Children.Add(previous);
parent.Children.Add(next);
previous = parent;
}
return previous;
}
}
Фактическое строительство узлов, вероятно, различаются в зависимости от реализации узла (и вы также можете воссоздать листья, а не ссылки на старые, как я).
Откуда взялись узлы «ABCDE» и «ABCD»? –
@ChrisSinclair: они созданы во время разбора выражения. Но они не являются существенными, важно только правильный порядок листовых узлов. – joe
Извините, но я не понимаю, что-то. На втором дереве последний символ отбрасывал новый лист, внезапно от ** ABC ** он обрезал ** A **. , , Я что-то пропустил? – Fallen