使用二叉树的级别顺序概念的垂直顺序遍历

时间:2018-06-03 22:02:34

标签: c# c++ tree-traversal

我想垂直遍历二叉树。我在Geeks for Cek中找到了一个工作代码。我想将它转换为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);
    }
}

请注意,我在&#34; VerticalOrderTraversal&#34;方法。 此VerticalOrderTraversal是Vertical Order Traversal in C++

的精确副本
  

异常:密钥已存在于字典

修改

添加此检查后,Logic仍未提供正确的输出

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

4 个答案:

答案 0 :(得分:0)

你有这个:

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

原作有:

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

现在,当我们在documentation中查找运算符std::map::operator[]的内容时,我们发现

  

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

而且重要的是,

  

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

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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我对原始代码进行了一些更改: 1.如果Dict中已经存在级别(hd),则需要将节点添加到列表的末尾,而不要插入新的级别和列表元组。所以我添加了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);
        }
    }
}

}

答案 3 :(得分:0)

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

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