题目来源
题目描述
给定一棵二叉树的头节点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);
}
}
};