哈希(2) - 垂直打印一棵二叉树(使用哈希表实现)

垂直打印给定的一棵二叉树。下面的例子演示了垂直遍历的顺序。

1

        /           2      3
      / \      /     4   5   6   7
               \                  8   9
对这棵树的垂直遍历结果为:
4
2
1 5 6
3 8
7
9

在二叉树系列中,已经讨论过了一种O(n2)的方案。在本篇中,将讨论一种基于哈希表的更优的方法。首先在水平方向上检测所有节点到root的距离。如果两个node拥有相同的水平距离(Horizontal Distance,简称HD), 则它们在相同的垂直线上。root自身的HD为0,右侧的node的HD递增,即+1,而左侧的node的HD递减,即-1。例如,上面的那棵树中,Node4的HD为-2,
而Node5和Node6的HD为0,Node7的HD为2.。

可以对二叉树做先序遍历。在遍历的过程中,可以递归的计算HD的值。首先指定root HD为0。对于左子树,递归的-1, 而对于右子树,递归的+1。对于每一个HD值,我们在哈希表中维护一个节点链表。当遍历时每获取到一个节点,则将此node插入到哈希表中,利用它的HD做为key。

下面是上述方法的C++实现。

<span style="font-size:12px;">// C++程序:垂直的打印一棵二叉树
#include <iostream>
#include <vector>
#include <map>

//二叉树的节点
struct Node
{
    int key;
    Node *left;
    Node *right;
};

//创建一个新的节点
Node* newNode(int key)
{
    Node* node = new Node;
    node->key = key;
    node->left = node->right = NULL;
    return node;
}

// 将垂直排序的节点存入哈希表m中;
// 参数distance表示当前节点到root的HD距离。初始值为0
void getVerticalOrder(Node* root, int distance, std::map<int, std::vector<int> > &result)
{
    // 检测特定情况
    if (root == NULL)
        return;

    // 将当前node存入map中
    result[distance].push_back(root->key);

    // 递归存储左子树。 注意:距离值是递减的
    getVerticalOrder(root->left, distance-1, result);

    // 递归存储右子树。注意:距离值是递增的
    getVerticalOrder(root->right, distance+1, result);
}

// 按照垂直顺序打印二叉树的节点
void printVerticalOrder(Node* root)
{
    //map存储所有垂直排序的节点
    std::map <int, std::vector<int> > result;
    int distance = 0;
    getVerticalOrder(root, distance, result);

    //遍历map,进行打印
    std::map< int,std::vector<int> > :: iterator it;
    for (it=result.begin(); it!=result.end(); it++)
    {
        for (unsigned int i=0; i<it->second.size(); ++i)
            std::cout << it->second[i] << " ";
        std::cout << std::endl;
    }
}

Node* generateBST()
{
  /* 构建二叉树树
         1
      /         2      3
    / \    /    4   5  6   7
           \               8   9
   */
  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);
  return root;
}

int main()
{
    Node *root = generateBST();
    std::cout << "Vertical order traversal is:"<<std::endl;
    printVerticalOrder(root);
    return 0;
}
</span>

输出:

Vertical order traversal is:

4

2

1 5 6

3 8

7

9

时间复杂度: 假设我们有一个比较好的哈希函数,能实现O(1)时间进行插入和检索,则基于哈希的这个方案的时间复杂度可以认为是O(n)。上述代码中,使用了STL
map。而STL map主要就是使用自平衡二叉树来实现的,其所有操作都是O(Logn)时间. 因此,上述方案的时间复杂都可以认为是O(nLogn).

时间: 2024-10-12 04:51:26

哈希(2) - 垂直打印一棵二叉树(使用哈希表实现)的相关文章

如何直观形象地树状打印一棵二叉树?

