目录
题目
翻转一棵二叉树。
示例:
输入:
4
/
2 7
/ \ /
1 3 6 9
输出:
4
/
7 2
/ \ /
9 6 3 1
1、层序法:
层序遍历,然后将同一层的所有结点的左右孩子交换
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*> que;
if(root!=NULL) que.push(root);
while(!que.empty())
{
int size = que.size();
for(int i =0;i<size;i++)
{
TreeNode* node = que.front();
que.pop();
TreeNode* tmp;
tmp = node->left;
node->left = node->right;
node->right = tmp;
//将左右孩子结点入队列,作为下一层的元素
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return root;
}
};
2、递归法:
遍历的过程中去翻转每一个结点的左右孩子就可以达到整体翻转的效果。
可以使用先序遍历和后序遍历,而中序遍历会把某些结点的左右孩子翻转两次。
1、先序遍历(中左右)
递归思考过程:
1、返回值:void 形参:指向结点的指针
2、终止条件:指向结点的指针为空指针
3、递归内部逻辑:先翻转指针指向的结点的左右孩子,然后递归遍历左右子树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void traversal(TreeNode* cur)
{
//终止条件
if(cur == NULL) return;
//逻辑:先交换左右子树内容,然后对左右子树依次进行遍历
TreeNode* tmp;
tmp = cur->left;
cur->left = cur->right;
cur->right = tmp;
traversal(cur->left);
traversal(cur->right);
}
TreeNode* invertTree(TreeNode* root) {
traversal(root);
return root;
}
};
2、后序遍历(左右中)
递归思考过程:
1、返回值:void 形参:指向结点的指针
2、终止条件:指向结点的指针为空指针
3、递归内部逻辑:先递归遍历左右子树,再翻转指针指向的结点的左右孩子
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void traversal(TreeNode* cur)
{
//终止条件
if(cur == NULL) return;
traversal(cur->left);
traversal(cur->right);
TreeNode* tmp;
tmp = cur->left;
cur->left = cur->right;
cur->right = tmp;
}
TreeNode* invertTree(TreeNode* root) {
traversal(root);
return root;
}
};
为什么后序遍历的方法更加快捷?
3、递归中序遍历为什么不行(左中右)
中序遍历之后是这样的:
因为交换完左右结点后,想要遍历右子树,实际由于进行了交换操作,遍历的还是原来的左子树。
如下图:
3、迭代法:
1、先序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if(root !=NULL) st.push(root);
while(!st.empty())
{
TreeNode* node = st.top();
//标记操作,直到遇到NULL
if(node!=NULL)
{
//将该结点弹出,避免重复操作
st.pop();
//添加右结点
if(node->right) st.push(node->right);
//添加左结点
if(node->left) st.push(node->left);
//添加中结点
st.push(node);
//标记
st.push(NULL);
}
//只有遇到空结点的时候,才将下一个结点的左右子结点进行交换
else
{
//弹出空结点
st.pop();
node = st.top();
st.pop();
TreeNode* tmp;
tmp = node->left;
node->left = node->right;
node->right = tmp;
}
}
return root;
}
};
2、中序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if(root !=NULL) st.push(root);
while(!st.empty())
{
TreeNode* node = st.top();
//标记操作,直到遇到NULL
if(node!=NULL)
{
//将该结点弹出,避免重复操作
st.pop();
//添加右结点
if(node->right) st.push(node->right);
//添加中结点
st.push(node);
//标记
st.push(NULL);
//添加左结点
if(node->left) st.push(node->left);
}
//只有遇到空结点的时候,才将下一个结点的左右子结点进行交换
else
{
//弹出空结点
st.pop();
node = st.top();
st.pop();
TreeNode* tmp;
tmp = node->left;
node->left = node->right;
node->right = tmp;
}
}
return root;
}
};
3、后序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if(root !=NULL) st.push(root);
while(!st.empty())
{
TreeNode* node = st.top();
//标记操作,直到遇到NULL
if(node!=NULL)
{
//将该结点弹出,避免重复操作
st.pop();
//添加中结点
st.push(node);
//标记
st.push(NULL);
//添加右结点
if(node->right) st.push(node->right);
//添加左结点
if(node->left) st.push(node->left);
}
//只有遇到空结点的时候,才将下一个结点的左右子结点进行交换
else
{
//弹出空结点
st.pop();
node = st.top();
st.pop();
TreeNode* tmp;
tmp = node->left;
node->left = node->right;
node->right = tmp;
}
}
return root;
}
};
为什么迭代法的中序遍历有效?
迭代的中序方法可以,因为先将交换前的右子树值存放到栈内了,即使后面进行了交换,想要遍历右子树时,是取栈内交换前的右子树值,而不是交换后的。
如图: