给定一个二叉树,垂直打印它。下面的例子说明了垂直顺序遍历。
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
The output of print this tree vertically will be:
4
2
1 5 6
3 8
7
9
我们在上一篇文章中讨论了 O(n 2 ) 解决方案。在这篇文章中,讨论了一种基于哈希映射的有效解决方案。我们需要检查所有节点与根的水平距离。如果两个节点具有相同的水平距离 (HD),则它们在同一条垂直线上。高清的想法很简单。根的HD为0,右边缘(连接到右子树的边缘)被认为是+1水平距离,左边缘被认为是-1水平距离。例如,在上面的树中,节点 4 的 HD 为 -2,节点 2 的 HD 为 -1,5 和 6 的 HD 为 0,节点 7 的 HD 为 +2。
我们可以对给定的二叉树进行先序遍历。在遍历树时,我们可以递归计算 HD。我们最初将根的水平距离设为 0。对于左子树,我们将水平距离作为根的水平距离减 1 传递。对于右子树,我们将水平距离作为根的水平距离加 1 传递。对于每个 HD 值,我们在哈希图中维护一个节点列表。每当我们在遍历中看到一个节点时,我们就会转到哈希映射条目并使用 HD 作为映射中的键将该节点添加到哈希映射中。
以下是上述方法的C++实现。感谢 Chirag 提供以下 C++ 实现。
C++
// C++ program for printing vertical order of a given binary tree
#include
#include
#include
Java
// Java program for printing vertical order of a given binary tree
import java.util.TreeMap;
import java.util.Vector;
import java.util.Map.Entry;
public class VerticalOrderBtree
{
// Tree node
static class Node
{
int key;
Node left;
Node right;
// Constructor
Node(int data)
{
key = data;
left = null;
right = null;
}
}
// Utility function to store vertical order in map 'm'
// 'hd' is horizontal distance of current node from root.
// 'hd' is initially passed as 0
static void getVerticalOrder(Node root, int hd,
TreeMap> m)
{
// Base case
if(root == null)
return;
//get the vector list at 'hd'
Vector get = m.get(hd);
// Store current node in map 'm'
if(get == null)
{
get = new Vector<>();
get.add(root.key);
}
else
get.add(root.key);
m.put(hd, get);
// Store nodes in left subtree
getVerticalOrder(root.left, hd-1, m);
// Store nodes in right subtree
getVerticalOrder(root.right, hd+1, m);
}
// The main function to print vertical order of a binary tree
// with the given root
static void printVerticalOrder(Node root)
{
// Create a map and store vertical order in map using
// function getVerticalOrder()
TreeMap> m = new TreeMap<>();
int hd =0;
getVerticalOrder(root,hd,m);
// Traverse the map and print nodes at every horigontal
// distance (hd)
for (Entry> entry : m.entrySet())
{
System.out.println(entry.getValue());
}
}
// Driver program to test above functions
public static void main(String[] args) {
// TO DO Auto-generated method stub
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
root.right.left.right = new Node(8);
root.right.right.right = new Node(9);
System.out.println("Vertical Order traversal is");
printVerticalOrder(root);
}
}
// This code is contributed by Sumit Ghosh
Python
# Python program for printing vertical order of a given
# binary tree
# A binary tree node
class Node:
# Constructor to create a new node
def __init__(self, key):
self.key = key
self.left = None
self.right = None
# Utility function to store vertical order in map 'm'
# 'hd' is horizontal distance of current node from root
# 'hd' is initially passed as 0
def getVerticalOrder(root, hd, m):
# Base Case
if root is None:
return
# Store current node in map 'm'
try:
m[hd].append(root.key)
except:
m[hd] = [root.key]
# Store nodes in left subtree
getVerticalOrder(root.left, hd-1, m)
# Store nodes in right subtree
getVerticalOrder(root.right, hd+1, m)
# The main function to print vertical order of a binary
#tree ith given root
def printVerticalOrder(root):
# Create a map and store vertical order in map using
# function getVerticalORder()
m = dict()
hd = 0
getVerticalOrder(root, hd, m)
# Traverse the map and print nodes at every horizontal
# distance (hd)
for index, value in enumerate(sorted(m)):
for i in m[value]:
print i,
print
# Driver program to test above function
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
root.right.left.right = Node(8)
root.right.right.right = Node(9)
print "Vertical order traversal is"
printVerticalOrder(root)
# This code is contributed by Nikhil Kumar Singh(nickzuck_007)
C++14
// C++ program for printing
// vertical order of a given binary
// tree
#include
using namespace std;
struct Node {
int data;
Node *left, *right;
};
struct Node* newNode(int data)
{
struct Node* node = new Node;
node->data = data;
node->left = node->right = NULL;
return node;
}
// Store vertical order
// in map "m", hd = horizontal
// distance, vd = vertical distance
void preOrderTraversal(Node* root,
long long int hd,
long long int vd,
map >& m)
{
if (!root)
return;
// key = horizontal
// distance (30 bits) + vertical
// distance (30 bits) map
// will store key in sorted
// order. Thus nodes having same
// horizontal distance
// will sort according to
// vertical distance.
long long val = hd << 30 | vd;
// insert in map
m[val].push_back(root->data);
preOrderTraversal(root->left, hd - 1, vd + 1, m);
preOrderTraversal(root->right, hd + 1, vd + 1, m);
}
void verticalOrder(Node* root)
{
// map to store all nodes in vertical order.
// keys will be horizontal + vertical distance.
map > mp;
preOrderTraversal(root, 0, 1, mp);
// print map
int prekey = INT_MAX;
map >::iterator it;
for (it = mp.begin(); it != mp.end(); it++) {
if (prekey != INT_MAX
&& (it->first >> 30) != prekey) {
cout << endl;
}
prekey = it->first >> 30;
for (int j = 0; j < it->second.size(); j++)
cout << it->second[j] << " ";
}
}
// Driver code
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->right->left->right = newNode(8);
root->right->right->right = newNode(9);
cout << "Vertical order traversal :- " << endl;
verticalOrder(root);
return 0;
}
Java
// Java Program for above approach
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
class Node {
int data;
Node left, right;
Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree {
Node root;
// Values class
class Values {
int max, min;
}
// Program to find vertical Order
public void verticalOrder(Node node)
{
Values val = new Values();
// Create TreeMap
Map > map
= new TreeMap >();
// Function Call to findHorizonatalDistance
findHorizonatalDistance(node, val, val, 0, map);
// Iterate over map.values()
for (List list : map.values()) {
System.out.println(list);
}
// Print "done"
System.out.println("done");
}
// Program to find Horizonatal Distance
public void findHorizonatalDistance(
Node node, Values min, Values max, int hd,
Map > map)
{
// If node is null
if (node == null)
return;
// if hd is less than min.min
if (hd < min.min)
min.min = hd;
// if hd is greater than min.min
if (hd > max.max)
max.max = hd;
// Using computeIfAbsent
map.computeIfAbsent(hd,
k -> new ArrayList())
.add(node.data);
// Function Call with hd equal to hd - 1
findHorizonatalDistance(node.left, min, max, hd - 1,
map);
// Function Call with hd equal to hd + 1
findHorizonatalDistance(node.right, min, max,
hd + 1, map);
}
// Driver Code
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
/* Let us construct the tree shown
in above diagram */
tree.root = new Node(1);
tree.root.left = new Node(2);
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
tree.root.right.left = new Node(6);
tree.root.right.right = new Node(7);
tree.root.right.left.right = new Node(8);
tree.root.right.right.right = new Node(9);
System.out.println("vertical order traversal is :");
// Function Call
tree.verticalOrder(tree.root);
}
}
基于散列的解决方案的时间复杂度可以被认为是 O(n),前提是我们有良好的散列函数,允许在 O(1) 时间内进行插入和检索操作。在上面的 C++ 实现中,使用了 STL 的映射。 STL 中的映射通常使用自平衡二叉搜索树实现,其中所有操作都需要 O(Logn) 时间。因此上述实现的时间复杂度为 O(nLogn)。
请注意,上述解决方案可能不会以与树中出现的相同垂直顺序打印节点。例如,上面的程序在 9 之前打印 12。有关示例运行,请参见此处。
1
/ \
2 3
/ / \
4 5 6 7
/ \
8 10 9
\
11
\
12
有关基于级别顺序遍历的解决方案,请参阅下面的帖子。下面的帖子确保垂直线的节点按照它们在树中出现的顺序打印。
按垂直顺序打印二叉树 |设置 3(使用水平顺序遍历)
使用先序遍历方法,保持节点的顺序与它们在树中出现的垂直顺序相同:
我们还可以按照它们出现在树中的相同垂直顺序来维护节点的顺序。具有相同水平距离的节点将根据水平顺序打印。
例如,在下图中,9 和 12 具有相同的水平距离。我们可以确保如果像 12 这样的节点在同一条垂直线上,它会打印在像 9 这样的节点之后
思路:我们不使用水平距离作为地图中的key,而是使用水平距离+垂直距离作为key。我们知道在二叉树中节点的数量不能超过整数范围。
我们将使用前 30 位密钥作为水平距离 [MSB 到 LSB],并将使用后 30 位作为垂直距离。因此,密钥将根据我们的要求存储在地图中。
下面是上述方法的实现。
C++14
// C++ program for printing
// vertical order of a given binary
// tree
#include
using namespace std;
struct Node {
int data;
Node *left, *right;
};
struct Node* newNode(int data)
{
struct Node* node = new Node;
node->data = data;
node->left = node->right = NULL;
return node;
}
// Store vertical order
// in map "m", hd = horizontal
// distance, vd = vertical distance
void preOrderTraversal(Node* root,
long long int hd,
long long int vd,
map >& m)
{
if (!root)
return;
// key = horizontal
// distance (30 bits) + vertical
// distance (30 bits) map
// will store key in sorted
// order. Thus nodes having same
// horizontal distance
// will sort according to
// vertical distance.
long long val = hd << 30 | vd;
// insert in map
m[val].push_back(root->data);
preOrderTraversal(root->left, hd - 1, vd + 1, m);
preOrderTraversal(root->right, hd + 1, vd + 1, m);
}
void verticalOrder(Node* root)
{
// map to store all nodes in vertical order.
// keys will be horizontal + vertical distance.
map > mp;
preOrderTraversal(root, 0, 1, mp);
// print map
int prekey = INT_MAX;
map >::iterator it;
for (it = mp.begin(); it != mp.end(); it++) {
if (prekey != INT_MAX
&& (it->first >> 30) != prekey) {
cout << endl;
}
prekey = it->first >> 30;
for (int j = 0; j < it->second.size(); j++)
cout << it->second[j] << " ";
}
}
// Driver code
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->right->left->right = newNode(8);
root->right->right->right = newNode(9);
cout << "Vertical order traversal :- " << endl;
verticalOrder(root);
return 0;
}
Vertical order traversal :-
4
2
1 5 6
3 8
7
9
上述实现的时间复杂度为 O(n Log n)。
辅助空间:O(n)
另一种使用 computeIfAbsent 方法的方法:
我们可以用更简洁的方式编写代码,通过在Java使用map的computeIfAbsent方法,并使用树图进行基于键的自然排序。
下面是上述方法的实现。
Java
// Java Program for above approach
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
class Node {
int data;
Node left, right;
Node(int item)
{
data = item;
left = right = null;
}
}
public class BinaryTree {
Node root;
// Values class
class Values {
int max, min;
}
// Program to find vertical Order
public void verticalOrder(Node node)
{
Values val = new Values();
// Create TreeMap
Map > map
= new TreeMap >();
// Function Call to findHorizonatalDistance
findHorizonatalDistance(node, val, val, 0, map);
// Iterate over map.values()
for (List list : map.values()) {
System.out.println(list);
}
// Print "done"
System.out.println("done");
}
// Program to find Horizonatal Distance
public void findHorizonatalDistance(
Node node, Values min, Values max, int hd,
Map > map)
{
// If node is null
if (node == null)
return;
// if hd is less than min.min
if (hd < min.min)
min.min = hd;
// if hd is greater than min.min
if (hd > max.max)
max.max = hd;
// Using computeIfAbsent
map.computeIfAbsent(hd,
k -> new ArrayList())
.add(node.data);
// Function Call with hd equal to hd - 1
findHorizonatalDistance(node.left, min, max, hd - 1,
map);
// Function Call with hd equal to hd + 1
findHorizonatalDistance(node.right, min, max,
hd + 1, map);
}
// Driver Code
public static void main(String[] args)
{
BinaryTree tree = new BinaryTree();
/* Let us construct the tree shown
in above diagram */
tree.root = new Node(1);
tree.root.left = new Node(2);
tree.root.right = new Node(3);
tree.root.left.left = new Node(4);
tree.root.left.right = new Node(5);
tree.root.right.left = new Node(6);
tree.root.right.right = new Node(7);
tree.root.right.left.right = new Node(8);
tree.root.right.right.right = new Node(9);
System.out.println("vertical order traversal is :");
// Function Call
tree.verticalOrder(tree.root);
}
}
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。