Попытка напечатать верхний вид дерева с использованием двух операторов if

Заявление о проблемах

Вам предоставляется указатель на корень двоичного дерева. Распечатайте вид сверху двоичного дерева. Вам нужно только выполнить функцию.

Мой код:

void top_view(Node root)
 {  
       Node r = root;

       if(r.left!=null){
          top_view(r.left);
          System.out.print(r.data + " ");
        }
       if(r.right!=null){
          System.out.print(r.data + " ");
          top_view(r.right);
        }
}

Два оператора if выполняются каждый раз при вызове функции, но мне нужно выполнить только один из них. Я попробовал переключатель, но он дал постоянную ошибку выражения. Я уже нашел другое решение для этой проблемы.

Итак, я только хочу знать, можем ли мы сделать только одно, если выполняем за один раз, т.е. есть ли способ исправить мой код без изменения подхода?

enter image description hereenter image description here

Ссылка на проблему: https://www.hackerrank.com/challenges/tree-top-view

Ответ 1

Эта проблема может быть легко решена с помощью:

Стек. Чтобы напечатать корневое и левое поддеревы.

Очередь. Чтобы напечатать правое поддерево.

Ваша функция должна быть такой:

 void topview(Node root)
 {
     if(root==null)
      return;
     Stack<Integer> s=new Stack<Integer>();
     s.push(root.data);
     Node root2=root;
     while(root.left!=null)
     {
      s.push(root.left.data);
      root=root.left;
     }
     while(s.size()!=0)
      System.out.print(s.pop()+" ");

     Queue<Integer> q=new LinkedList<Integer>(); 
     q.add(root2.right.data);
     root2=root2.right;     
     while(root2.right!=null)
     {
      q.add(root2.right.data);
      root2=root2.right;
     }
     while(q.size()!=0)
      System.out.print(q.poll()+" ");
 }

Ответ 2

Ваш подход будет работать не потому, что, когда вы вызываете поддерево left или right, вы просто будете придерживаться его. Проблема с этим подходом заключается в том, что вы просто управляетесь, с какой стороны дерева вызывается первым.

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

(СМОТРИТЕ КОД НА КОНЕЦ, ОЧЕНЬ ПРОСТО)

Подход к решению этого вопроса заключается в поддержке horizontal distance от root, и вы печатаете первый node для каждого другого horizontal distance.

Что такое горизонтальное расстояние?

Я просто беру изображение, которое вы добавили.

enter image description here

horizontal distance для конкретного node определяется как число от root по горизонтали. Если вы не увидите края, которые станут вертикальными.

Сделать все проще для всех узлов с левой стороны от начала root с -ve горизонтальным расстоянием и положительным расстоянием справа.

Как вы вычисляете горизонтальное расстояние?

Если вы идете вправо add 1, если вы идете влево, добавьте -1.

так

    horizontal distance of 3 = 0

    horizontal distance of 5 = -1
    horizontal distance of 1 = -2
    horizontal distance of 9 = -1
    horizontal distance of 4 = 0

    horizontal distance of 2 =  1
    horizontal distance of 6 =  0
    horizontal distance of 7 =  2
    horizontal distance of 8 =  0

Узлы 3,4,6,8 имеют одинаковое горизонтальное расстояние 0, что означает среднее?

Это означает, что когда вы видите сверху, все эти узлы находятся в вертикальной вертикали над ним.

Если они находятся в вертикальной линии, которую вы видите?

Тот, который может быть достигнут сначала от root.

Как вы находите, с кем можно связаться первым?

как обычно BFS

Как это печатает решение для вашего примера?

Существует пять различных значений горизонтального расстояния {-1, -2,0,1,2}

hor dist        Nodes

   0      - {3,6,8} // 3 comes first in BFS so print 3
  -1      - {5,9}   // 5 comes first in BFS so print 5
  -2      - {1}     // just print 1
   1      - {2}     // just print 2
   2      - {7}     // just print 7

Таким образом, он напечатает {3,5,1,2,7}

HashSet<Integer> set = new HashSet<>();
Queue<QueueItem> queue = new LinkedList<>();
queue.add(new QueueItem(root, 0)); // Horizontal distance of root is 0

while (!queue.isEmpty())
{
    QueueItem temp = queue.poll();
    int hd = temp.hd;
    TreeNode n = temp.node;

    // If this is the first node at its horizontal distance,
    // then this node is in top view
    if (!set.contains(hd))
    {
        set.add(hd);
        System.out.print(n.key + " ");
    }

    if (n.left != null)
        queue.add(new QueueItem(n.left, hd-1));
    if (n.right != null)
        queue.add(new QueueItem(n.right, hd+1));
}

Ответ 3

Решение довольно просто, если вы печатаете левую сторону рекурсией и правой стороной, используя простой цикл while.

 void for_left(node *root)
{
    if(!root->left)
        {
        cout<<root->data<<" ";
        return;
    }
    for_left(root->left);
    cout<<root->data<<" ";
    return;

}

void top_view(node * root)
{
    for_left(root->left);
    cout<<root->data<<" ";
    while(root->right)
        {
        cout<<(root->right)->data<<" ";
        root=root->right;
    }


}

Ответ 4

Это действительно работает. Не нужна очередь, но использует стек для того, чтобы отступить с левой стороны, поскольку мы не имеем ссылки на родителя.

void top_view(Node root)
{
    Stack<Node> p = new Stack<Node>();
    Node current = root;
    while (current != null) 
    {
        p.push(current);
        current = current.left;
    }

    while (p.peek() != root) 
    {
        System.out.print(p.pop().data + " ");
    }

    current = root;
    while (current != null) 
    {
        System.out.print(current.data + " ");
        current = current.right;
    }
}

Ответ 5

Моя реализация Java прилагается. Левая часть дерева более интересна, если рекурсивно решается, но изменение строки (мой путь ниже) было проще и требовало только одного метода.

public void top_view(Node root){

    String output = "";

    Node left = root.left;
    Node right = root.right;

    String leftOutput = "";
    while(left != null){
        leftOutput += left.data + " ";
        left = left.left;
    }

    String left = "";
    for(int i = leftOutput.length - 1; i >= 0; i--){
        left += leftOutput.substring(i, i+1);
    }

    output += left;

    output += " " + root.data + " ";

    while(right != null){
        output += right.data + " ";
        right = right.right;
    }

    output = output.substring(1, output.length());
    System.out.println(output);
}

Ответ 6

void top_view(Node root)    
{    
    if(root.left!=null) top_view(root.left);   

    if(root.left!=null || root.right!=null)
         System.out.print(root.data + " ");

    if(root.right!=null) top_view(root.right);        
}

Ответ 7

Более простой подход в С++

`// printing top view of the tree
void left_array(node *p)
{
    if(p==NULL)
    return;
    else
    {
        left_array(p->left);
        cout<<p->data<<" ";
    }
}
void right_array(node *p)
{
    if(p==NULL)
    return;
    else
    {
        cout<<p->data<<" ";
        right_array(p->right);
    }

}
void top_view(node * root)
{   int i=0;
node *t1=root;
node *t2=root;
    left_array(t2);
    right_array(t1->right);

}`

Ответ 8

Очень простое рекурсивное решение, которое заботится о длинных ветвях ребенка node. Это решается с использованием концепции горизонтального расстояния.

public void printTopView(BNode root) {
        Map<Integer, Integer> data = new TreeMap<Integer, Integer>();
        printTopViewRecursive(data, root, 0);
        for(int key : data.keySet()) {
            System.out.print(data.get(key) +" ");
        }
    }


    private void printTopViewRecursive(Map<Integer, Integer> hDMap, BNode root, int hD) {
        if(root == null)
            return;
        if(!hDMap.containsKey(hD)) {
            hDMap.put(hD, root.data);
        }
        printTopViewRecursive(hDMap, root.left,hD - 1);
        printTopViewRecursive(hDMap, root.right, hD + 1);
    }

Ответ 9

в рекурсивном решении Java. преобразован из кода С++

void top_view(Node root)
{
    left_array(root);
    right_array(root.right);
}

void left_array(Node p)
{
    if(p==null)
        return;
    else
    {
        left_array(p.left);
        System.out.printf("%d ",p.data);
    }
}
void right_array(Node p)
{
    if(p==null)
        return;
    else
    {
        System.out.printf("%d ",p.data);
        right_array(p.right);
    }
}

Ответ 10

void top_view(Node root)
 {
    Node left = root;
    Node right = root;
    print_left(root.left);
    System.out.print(root.data + " ");
    print_right(root.right) ;
 }

