Как найти следующий узел в дереве? - PullRequest
2 голосов
/ 06 августа 2020

Проблема выглядит так:

У нас есть дерево, построенное с использованием класса Node, где экземпляр класса представляет собой узел в дереве. Для простоты узел имеет одно поле данных типа int. Ваша задача - написать метод расширения NodeExtensions.Next () для поиска следующего элемента в дереве. Вы можете написать столько вспомогательных методов, сколько захотите, но не меняйте сигнатуру метода расширения NodeExtensions.Next ().

У меня есть этот класс Node:

public class Node
{
    private List<Node> _children;

    public Node(int data, params Node[] nodes)
    {
        Data = data;
        AddRange(nodes);
    }

    public Node Parent { get; set; }

    public IEnumerable<Node> Children
    {
        get
        {
            return _children != null
                ? _children
                : Enumerable.Empty<Node>();
        }
    }

    public int Data { get; private set; }

    public void Add(Node node)
    {
        Debug.Assert(node.Parent == null);

        if (_children == null)
        {
            _children = new List<Node>();
        }

        _children.Add(node);
        node.Parent = this;
    }

    public void AddRange(IEnumerable<Node> nodes)
    {
        foreach (var node in nodes)
        {
            Add(node);
        }
    }

    public override string ToString()
    {
        return Data.ToString();
    }
}

Решением должен быть метод расширения, такой как этот

      public static Node Next(this Node node)
    {

    }

Код, который я пробовал:

  public static Node Next(this Node node)
    {
        var newNode = NextLargerElement(node, node.Data);

        return newNode;
    }

    public static Node res;
    public static Node NextLargerElementUtil(Node root, int x) 
    {
        if (root == null)
            return null;

        if (root.Data > x)
            if ((res == null || (res).Data > root.Data))
                res = root;

        foreach (var children in root.Children)
        {
            NextLargerElementUtil(children, x);
        }

        return res;
    }

    static Node NextLargerElement(Node root, int x)
    {
        res = null;

        NextLargerElementUtil(root, x);

        return res;
 }   

Вот пример тестирования:

    [Test]
    public void Test()
    {
        // Test tree:
        // 
        // 1
        // +-2
        //   +-3
        //   +-4
        // +-5
        //   +-6
        //   +-7
        //
        var root = new Node(
            1,
            new Node(
                2,
                new Node(3),
                new Node(4)),
            new Node(
                5,
                new Node(6),
                new Node(7)));

        // Expected output:
        //
        // 1
        // 2
        // 3
        // 4
        // 5
        // 6
        // 7
        //
        var n = root;
        while (n != null)
        {
            Console.WriteLine(n.Data);
            n = n.Next();
        }

        // Test
        //
        n = root;
        Assert.AreEqual(1, n.Data);
        n = n.Next();
        Assert.AreEqual(2, n.Data);
        n = n.Next();
        Assert.AreEqual(3, n.Data);
        n = n.Next();
        Assert.AreEqual(4, n.Data);
        n = n.Next();
        Assert.AreEqual(5, n.Data);
        n = n.Next();
        Assert.AreEqual(6, n.Data);
        n = n.Next();
        Assert.AreEqual(7, n.Data);
        n = n.Next();
        Assert.IsNull(n);
    }

1 Ответ

2 голосов
/ 06 августа 2020

Вы можете использовать Equals, чтобы отследить текущую позицию вашего узла в дереве и вернуть его следующего дочернего родительского элемента, если таковой имеется, если его нет, вам нужно отследить текущую родительскую позицию узла и так далее:

public static Node Next(this Node node)
{
    if(node.Children != null && node.Children.Any())
    {
        return node.Children.First();
    }
    
    // "backtracking", also can be done recursively
    var parent = node.Parent;
    while(parent != null)
    {
        var returnNext = false; // return next element in Children if current is node
        foreach (var element in parent.Children)
        {
            if(returnNext)
            {
                return element;
            }
            
            if(element == node)
            {
                returnNext = true;
                node = parent; // to find parent's position if there is no next child
            }
        }
        parent = parent.Parent;
    }
    
    return null;
}
...