繁体   English   中英

使用二叉树层序概念的垂直序遍历

[英]Vertical Order Traversal in using Level Order Concept of Binary Tree

我想垂直遍历二叉树。 我在 Geeks for Geeks in C++ 中找到了一个工作代码。 我想将其转换为 C#,但我无法这样做。 请指导我。

以下是我的尝试:

// we always need the address of the Root Node come what may!
public class BstNode
{
    public int data      { get; set; }
    public BstNode left  { get; set; }
    public BstNode right { get; set; }

    public BstNode(int value) => data = value;
}

public class BstTree
{
    // For BST
    public BstNode Insert(BstNode root, int data)
    {
        if (root == null)
        {
            root       = new BstNode(data);
            root.left  = null;
            root.right = null;
        }
        else if (data > root.data)
             root.right = Insert(root.right, data);
        else root.left = Insert(root.left, data);

        return root;
    }
    // PROBLEM IN BELOW CODE
    public void VerticalOrderTraverse(BstNode root)
    {
        // Base case
        if (root == null)
            return;

        // Create a map and store vertical oder in
        Dictionary<int, List<int>> dict = new Dictionary<int, List<int>>();
        int hd = 0;

        // Create queue to do level order traversal.
        // Every item of queue contains node and
        // horizontal distance.
        Queue<Tuple<BstNode, int>> que = new Queue<Tuple<BstNode, int>>();
        que.Enqueue(new Tuple<BstNode, int>(root, hd));
        while (que.Count != 0)
        {
            // pop from queue front
            Tuple<BstNode, int> temp = que.Peek();
            que.Dequeue();
            hd = temp.Item2;
            BstNode node = temp.Item1;

            // insert this node's data in vector of hash
            dict.Add(hd, new List<int>(node.data)); // CONFUSED HERE

            if (node.left != null)
                que.Enqueue(new Tuple<BstNode, int>(node.left, hd - 1));
            if (node.right != null)
                que.Enqueue(new Tuple<BstNode, int>(node.right, hd + 1));
        }
        foreach (var item in dict)
            foreach (var ite in item.Value)
                Console.WriteLine(ite);
    }
}

class Program
{
    public static void Main()
    {
        BstNode root = null;
        BstTree bstTree = new BstTree();
        root = bstTree.Insert(root, 10);
        root = bstTree.Insert(root, 12);
        root = bstTree.Insert(root, 7);
        root = bstTree.Insert(root, 8);
        root = bstTree.Insert(root, 15);
        root = bstTree.Insert(root, 11);
        root = bstTree.Insert(root, 6);
        bstTree.VerticalOrderTraverse(root);
    }
}

请注意,我在“VerticalOrderTraversal”方法中遇到异常。 这个 VerticalOrderTraversal 是C++垂直顺序遍历的精确复制品

例外:键已存在于字典中

编辑:

添加此检查后,逻辑仍然没有给出正确的输出

if (dict.ContainsKey(hd))
     dict[hd].Add(node.data);
else dict.Add(hd, new List<int>(node.data));

你有这个:

dict.Add(hd, new List<int>(node.data));

原文是这样的:

m[hd].push_back(node->key);

现在,当我们在文档中查找操作符std::map::operator[]作用时,我们发现

如果 k 与容器中元素的键匹配,则该函数返回对其映射值的引用。

并且重要的是,

如果 k 与容器中任何元素的键都不匹配,则该函数会插入一个具有该键的新元素

Dictionary<TKey, TValue>.Item的索引器具有相同的功能(“集合操作创建具有指定键的新元素”),但在 C++ 中,这意味着构建一个新向量作为新元素的值,C# 不会为我们创建List<int>的实例,因此一个简单的解决方案可能是:

if (dict.ContainsKey(hd))
     dict[hd].Add(node.data);
