给定二叉树中的垂直和

时间:2013-01-23 17:03:29

标签: algorithm data-structures binary-tree

给定二叉树,找到同一垂直线上的节点的垂直和。通过不同的垂直线打印所有总和。

要了解相同的垂直线,我们需要先定义水平距离。如果两个节点具有相同的水平距离(HD),则它们位于同一垂直线上。 HD的想法很简单。根的HD为0,右边缘(连接到右子树的边缘)被认为是+1水平距离而左边缘被认为是-1水平距离。例如,在上面的树中,节点4的HD为-2,节点2的HD为-1,5和6的HD为0,节点7的HD为+2。

示例:

    1
  /   \
 2     3
/ \   / \
4  5  6  7

树有5条垂直线

Vertical-Line-1只有一个节点4 =>垂直和是4

Vertical-Line-2:只有一个节点2 =>垂直和是2

Vertical-Line-3:有三个节点:1,5,6 =>垂直和是1 + 5 + 6 = 12

Vertical-Line-4:只有一个节点3 =>垂直和是3

Vertical-Line-5:只有一个节点7 =>垂直和是7

因此预期产出为4,2,12,3和7

我的解决方案: 我想出了这个问题的o(nlong(n))解决方案。这个想法是:

(1)使用preorder遍历获取每个节点的HD,并将HD及其相关节点存储在一个数组中。

(2)按HD排序数组

(3)遍历排序的数组以打印结果。

我确信这不是解决这个问题的最佳方法。任何人都可以帮我提供更好的解决方案吗?

10 个答案:

答案 0 :(得分:11)

你不能在第一次遍历中全部完成吗?定义从HD到sum的字典(哈希映射)。 对于您访问的每个节点,将其值添加到正确的字典键 - 这是O(n)解决方案。

d = {}

def traverse(node, hd):
  if not node:
    return
  if not hd in d:
    d[hd] = 0
  d[hd] = d[hd] + node.value
  traverse(node.left, hd - 1)
  traverse(node.right, hd + 1)

然后只需致电traverse(root, 0)

答案 1 :(得分:0)

这是C中的一个。返回后的vsum数组将有结果。

void vsum(struct tree *t, int vsum[], int depth)     {

    if (t == NULL)
        return;

    vsum[depth] += t->val;
    depth++;

    vsum(t->left, vsum, depth);
    vsum(t->right, vsum, depth);

}

答案 2 :(得分:0)

使用级别顺序遍历,使用具有元素的队列以及与其HD值相邻的队列。以下算法将给出O(n)[未经过运行测试]

