算法:打印二叉树的边界节点

题目来源

题目描述

给定一棵二叉树的头节点head,

按照两种标准分别实现二叉树边界节点的逆时针打印

标准一

  • 头节点为边界节点
  • 叶节点为边界节点
  • 如果节点在其所在的层中是最左或者最右边,那么也是边界节点

标准二

  • 头节点作为边界节点
  • 叶节点位边界节点
  • 树左边界延伸下去的路径为边界节点
  • 树右边界延伸下去的路径为边界节点

举个例子:
在这里插入图片描述
按照标准1打印:1,2,4,7,11,13,14,15,16,12,10,6,3
按照标准2打印: 1,2,4,7,13,14,15,16,10,6,3

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {

public:
    void printEdge(TreeNode *head){
        
    }
};

题目实现

按照标准一

在这里插入图片描述

思路:
(1)得到二叉树每一层上最左和最右的节点

在这里插入图片描述
(2)从上到下打印所有层中的最左节点。得到:1、2、4、7、11、13
(3)先序遍历二叉树,打印哪些不属于某一层最左或者最优的节点,但是是叶子节点的节点。得到:14、15
(4)从下到上打印所有层中的最右节点,但是节点不能即使最左节点,又是最右节点。得到:16、12、10、6、3

class Solution {
    int getHeight(TreeNode *head, int height){
        if(head == nullptr){
            return height;  
        }
        return std::max(getHeight(head->left, height + 1), getHeight(head->right, height + 1 ));
    }
    
    void setEdgeMap(TreeNode *head, int height, std::vector<std::vector<TreeNode*>> &edge){
        if(head == nullptr){
            return ;
        }
        edge[height][0] = edge[height][0] == nullptr ? head : edge[height][0];
        edge[height][1] = head;
        setEdgeMap(head->left, height + 1, edge);
        setEdgeMap(head->right, height + 1, edge);
    }
    
    void printfLeafNotInMap(TreeNode *head, int height, std::vector<std::vector<TreeNode*>> &edge){
        if(head == nullptr){
            return;
        }
        if(head->left == nullptr && head->right == nullptr && head != edge[height][0] && head != edge[height][1]){
            printf("%d\t", head->val);
        }
        printfLeafNotInMap(head->left, height + 1, edge);
        printfLeafNotInMap(head->right, height + 1, edge);
    }
    
    
public:
    void printEdge(TreeNode *head){
        if(head == nullptr){
            return;
        }
        
        int height = getHeight(head, 0);
        std::vector<std::vector<TreeNode*>> edge(height, std::vector<TreeNode*>(2, nullptr));
        setEdgeMap(head, 0, edge);
        //打印左边界
        for (int i = 0; i < edge.size(); ++i) {
            printf("%d\t", edge[i][0]->val);
        }
        //打印既不是左边界,也不是右边界的叶子节点 
        printfLeafNotInMap(head, 0, edge);
        //打印右边界但是不是左边界的节点
        for (int i = (int)edge.size() - 1; i != -1; --i) {
            if(edge[i][0] != edge[i][1]){
                printf("%d\t", edge[i][1]->val);
            }
        }
    }
};

按照标准二

在这里插入图片描述

过程:
(1)从头结点开始往下找,只要找到第一个既有左孩子,又有右孩子,则进入步骤2

  • 此过程中,找过的节点都打印。以上图例子举例,就是打印1, 打印完1之后,再进入步骤2
  • 如果在整个树的查找过程中都不存在既有左子树,又有右子树的节点,如下图,那么打印找过的节点然后直接返回即可
    在这里插入图片描述

(2)head的左子树进入步骤3的打印过程;head的右子树进入步骤4的打印过程

(3)打印左边界的延伸路径以及head左子树上所有的叶节点

  • 从上到下打印(前序遍历)
  • 左边界(而且是叶子节点,但是根节点一定会打印)一定会打印
  • 只有当前节点打印了&&左子树为空时,才打印右子树

(4)打印右边界的延伸路径以及head右子树上所有的叶节点

  • 从下到上打印(后序遍历)
  • 右边界(而且是叶子节点,但是根节点一定会打印)一定会打印
  • 只有当前节点打印了&&右子树为空时,才打印左子树

实现:

class Solution {
    void printLeftEdge(TreeNode *head, bool  print){
        if(head == nullptr){
            return;
        }
        
        if(print || (head->left == nullptr && head->right == nullptr)){
            printf("%d\t", head->val);
        }
        printLeftEdge(head->left, print);
        printLeftEdge(head->right, print && head->left == nullptr);
    }
    void printRightEdge(TreeNode *head, bool  print){
        if(head == nullptr){
            return;
        }
        printRightEdge(head->left, print && head->right == nullptr);
        printRightEdge(head->right, print);
        if(print || (head->left == nullptr && head->right == nullptr)){
            printf("%d\t", head->val);
        }
    }
public:
    void printEdge(TreeNode *head){
        if(head == nullptr){
            return;
        }

        printf("%d\t", head->val);
        if(head->left != nullptr && head->right != nullptr){
            printLeftEdge(head->left, true);
            printRightEdge(head->right, true);
        }else{
            printEdge(head->left == nullptr ? head->right : head->left);
        }
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值