else dict.Add(hd, new List<int>(node.data));
 /// <summary>
    /// We must calculate horizontal distance.
    /// Each node along with its hd shall be queued.
    /// Add hd and values in one hashset.
    /// </summary>
    /// <param name="root"></param>
    public void VerticalOrderTraversal(Node<T> root)
    {
        if (root == null)
            return;

        int hd = 0;
        Queue<Tuple<Node<T>,int>> q = new Queue<Tuple<Node<T>,int>>();
        Dictionary<int, HashSet<T>> ht = new Dictionary<int, HashSet<T>>();
        q.Enqueue(new Tuple<Node<T>, int>(root,hd));
        ht[hd] = new HashSet<T>();
        ht[hd].Add(root.Data);
        while (q.Count > 0)
        {
            Tuple<Node<T>, int> current = q.Peek();
            q.Dequeue();

            if (current.Item1.leftNode != null)
            {
                if (!ht.ContainsKey(current.Item2 -1))
                {
                    ht[current.Item2 - 1] = new HashSet<T>();
                    ht[current.Item2 - 1].Add(current.Item1.leftNode.Data);
                }
                else
                {
                    ht[current.Item2 - 1].Add(current.Item1.leftNode.Data);
                }
                q.Enqueue(new Tuple<Node<T>, int>(current.Item1.leftNode, current.Item2 - 1));


            }
            if (current.Item1.rightNode != null)
            {
                if (!ht.ContainsKey(current.Item2 + 1))
                {
                    ht[current.Item2 + 1] = new HashSet<T>();
                    ht[current.Item2 + 1].Add(current.Item1.rightNode.Data);
                }
                else
                {
                    ht[current.Item2 + 1].Add(current.Item1.rightNode.Data);
                }
                q.Enqueue(new Tuple<Node<T>, int>(current.Item1.rightNode, current.Item2 + 1));

            }
        }

        foreach (int key in ht.Keys)
        {
            foreach (T data in ht[key])
            {
                Console.WriteLine("Vertical Level " + key + " value " + data);
            }
        }
    }

我对原始代码做了一些更改:

  1. 如果 Dict 中已经存在 level (hd),我们需要将节点添加到列表的末尾,而不是插入新的 l​​evel 和 list 元组。 所以我添加了 if 语句 [if (dict.ContainsKey(hd))]

  2. 最好使用排序字典,以便打印将从最低级别而不是从插入的第一级别开始。

  3. 在原始代码中,列表是在插入 Dict 时创建的,这是一个问题,因为 node.data 将被视为列表的容量而不是列表中的数据。

     public void VerticalOrderTraverse(BstNode root) { // Base case if (root == null) return; // Create a map and store vertical oder in SortedDictionary<int, List<int>> dict = new SortedDictionary<int, List<int>>(); //used Sorted Dictionary int hd = 0; Queue<Tuple<BstNode, int>> que = new Queue<Tuple<BstNode, int>>(); que.Enqueue(new Tuple<BstNode, int>(root, hd)); while (que.Count != 0) { Tuple<BstNode, int> temp = que.Peek(); que.Dequeue(); hd = temp.Item2; BstNode node = temp.Item1; if (dict.ContainsKey(hd)) //No need to try creating a new list, add it to the existing dict[hd].Add(node.data); else { dict.Add(hd, new List<int>()); dict[hd].Add(node.data); } if (node.left != null) que.Enqueue(new Tuple<BstNode, int>(node.left, hd - 1)); if (node.right != null) que.Enqueue(new Tuple<BstNode, int>(node.right, hd + 1)); } foreach (var item in dict) foreach (var ite in item.Value) Console.WriteLine(ite); } } } }
public class Solution {
    
    public IList<IList<int>> result = new List<IList<int>>();
    public SortedDictionary<int, List<int>> IndexingItems = new SortedDictionary<int, List<int>>();
        
    public IList<IList<int>> VerticalTraversal(TreeNode root)
    {
        if(root == null) return result;
        Queue<(int, TreeNode)> queue = new Queue<(int, TreeNode)>();
        int hDis = 0;
        queue.Enqueue((hDis, root));
        
        while(queue.Count != 0)
        {
            (int, TreeNode) qTop = queue.Peek();
            queue.Dequeue();
            hDis = qTop.Item1;
            TreeNode current = qTop.Item2;
            AddItemToDictionary(hDis, current);
            
            if(current.left != null)
            {
                queue.Enqueue((hDis - 1, current.left));
            }
            
            if(current.right != null)
            {
                queue.Enqueue((hDis + 1, current.right));
            }
        }
        
        foreach(var item in IndexingItems)
        {
            var value = item.Value as List<int>;            
            result.Add(value);
        }
        return result;
    }
    
    public void AddItemToDictionary(int hDis, TreeNode node)
    {
        if(IndexingItems.ContainsKey(hDis))
        {
            IndexingItems[hDis].Add(node.val);
            // Console.WriteLine($"Updating {hDis} value");
        }
        else
        {
            // Console.WriteLine($"Adding new item {hDis} to Dictionary with {node.val} value");
            IndexingItems.Add(hDis, new List<int>(){ node.val });
        }
    }
}

我尝试过这种方法。 但我不确定,为什么相同节点的数据顺序有一些不匹配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM