C++ 打印二叉树的底部视图

C++ 打印二叉树的底部视图,c++,algorithm,tree,binary-tree,C++,Algorithm,Tree,Binary Tree,对于二叉树,我们定义水平距离如下: Horizontal distance(hd) of root = 0 If you go left then hd = hd(of its parent)-1, and if you go right then hd = hd(of its parent)+1. 然后,树的底部视图由树的所有节点组成,其中没有具有相同hd和更高级别的节点。(对于给定的hd,可能有多个这样的节点。在这种情况下,所有节点都属于底部视图。)我正在寻找一种

对于二叉树,我们定义水平距离如下:

    Horizontal distance(hd) of root = 0
    If you go left then hd = hd(of its parent)-1, and 
    if you go right then hd = hd(of its parent)+1.
然后,树的底部视图由树的所有节点组成,其中没有具有相同
hd
和更高级别的节点。(对于给定的
hd
,可能有多个这样的节点。在这种情况下,所有节点都属于底部视图。)我正在寻找一种算法,该算法输出树的底部视图


示例:

假设二叉树是:

         1
        /  \
       2    3
      / \  / \
     4   5 6  7
            \
             8
树的底视图是:425687

    Ok so for the first example,
    Horizontal distance of node with value 1: 0, level = 1
    Horizontal distance of node with value 2: 0 - 1 = -1, level = 2
    Horizontal distance of node with value 3: 0 + 1 = 1, level = 2
    Horizontal distance of node with value 4: -1 - 1 = -2, level = 3
    Horizontal distance of node with value 5: -1 + 1 = 0, level = 3
    Horizontal distance of node with value 6: 1 - 1 = 0, level = 3
    Horizontal distance of node with value 7: 1 + 1 = 2, level = 3
    Horizontal distance of node with value 8: 0 + 1 = 1, level = 4

    So for each vertical line that is for hd=0, print those nodes which appear in the last level of that line.
    So for hd = -2, print 4
    for hd = -1, print 2
    for hd = 0, print 5 and 6 because they both appear in the last level of that vertical line
    for hd = 1, print 8
    for hd = 2, print 7
再举一个例子供参考:

         1
      /     \
    2         3
   / \       / \
  4   5     6     7 
 / \ / \   / \    / \
8  9 10 11 12 13 14 15     
因此,这方面的输出将是: 8 4 9 10 12 5 6 11 14 7 15

Similarly for this example
hd of node with value 1: 0, , level = 1
hd of node with value 2: -1, level = 2
hd of node with value 3: 1, level = 2
hd of node with value 4: -2, level = 3
hd of node with value 5: 0, , level = 3
hd of node with value 6: 0, level = 3
hd of node with value 7: 2, level = 3
hd of node with value 8: -3, level = 4
hd of node with value 9: -1, level = 4
hd of node with value 10: -1, level = 4
hd of node with value 11: 1, level = 4
hd of node with value 12: -1, level = 4
hd of node with value 13: 1, level = 4
hd of node with value 14: 1, level = 4
hd of node with value 15: 3, level = 4

So, the output will be:
hd = -3, print 8
hd = -2, print 4
hd = -1, print 9 10 12
hd = 0, print 5 6
hd = 1, print 11 13 14
hd = 2, print 7
hd = 3, print 15 

So the ouput will be:
8 4 9 10 12 5 6 11 13 14 7 15

我已经知道一种方法,在这种方法中,我可以使用大量额外的空间(一个映射和一个用于存储垂直线中最后一个元素的级别的一维数组),时间复杂度为$O(N\log N)$。 这就是这个方法的实现:

#include <iostream>
#include <cstdio>
#include <map>
#include <vector>

using namespace std;

struct Node{
       int data;
       struct Node *left, *right;
};

Node* newNode(int data)
{
    Node *temp = new Node;
    temp->data = data;
    temp->left = temp->right = NULL;
    return temp;
}

int height(Node *node)
{
    if(node == NULL)
            return 0;
    else{
         int lh = height(node->left);
         int rh = height(node->right);

         if(lh > rh)
               return (lh+1);
         else
               return (rh+1);
    }
}

void printBottom(Node *node, int level, int hd, int min, map< int, vector<int> >& visited, int lev[], int l)
{
     if(node == NULL)
             return;
     if(level == 1){
              if(lev[hd-min] == 0 || lev[hd-min] == l){
                      lev[hd-min] = l;
                      visited[hd-min].push_back(node->data);
              }
     }
     else if(level > 1)
     {
          printBottom(node->left, level-1, hd-1, min, visited, lev, l);
          printBottom(node->right, level-1, hd+1, min, visited, lev, l);
     }
}