void print_left(Node start)
 {
    if(start != null)
     {
       print_left(start.left);
       System.out.print(start.data + " "); 
     } 
 }

void print_right(Node start)
 {
    if(start != null)
    {
       System.out.print(start.data + " ");    
       print_right(start.right);
    }     
  } 

Ответ 11

Один простой рекурсивный способ сделать это:

void top_view(Node root)
{
    print_top_view(root.left, "left");
    System.out.print(root.data  + " ");
    print_top_view(root.right, "right");
}

void print_top_view(Node root, String side) {
    if(side.equals("left")) {
        if(root.left != null) {
            print_top_view(root.left, "left"); 
        }
       System.out.print(root.data + " ");
    } else if(side.equals("right")) {
        System.out.print(root.data + " ");
        if(root.right != null) {
          print_top_view(root.right, "right");  
        } 
    }
}

Ответ 12

if(root){
if(root->left !=NULL || root->right !=NULL){
    if(root->left)
        top_view(root->left);

     cout<<root->data<<" ";

     if(root->right)
        top_view(root->right);

}}

Ответ 13

Это код для верхнего представления двоичного дерева в С++..

void topview (node * root, queue & Q)

{

if(!root)
    return;
map<int,int> TV;
Q.push(root);
TV[root->data]=0;
map<int,int>:: iterator it;
int min=INT_MAX,max=INT_MIN;
while(!Q.empty())
{
    node* temp =Q.front();
    Q.pop();
    int l=0;

    for(it=TV.begin();it!=TV.end();it++)
    {
        if(it->first==temp->data)
        {
            l=it->second;
           break;
        }

    }
    if(l<min) 
        {min=l;}
    if(l>max) 
        max=l;
    if(temp->left)
    {
        Q.push(temp->left);
        TV[temp->left->data] = l-1;
    }
    if(temp->right)
    {
        Q.push(temp->right);
        TV[temp->right->data] = l+1;
    }
}
cout<<max<<min<<endl;
for(int  i =min;i<=max;i++)
{
    for(it=TV.begin();it!=TV.end();it++)
    {
        if(it->second==i)
        {
            cout<<it->first;
            break;
        }
    }
}

}

void topview_aux (node * root)

{

queue<node*> Q;

topview(root,Q);

}

Ответ 14

Совсем аналогичный подход к @Karthik, но с сохранением порядка, заключается в том, чтобы отложить печать до конца и сохранить вид сверху узлы, упорядоченные в очереди с двойным завершением.

  • Мы гарантируем заказ с помощью BFS
  • В каждом раунде мы проверяем, превышает ли текущее горизонтальное расстояние node максимальное расстояние, достигнутое в предыдущих раундах (отрицательное расстояние для левых узлов).
  • Новые верхние узлы верхнего уровня с -ve расстоянием (левая позиция) добавлены в левый конец дека, а правые узлы с + ve расстоянием добавлены в правый конец.

Пример решения в Java

import java.util.*;

class Node {
  int data;
  Node left;
  Node right;

  public Node(int data) {
    this.data = data;
  }
}

enum Position {
  ROOT,
  RIGHT,
  LEFT
}

class NodePositionDetails {
  Node node;
  // Node position in the tree
  Position pos;
  // horizontal distance from the root (-ve for left nodes)
  int hd;

  public NodePositionDetails(Node node, Position pos, int hd) {
    this.node = node;
    this.pos = pos;
    this.hd = hd;
  }
}

public class TreeTopView {
  public void topView(Node root) {
    // max horizontal distance reached in the right direction uptill the current round
    int reachedRightHD = 0;
    // max horizontal distance reached in the left direction uptill the current round
    int reachedLeftHD = 0;

    if (root == null)
      return;

    // queue for saving nodes for BFS
    Queue < NodePositionDetails > nodes = new LinkedList < > ();

    // Double ended queue to save the top view nodes in order
    Deque < Integer > topViewElements = new ArrayDeque < Integer > ();

    // adding root node to BFS queue 
    NodePositionDetails rootNode = new NodePositionDetails(root, Position.ROOT, 0);
    nodes.add(rootNode);

    while (!nodes.isEmpty()) {
      NodePositionDetails node = nodes.remove();

      // in the first round, Root node is added, later rounds left and right nodes handled in order depending on BFS. if the current horizontal distance is larger than the last largest horizontal distance (saved in reachedLeftHD and reachedRightHD)
      if (node.pos.equals(Position.LEFT) && node.hd == reachedLeftHD - 1) {
        topViewElements.addFirst(node.node.data);
        reachedLeftHD -= 1;
      } else if (node.pos.equals(Position.RIGHT) && node.hd == reachedRightHD + 1) {
        topViewElements.addLast(node.node.data);
        reachedRightHD += 1;
      } else if (node.pos.equals(Position.ROOT)) { // reachedLeftHD == 0 && reachedRightHD ==0
        topViewElements.addFirst(node.node.data);
      }

      // Normal BFS, adding left and right nodes to the queue
      if (node.node.left != null) {
        nodes.add(new NodePositionDetails(node.node.left, Position.LEFT, node.hd - 1));
      }
      if (node.node.right != null) {
        nodes.add(new NodePositionDetails(node.node.right, Position.RIGHT, node.hd + 1));
      }
    }

    // print top elements view
    for (Integer x: topViewElements) {
      System.out.print(x + " ");
    }
  }
}

И для тестирования:

  public static void main(String[] args) throws java.lang.Exception {
    /**
       Test Case 1 & 2
        1
       /  \
      2    3
     / \   
    7    4  
   /      \ 
  8        5
            \
             6

       Test Case 3: add long left branch under 3  (branch : left to the 3   3-> 8 -> 9 -> 10 -> 11

       **/

    Node root = new Node(1); //hd = 0
    // test Case 1 -- output: 2 1 3 6
    root.left = new Node(2); // hd = -1
    root.right = new Node(3); // hd = +1
    root.left.right = new Node(4); // hd = 0
    root.left.right.right = new Node(5); // hd = +1
    root.left.right.right.right = new Node(6); // hd = +2

    // test case 2 -- output: 8 7 2 1 3 6 
    root.left.left = new Node(7); // hd = -2
    root.left.left.left = new Node(8); // hd = -3

    // test case 3 -- output: 11 7 2 1 3 6 
    root.left.left.left = null;
    root.right.left = new Node(8); //hd = 0
    root.right.left.left = new Node(9); // hd = -1
    root.right.left.left.left = new Node(10); // hd = -2
    root.right.left.left.left.left = new Node(11); //hd = -3

    new TreeTopView().topView(root);
  }

Ответ 15

Простейшее рекурсивное решение

void top_view(Node root)
{
 // For left side of the tree
    top_view_left(root);
 // For Right side of the tree
    top_view_right(root.right);
}

void top_view_left(Node root){
     if(root != null)
  {     
     // Postorder
     top_view_left(root.left);
     System.out.print(root.data + " ");
  }  
}

void top_view_right(Node root){
    if(root != null)
  {
        //  Preorder
      System.out.print(root.data + " ");
      top_view_right(root.right);
  }  
}

Ответ 16

Решение можно найти здесь - Git URL-адрес концентратора

Обратите внимание, что независимо от вопроса хакерранка относительно сбалансированного дерева, если дерево находится в несбалансированном состоянии, как показано ниже

    1
  /   \
2       3
  \   
    4  
      \
        5
         \
           6

Для таких деревьев требуется сложная логика, которая определена здесь в geeksforgeeks - GeeksforGeeks

Ответ 17

Это:

import queue

class NodeWrap:
    def __init__(self, node, hd):
        self.node = node
        #horizontal distance
        self.hd = hd

def topView(root):
    d = {}
    q = queue.Queue()
    q.put(NodeWrap(root, 0))
    while not q.empty():
        node_wrap = q.get()
        node = node_wrap.node
        current_hd = node_wrap.hd
        if d.get(current_hd) is None:
            d[current_hd] = node
            print(node.info, end=" ")
        if node.left is not None:
            q.put(NodeWrap(node.left, current_hd - 1))
        if node.right is not None:
            q.put(NodeWrap(node.right, current_hd + 1))

должен быть рабочим решением на Python, но по некоторым причинам он проваливается в 6 тестовых случаях из 7 на hackerrank.com. Может кто-нибудь объяснить мне, почему это происходит?

Те люди, которые просто запускают "левую" и "правую" функции, не понимают задачу.