网上绝大部分的二叉树打印效果都十分潦草,也不够直观形象,最近自己用Java写了个打印器,可以实现如下效果 1 BinarySearchTree<Integer> bst1 = bst(new Integer[]{ 2 7, 4, 9, 2, 5, 8, 11, 1, 3, 6, 10, 12 3 }); 4 printer.treeln(bst1); 5 /* 6 7 7 / 8 4 9 9 / \ / 10 2 5 8 11 11 / \ \ / 12 1 3 6 10 12 13 */ 1

Invert a binary tree 翻转一棵二叉树

假设有如下一棵二叉树: 4  / \   2    7  / \   / \ 1  3 6  9翻转后: 4     /    \    7     2   / \    / \  9  6  3  1 这里采用递归的方法来处理.遍历结点,将每个结点的两个子结点交换位置即可. 从左子树开始,层层深入,由底向上处理结点的左右子结点:然后再处理右子树 全部代码如下: public class InvertBinaryTree { public static void main(String args

019写程序在一棵二叉树中找到两个结点的最近共同祖先(keep it up)

写程序在一棵二叉树中找到两个结点的最近共同祖先. 分两种情况来讨论这个题: 第一种情况结点中没有指向父结点的指针 第二种情况接种有指向父节点的指针 我们先看第一种情况,结点中没有指向父结点的指针. 我们可以采用暴力搜索每一个结点,如果这个结点的子树中 有已知的两个结点,那我们就继续沿着左右子树找,如果左子树 能找到,我们就继续沿着左子树找,如果有子树能找到,我们就 沿着右子树找,不存在两个子树都能够找到. 代码: struct TreeNode {<pre name="code"

判断一棵二叉树是不是平衡二叉树

二叉树中任意左右子树的深度相差不超过1,那么它就是一棵平衡二叉树. 两种解法. 第一种:菜鸟的解法,出现重复遍历,时间复杂度高. 1 bool IsBalanced(BinaryTreeNode* root) 2 { 3 if (root == NULL) 4 { 5 return true ; 6 } 7 int left = TreeDepth(root->m_pLeft);//该函数实现见我上一篇博客"数的深度" 8 int right = TreeDepth(root-&

编程实现判断一棵二叉树是否是平衡二叉树

Balanced Binary Tree Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1. 思路:遍历这棵二叉树,每访问

比较两棵二叉树--(比较两棵二叉树是否相同/判断一棵二叉树是否是另一棵二叉树的子树)

一,问题介绍 本文章讨论两个问题: ①如何判断两棵二叉树的结构是一样的.对应的每个结点都有着相同的值.--即判断两棵二叉树是一样的 ②给定两棵二叉树,如何判断一棵二叉树是另一棵二叉树的子结构 ③给定两棵二叉树,如何判断一棵二叉树是另一棵二叉树的子树 注意,子结点与子树有那么一点点不同. 上面的二叉树B 是二叉树A 的子结构,但是不能说是二叉树A的子树.但是二叉树C 是 二叉树A的子树. 二,问题分析 1,如何判断两棵二叉树的结构是一样的.且对应的每个结点都有着相同的值. 对于①如何判断两棵二叉树

编程实现求一棵二叉树的最短树路径和最长树路径

Minimum Depth of Binary Tree Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. class Solution { public: int minDepth(TreeNode *root) { if(!r

572. 是否为另一棵二叉树的子树 Subtree of Another Tree

Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s is a tree consists of a node in s and all of this node's descendants. The tree s could also be considere

【面试】判断一棵二叉树是否为二叉排序树

一.描述 给定一棵二叉树,如何判断一棵树是否是二叉排序树.给出树结点定义如下 class TreeNode { int key; TreeNode left; TreeNode right; public TreeNode(int key) { this.key = key; } } 二.解题思路 根据二叉排序树的性质,在进行中序遍历的时候,当前结点的值总是大于前驱结点的值,需要在遍历时保存前驱结点的值,这样有利于进行判断,基于这样的思路来进行解题. 三.代码 根据以上的解题思路(遍历时利用二叉