void findMinMax(Node *node, int *min, int *max, int hd)
{
     if(node == NULL)
             return;

     if(hd < *min)
          *min = hd;
     else if(hd > *max)
          *max = hd;

     findMinMax(node->left, min, max, hd-1);
     findMinMax(node->right, min, max, hd+1);
}

int main()
{
    Node *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);
    root->left->left->left = newNode(8);
    root->left->left->right = newNode(9);
    root->left->right->left = newNode(10);
    root->left->right->right = newNode(11);
    root->right->left->left = newNode(12);
    root->right->left->right = newNode(13);
    root->right->right->left = newNode(14);
    root->right->right->right = newNode(15);

    int min = 0, max = 0;

    findMinMax(root, &min, &max, 0);

    int lev[max-min+1];
    map < int, vector<int> > visited;
    map< int,vector<int> > :: iterator it;

    for(int i = 0; i < max-min+1; i++)
            lev[i] = 0;

    int h = height(root);

    for (int i=h; i>0; i--){
        printBottom(root, i, 0, min, visited, lev, i);
    }

    for(it = visited.begin() ; it != visited.end() ; it++) {
        for(int i=0 ; i < it->second.size() ; i++) {
            cout << it->second[i] << " ";
        }
    }

    return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
结构节点{
int数据;
结构节点*左、*右;
};
Node*newNode(int数据)
{
Node*temp=新节点;
温度->数据=数据;
临时->左=临时->右=空;
返回温度;
}
整数高度(节点*节点)
{
if(node==NULL)
返回0;
否则{
int lh=高度(节点->左侧);
int rh=高度(节点->右侧);
如果(左侧>右侧)
返回(左侧+1);
其他的
返回(rh+1);
}
}
void printbooth(节点*Node,int-level,int-hd,int-min,map&已访问,int-lev[],int-l)
{
if(node==NULL)
返回;
如果(级别==1){
如果(lev[hd min]==0 | | lev[hd min]==l){
lev[hd min]=l;
已访问[hd min]。推回(节点->数据);
}
}
否则,如果(级别>1)
{
打印底部(节点->左、一级、hd-1、最小、已访问、lev、l);
打印底部(节点->右侧,一级,hd+1,最小,已访问,级别,l);
}
}
void findMinMax(节点*Node,int*min,int*max,int-hd)
{
if(node==NULL)
返回;
如果(hd<*分钟)
*最小值=hd;
否则如果(hd>*最大值)
*max=hd;
findMinMax(节点->左、最小、最大、hd-1);
findMinMax(节点->右侧、最小值、最大值、hd+1);
}
int main()
{
Node*root=newNode(1);
根->左=新节点(2);
根->右=新节点(3);
根->左->左=新节点(4);
根->左->右=新节点(5);
根->右->左=新节点(6);
根->右->右=新节点(7);
根->左->左->左=新节点(8);
根->左->左->右=新节点(9);
根->左->右->左=新节点(10);
根->左->右->右=新节点(11);
根->右->左->左=新节点(12);
根->右->左->右=新节点(13);
根->右->右->左=新节点(14);
根->右->右->右=新节点(15);
int min=0,max=0;
findMinMax(根、最小值和最大值,0);
整数级[最大最小值+1];
地图访问;
map::对其进行迭代器;
对于(int i=0;i0;i--){
printBottom(根,i,0,min,已访问,lev,i);
}
for(it=visted.begin();it!=visted.end();it++){
对于(inti=0;isecond.size();i++){

cout second[i]首先,您可以将时间复杂度降低到O(n),同时保持相同的空间复杂度。您可以通过在一次运行
printbooth
中填充
visted
来实现这一点:

void printBottom(Node *node, int level, int hd, int min, map< int, vector<int> >& visited, int lev[])
{
     if(node == NULL)
             return;
     if(lev[hd-min] < level){
         lev[hd-min] = level;
         visited[hd-min] = new vector<int>; //erase old values, they are hidden by the current node
     }
     if(lev[hd-min] <= level){
         visited[hd-min].push_back(node->data);
     }
     printBottom(node->left, level+1, hd-1, min, visited, lev);
     printBottom(node->right, level+1, hd+1, min, visited, lev);
}
使用调用
fillLev(root,1,0,min,lev);
printBottom(root,1,0,min,lev);
无效底部视图(节点*根)
{
如果(!root)
返回;
底部视图(根->左);
如果(!root->left | |!root->right)
coutleft)&&(根->左&&!根->左->右)

cout下面给出了java中的解决方案

所有的电话都是

boolean obstructionFromLeftSide = printBottomViewOrderOfTree(root.left, true);
boolean obstructionFromRightSide = printBottomViewOrderOfTree(root.right, false);
if (!(obstructionFromLeftSide || obstructionFromRightSide))
    out.println(root.data + " ");
这里给出了函数

    boolean printBottomViewOrderOfTree(Node root, boolean fromLeftSide)
   {
    if (root == null)
        return false;
    boolean obstructionFromLeftSide = printBottomViewOrderOfTree(root.left, true);
    boolean obstructionFromRightSide = printBottomViewOrderOfTree(root.right, false);
    if (!(obstructionFromLeftSide || obstructionFromRightSide))
        out.println(root.data + " ");
    if (fromLeftSide)
    {
        return root.right != null;
    }
    else
    {
        return root.left != null;
    }
}

你是否考虑使用基于水平距离和水平的HASMAP? 在C++中,我们可以有这样的哈希图:

map<int,map<int,vector<int>>> HM;    
// Let Horizontal Distance = HD,Level = L  
// HM[HD][L] -> Vector tracking every node for a given HD,L
map-HM;
//让水平距离=HD,标高=L
//HM[HD][L]->给定HD,L的每个节点的向量跟踪
此方法的时间=O(n),并且在删除笨拙的fillLev()函数方面比您的代码有所改进。我们在这里所做的只是单树遍历和单hashmap遍历。代码如下:

void getBottomView(struct node *tree,int HD,int L,map<int,map<int,vector<int>>> &HM)
{
    if(tree==NULL)
        return;

    HM[HD][L].push_back(tree->data);
    getBottomView(tree->left,HD-1,L+1,HM);
    getBottomView(tree->right,HD+1,L+1,HM);
}

void printBottomViewbyMap(map<int,map<int,vector<int>>> &HM)
{
    map<int,map<int,vector<int>>>::iterator i;

    for(i=HM.begin() ; i!=HM.end() ; i++)
    {
        if(i->second.size()==1)
        {
            map<int,vector<int>>::iterator mapi;
            mapi = i->second.begin();
            for(int j=0 ; j<= mapi->second.size()-1 ; j++)
                cout<<mapi->second[j]<<" ";
        }
        else
        {
            map<int,vector<int>>::reverse_iterator mapi;
            mapi = i->second.rbegin();
            for(int j=0 ; j<= mapi->second.size()-1 ; j++)
                cout<<mapi->second[j]<<" ";
        }
    }
} 

void printBottomView(struct node *tree)
{
    map<int,map<int,vector<int>>> HM;
    getBottomView(tree,0,0,HM);
    printBottomViewbyMap(HM);
}
void getBottomView(结构节点*tree,int-HD,int-L,map&HM)
{
if(tree==NULL)
返回;
HM[HD][L]。向后推(树->数据);
getBottomView(树->左,HD-1,L+1,HM);
getBottomView(树->右,HD+1,L+1,HM);
}
无效printBottomViewbyMap(地图和HM)
{
迭代器i;
for(i=HM.begin();i!=HM.end();i++)
{
如果(i->second.size()==1)
{
迭代器mapi;
mapi=i->second.begin();
对于(int j=0;jssecond.size()-1;j++)

cout如果你仔细观察算法,你只能以增量的方式到达更高水平的节点。如果我们有一个数组(因为负水平距离,我们不能),我们只需要做一个[horizontalDistance]=节点

然后遍历此数组以打印底部视图

这将起作用,因为数组将存储特定水平距离的最底部元素,因为我们正在执行级别顺序遍历

现在,为了解决负索引问题,创建一个名为双向AcListar的类。在爪哇中,可以使用两个数组或C++中的两个STD::向量:

我已经在这里发布了代码:

但以下是您需要编写的双向列表:

public class BiDirectionalList<T> {
List<T> forward;
List<T> reverse;

public BiDirectionalList() {
    forward = new ArrayList<>();
    reverse = new ArrayList<>();
    reverse.add(null); //0 index of reverse list will never be used
}

public int size() {
    return forward.size() + reverse.size()-1;
}

public boolean isEmpty() {
    if (forward.isEmpty() && reverse.size() == 1) return true;
    return false;
}

public T get(int index) {
    if (index < 0) {
        reverse.get(-index);
    } 
    return forward.get(index);
}

/**
 * Sets an element at given index only if the index <= size.
 * i.e. either overwrites an existing element or increases the size by 1
 * @param index 
 * @param element
 */
public void set(int index, T element) {
    if (index < 0) {
        index = -index;
        if (index  > reverse.size()) throw new IllegalArgumentException("Index can at max be equal to size");
        else if (reverse.size() == index ) reverse.add(index, element);
        else reverse.set(index, element);

    } else {
        if (index > forward.size()) throw new IllegalArgumentException("Index can at max be equal to size");
        else if (forward.size() == index ) forward.add(index, element);
        else forward.set(index, element);
    }
}
}
公共类双向列表{
向前列出;
反向列表;
公共双向专家(){
forward=新的ArrayList();
反向=新的ArrayList();
reverse.add(null);//将永远不会使用反向列表的0索引
}
公共整数大小(){
返回forward.size()+reverse.size()-1;
}
公共布尔值为空(){
if(forward.isEmpty()&&reverse
void getBottomView(struct node *tree,int HD,int L,map<int,map<int,vector<int>>> &HM)
{
    if(tree==NULL)
        return;

    HM[HD][L].push_back(tree->data);
    getBottomView(tree->left,HD-1,L+1,HM);
    getBottomView(tree->right,HD+1,L+1,HM);
}

void printBottomViewbyMap(map<int,map<int,vector<int>>> &HM)
{
    map<int,map<int,vector<int>>>::iterator i;

    for(i=HM.begin() ; i!=HM.end() ; i++)
    {
        if(i->second.size()==1)
        {
            map<int,vector<int>>::iterator mapi;
            mapi = i->second.begin();
            for(int j=0 ; j<= mapi->second.size()-1 ; j++)
                cout<<mapi->second[j]<<" ";
        }
        else
        {
            map<int,vector<int>>::reverse_iterator mapi;
            mapi = i->second.rbegin();
            for(int j=0 ; j<= mapi->second.size()-1 ; j++)
                cout<<mapi->second[j]<<" ";
        }
    }
} 

void printBottomView(struct node *tree)
{
    map<int,map<int,vector<int>>> HM;
    getBottomView(tree,0,0,HM);
    printBottomViewbyMap(HM);
}
public class BiDirectionalList<T> {
List<T> forward;
List<T> reverse;

public BiDirectionalList() {
    forward = new ArrayList<>();
    reverse = new ArrayList<>();
    reverse.add(null); //0 index of reverse list will never be used
}

public int size() {
    return forward.size() + reverse.size()-1;
}

public boolean isEmpty() {
    if (forward.isEmpty() && reverse.size() == 1) return true;
    return false;
}

public T get(int index) {
    if (index < 0) {
        reverse.get(-index);
    } 
    return forward.get(index);
}

/**
 * Sets an element at given index only if the index <= size.
 * i.e. either overwrites an existing element or increases the size by 1
 * @param index 
 * @param element
 */
public void set(int index, T element) {
    if (index < 0) {
        index = -index;
        if (index  > reverse.size()) throw new IllegalArgumentException("Index can at max be equal to size");
        else if (reverse.size() == index ) reverse.add(index, element);
        else reverse.set(index, element);

    } else {
        if (index > forward.size()) throw new IllegalArgumentException("Index can at max be equal to size");
        else if (forward.size() == index ) forward.add(index, element);
        else forward.set(index, element);
    }
}
}
 void printBottom(Node *root,int dif,int level,map<int, pair<int,int> > &map){
    if(root==NULL)return;
    if(map.find(dif)==map.end() || level>= map[dif].second){
        map[dif] = {root->data,level};
    }
    printBottom(root->left,dif-1,level+1,map);
    printBottom(root->right,dif+1,level+1,map);
}

void bottomView(Node *root){
       map<int ,pair<int,int> > map;
       printBottom(root,0,0,map);
       for(auto it : map){
           printf("%d ",it.second.first);
       }
    }
        public class node
        {
            public int data;
            public node left, right;
            public int hd;
        }

        static node newNode(int item)
        {
            node temp = new node();
            temp.data = item;
            temp.left = null;
            temp.right = null;
            return temp;
        }

        static void rightViewOfBT(node root)
        {
            Queue<node> queue = new Queue<node>();
            SortedDictionary<int, int> treeMap = new SortedDictionary<int, int>();
            int hd = 0;
            root.hd = hd;
            queue.Enqueue(root);
            while(queue.Count > 0)
            {
                node temp = queue.Peek();
                queue.Dequeue();

                if (treeMap.ContainsKey(temp.hd))
                {
                    treeMap[temp.hd] = temp.data;
                }
                else
                {
                    treeMap.Add(temp.hd, temp.data);
                }

                if (temp.left != null)
                {
                    temp.left.hd = temp.hd - 1;
                    queue.Enqueue(temp.left);
                }

                if (temp.right != null)
                {
                    temp.right.hd = temp.hd + 1;
                    queue.Enqueue(temp.right);
                }
            }
            foreach (var tree in treeMap)
                Console.Write(tree.Value);
        }
        static void Main(string[] args)
        {
            node root = newNode(1);
            root.left = newNode(2);
            root.right = newNode(3);
            root.left.left = newNode(4);
            root.left.right = newNode(5);
            root.left.left.right = newNode(8);
            root.left.right.left = newNode(9);
            root.right.left = newNode(6);
            root.right.right = newNode(7);
            root.right.right.right = newNode(11);
            root.right.left.right = newNode(10);
            rightViewOfBT(root);
        }