的解决方案
void findVertSum( struct node *root)
{
 enqueue(root);
 enqueue(0);
 while(!isEmptyQueue())
 {
   tempnode = dequeue();
   vertIndex = dequeue();

   sum[vertIndex] += tempnode->val;  
       // Array cant be used because there will be sum[-1], sum[-2] etc, which will give error. This line hense only gives the idea to store solution.

   if(t->left)
   {
     enqueue(t->left);
     enqueue(vertIndex - 1);
   }

   if(t->right)
   {
     enqueue(t->right);
     enqueue(vertIndex + 1);
   }
}

答案 3 :(得分:0)

这是我在O(n)`

中运行的解决方案
 #include <iostream>
 #include <vector>
 using namespace std;

 vector<int> v;
 int size;

typedef struct node
{
int data;
struct node *left, *right ;
} node, *ptr;



ptr newNode(int item)
{
ptr temp =  new node;
temp->data = item;
temp->left = temp->right = NULL;
return temp;
}

void printVerticalSumUtil(ptr root, int line)
{

if (root == NULL) return;
else
{

    v[line] += root->data;
    printVerticalSumUtil(root->left, line - 1);
    printVerticalSumUtil(root->right, line + 1);
}


}

void printVerticalSum(ptr root)
{
if (root == NULL)
    return;

//Calculating the line No for the root
ptr curr = root;
int line = 0;
while (curr->left != NULL)
{
    curr = curr->left;
    line++;
}
size = 2 * line + 1;  //Total No of Lines
line++;      //Adjusting line no for root

for (int i = 1; i <= size; ++i)   //Initializing lines to zero
    v.push_back(0);

printVerticalSumUtil(root, line);

for (int i = 1; i <= size; ++i)
{
    cout << "Sum of Line " << i << " is " << v[i] << endl;
}
}

int main()
{

ptr root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);

printVerticalSum(root);

return 0;
}`

答案 4 :(得分:0)

#define HD_OFFSET 16

void vertical_sum(Node *node, int hd, int sum[], int *min, int *max){

/* We are offseting the index to access array correctly.
Root will be at HD_OFFSET/2 index and all vertical lines on left will
be at 0 to HD_OFFSET/2 and right side will be on HD_OFFSET/2 to HD_OFFSET */

int index = hd + HD_OFFSET/2;

if(!node) return;

/* to keep track of min and max index filled in sum array */
if(index > (*max)) (*max) = index;
if(index < (*min)) (*min) = index;

sum[index]+= node->value;
/*If we are moving on the left side, 
we will pass index as one less the current */
vertical_sum(node->left, hd-1, sum, min, max);

/*If we are moving on the right side, 
we will pass index as one more the current */
vertical_sum(node->right, hd+1, sum, min, max);
}

答案 5 :(得分:0)

对于迟到的解决方案感到抱歉。 有几种方法可以解决这个问题。 Itay Karo已经使用hashmap提供了一个很好的解决方案。您还可以使用双向链接列表:

  • 从根节点开始,清空双列表listNode
  • 将rootNode的值添加到当前listNode
  • 现在,无论何时离开,都要传递listNode.left和root.left,并递归调用step1和2。
  • 同样对于右侧节点,传递listNode.right和root.right 这是代码:

printVerticalSum(TreeNode root)
{
   if(root==null)
       return -1;
    allocate node doubleLinkList //initialize,
    printVerticalSumUtil(root, doubleLinkList); 
    //write the function to print double linked list
    System.out.println(doubleLinkList.toString())
}

printVerticalSumUtil(TreeNode root, ListNode listNode) { if(root==NULL) return;

if(root.left!=NULL) if(listNode.prev!=NULL) listNode.prev.data += root.data; else ListNode t = new ListNode(root.data); t.next=listNode; listNode.prev = t; findVerticalSum(root.left, listNode.prev)

if(root.right!=NULL) if(listNode.next!=NULL) listNode.next.data += root.data; else ListNode t = new ListNode(root.data); t.prev=listNode; listNode.next = t; findVerticalSum(root.right, listNode.next) }

更多细节 - http://k2code.blogspot.in/2011/12/vertical-sum-of-binary-tree.html。 感谢。

答案 6 :(得分:0)

以下代码将完成这项工作:

使用的语言:Java

    //  Algorithm for calculating the vertical sum of a binary tree.
static void verticalSum(Node root, int[] sum, int index)
{
    /*
       The sum array contains the sum of each 
       vertical line starting from the leftmost vertical line.
    */
    if(root==null)
    {
        return;
    }
    else
    {
        sum[index]+=(int)root.data;
        verticalSum(root.left, sum, index-1);
        verticalSum(root.right, sum, index+1);
    }
}

您需要使用以下代码调用上述函数:

//Algorithm for calculating the vertical sum of a binary tree.
int level=countLevels(root);
int a=1,d=2,n=level;
int sizeOfArray= a+(n-1)*d;
int index=sizeOfArray/2;
int[] sum=new int[sizeOfArray];
verticalSum(root, sum, index);
System.out.print("Vertical Sum of the binary tree is : ");
for(int i=0;i<sizeOfArray;i++)
{
    System.out.print(", " + sum[i]);
}

countLevels(root)函数在下面提供:

//  Algorithm for calculating the number of levels
static int countLevels(Node root)
{
    int count=0,c=1,i=0,level=0;
    Queue<Node> queue=new LinkedList<Node>();
    Node temp = null;
    queue.add(root);
    while(true)
    {
        if(queue.isEmpty())
        {
            break;
        }
        level++;
        for(i=0;i<c;i++)
        {
            temp=queue.remove();
            if(temp.left!=null)
            {
                queue.add(temp.left);
                count++;
            }
            if(temp.right!=null)
            {
                queue.add(temp.right);
                count++;
            }
        }
        c=count;
        count=0;
    }
    return level;
}

答案 7 :(得分:0)

//经过测试和运作的例子

package tree;

    import java.util.TreeMap;

    public class VerticalSumProblem 
    {

        public static void main(String[] args) 
        {
            VerticalSumProblem verticalSum = new VerticalSumProblem();
            TreeNode treeNode = verticalSum.new TreeNode(1);

            treeNode.left = verticalSum.new TreeNode(2);
            treeNode.right = verticalSum.new TreeNode(3);

            treeNode.left.left = verticalSum.new TreeNode(4);
            treeNode.left.right = verticalSum.new TreeNode(5);

            treeNode.right.left = verticalSum.new TreeNode(6);
            treeNode.right.right = verticalSum.new TreeNode(7);

            //treeNode.right.right.left =verticalSum.new TreeNode(8);

            verticalSum.printTree(treeNode);
            verticalSum.findVerticalSum(treeNode);
        }

        private void findVerticalSum(TreeNode root)
        {
            if(root == null) return;

            TreeMap<Integer,Integer> _mappings = new TreeMap<Integer,Integer>();
            findVerticalSum(root,_mappings,0);

            if (_mappings != null) 
            {
                System.out.println(_mappings.entrySet());
            }
        }

        //if goes left --  and if goes right ++
        private void findVerticalSum(TreeNode treeNode,TreeMap<Integer,Integer> mappings, int level)
        {
            if(treeNode == null) return;

            TreeNode treeNodeLeft,treeNodeRight;

            if(treeNode.left != null)
            {
                treeNodeLeft =  treeNode.left;
                findVerticalSum(treeNodeLeft, mappings,level - 1);
            }

            int sum = mappings.get(level) == null ? 0 : mappings.get(level); 
            mappings.put(level, treeNode.data + sum);

            if( treeNode.right != null)
            {
                treeNodeRight =  treeNode.right;
                findVerticalSum(treeNodeRight,mappings, level + 1);
            }
        }



    /* Create following Binary Tree
         1
       /   \
      2      3
     / \    / \
    4   5, 6    7

    */

        private void printTree(TreeNode treeNode)
        {
            TreeNode treeNodeLeft,treeNodeRight;

            if(treeNode == null) return;

            if(treeNode.left != null || treeNode.right != null)
            {
                treeNodeLeft =  treeNode.left;
                treeNodeRight =  treeNode.right;

                System.out.println("rootValue ="+treeNode.data);

                System.out.println("Left child of ="+treeNode.data +" is : "+ getNodedata(treeNodeLeft));   
                System.out.println("Right child of ="+treeNode.data+" is : "+ getNodedata(treeNodeRight)+"\n");

                printTree(treeNodeLeft);
                printTree(treeNodeRight);
            }
        }

        private int getNodedata(TreeNode treeNode)
        {
            if(treeNode != null)
            {
               return treeNode.data;    
            }
            return -1;
        }

        private class TreeNode
        {
            private int data;
            private TreeNode left,right;

            TreeNode(int data)
            {
                this.data = data;
                left = null;
                right = null;
            }
        }

    }



    //vertical sum
    ///   |   |    |   |    | 
    //    |   |    1   |    | 
    ///   |   2    |   3    | 
    //    4   |   5,6  |    7


    //             0 
    //         1        -1
    //     2      0,0        -2
    //

答案 8 :(得分:0)

这是我在c ++中的简单解决方案: - 在这里,我使用地图来存储基于距离中心的水平距离的总和。

Node *vsumprint(Node *root,int level,map<int,int> &mp){
    if(root==NULL)return NULL;
    Node *temp = vsumprint(root->left,--level,mp);
    if(temp==NULL){
        level++;
    }
    if(mp.find(level)!=mp.end()){
        mp[level] = root->data+mp[level];
    }
    else{
         mp[level] = root->data+mp[level];
    }
    return vsumprint(root->right,++level,mp);
 }
void printVertical(Node *root)
{
    map<int,int> mp;
    vsumprint(root,0,mp);
    for(auto it:mp){
        cout<<it.second<<" ";
    }

}

答案 9 :(得分:0)

这是我在C#中的解决方案:请注意顺序很重要,它如何输出,所以我必须创建一个类并应用自定义排序。

public class Location 
{
    public int x, y, val;

    public Location(int x, int y, int val)
    {
        this.x = x;
        this.y = y;
        this.val = val;
    }
}

private List<Location> locations;
public IList<IList<int>> VerticalTraversal(TreeNode root)
{
    // Each location is a node's x position, y position, and value
    locations = new List<Location>();
    dfs(root, 0, 0);
    locations.Sort(Comparer<Location>.Create((a,b) =>
    {
        if (a.x != b.x)
            return a.x.CompareTo(b.x);
        return a.y != b.y ? a.y.CompareTo(b.y) : a.val.CompareTo(b.val);
    }));

    var result = new List<IList<int>>();
    result.Add(new List<int>());

    int prev = locations[0].x;

    foreach(Location loc in locations)
    {
        // If the x value changed, it's part of a new report.
        if (loc.x != prev)
        {
            prev = loc.x;
            result.Add(new List<int>());
        }

        // We always add the node's value to the latest report.
        result[result.Count - 1].Add(loc.val);
    }
    return result;
}

private void dfs(TreeNode node, int x, int y)
{
    if (node != null)
    {
        locations.Add(new Location(x, y, node.val));
        dfs(node.left, x - 1, y + 1);
        dfs(node.right, x + 1, y + 1);
    }
}