前序遍历(先根遍历) :
(1)先访问根节点 (2)前序访问左子树(3)前序访问右子树【1 2 3 4 5 6】
中序遍历:
(1)中序访问左子树 (2)访问根节点 (3)中序访问右子树【3 2 4 1 6 5】
后序遍历(后根遍历):
(1)后序访问左子树 (2)后序访问右子树(3)访问根节点【3 4 2 6 5 1】
层序遍历: 一层层节点依次遍历。 【1 2 5 3 4 6】
前序遍历:
要借助栈的后进先出的特性来完成。 我们将1,2,3分别压栈,3的左为空则停止压栈,取栈顶元素3存放在变量top中,并删除栈顶元素,访问top的右子树,它的右子树也为空,则取栈顶元素2并访问它的右子树,直至栈为空(中序遍历思想相同)
后序遍历:
我们要先访问了左子树和右子树才能访问根。所以我们在这里增加了一个变量prev,它用于记录上一个走过的结点 。
//前序遍历(中左右)——————递归
void PrevOrder()
{
_PrevOrder(_root);
}
void _PrevOrder(Node* root)
{
if(root == NULL)
return;
cout<_data<<" ";//中
_PrevOrder(root->_left);//左
_PrevOrder(root->_right);//右
}
//________________________________________________
//前序遍历(中左右)——————非递归
//________________________________________________
void PrevOrderNonR()
{
Node* cur = _root;
stack s;
while( cur || !s.empty())
{
while(cur)
{
cout<_data<<" ";
s.push(cur);
cur = cur->_left;
}//中左
Node* top = s.top();
s.pop();
cur = top->_right;
}
cout<//中序遍历(左中右)————————递归
void InOrder()
{
_InOrder(_root);
}
void _InOrder(Node* root)
{
if(root == NULL)
return;
_InOrder(root->_left);//左
cout<_data<<" ";//中
_InOrder(root->_right);//右
}
//________________________________________________
//中序遍历(左中右)——————非递归
//________________________________________________
void InOrderNonR()
{
Node* cur = _root;
stack s;
while( cur || !s.empty() )
{
while(cur)
{
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
cout<_data<<" ";
s.pop();
cur = top->_right;
}
cout<//________________________________________________
//后序遍历(左右中)——————递归
//________________________________________________
void PostOrder()
{
_PostOrder(_root);
}
void _PostOrder(Node* root)
{
if(root == NULL)
return;
_PostOrder(root->_left);//左
_PostOrder(root->_right);//右
cout<_data<<" ";//中
}
//________________________________________________
//后序遍历(左右中)——————非递归
//________________________________________________
void PostOrderNonR()
{
Node* cur = _root;
stack s;
Node* prev = NULL;
while( cur || !s.empty() )
{
while(cur)
{
s.push(cur);
cur = cur->_left; // 左
}
Node* top = s.top();
if(top->_right == NULL || top->_right == prev)// 如果当前节点的右子树为空 或者它的前一个节点为它的右节点(证明右节点已经访问过了),即打印当前节点的值(右中)
{
cout<_data<<" ";
s.pop();
prev = top;
}
else
cur = top->_right;// 右
}
cout<
Given a binary tree, return the preorder traversal of its nodes’ values. For example: Given binary tree{1,#,2,3},return[1,2,3]. Note: Recursive solution is trivial, could you do it iteratively?
class Solution {
public:
void _preorderTraversal(TreeNode *root,vector<int>& V){
if(root == NULL)
return;
V.push_back(root->val);
_preorderTraversal(root->left,V);
_preorderTraversal(root->right,V);
}
vector<int> preorderTraversal(TreeNode *root) {
//前序遍历二叉树 中左右
vector<int> V;
_preorderTraversal(root,V);
return V;
}
};
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void _postorderTraversal(TreeNode *root,vector<int> &V){
if(root == NULL)
return;
_postorderTraversal(root->left,V);
_postorderTraversal(root->right,V);
V.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode *root) {
vector<int> V;
_postorderTraversal(root,V);
return V;
}
};
思想:借助队列的先进先出。
先将根节点root(1)入队,然后拿出根节点,并且将根节点的左右孩子入队(2 5);再将队头节点(2)拿出来,将队头的左右孩子(3 4)入队,以此类推,直至队列为空,循环终止。
//层序遍历——广度优先遍历
void LevelOrder()
{
queue q;
if(_root)
q.push(_root);
while( !q.empty() )// 终止条件:队列为空
{
Node* front = q.front();
cout<_data<<" ";
q.pop();
// 队头pop(),将其左右非空节点入队
if(front->_left)
q.push(front->_left);
if(front->_right)
q.push(front->_right);
}
cout<
思想:化为子问题:比较左右子树的高度,高的树的depth+1就是二叉树的高度。(其中1是根节点,第一层)
//求高度
size_t Depth()
{
return _Depth(_root);
}
size_t _Depth(Node* root)
{
if(root == NULL)
return 0;
size_t leftDepth = _Depth(root->_left);
size_t rightDepth = _Depth(root->_right);
return leftDepth > rightDepth ? leftDepth+1 : rightDepth+1;
}
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{
if(pRoot == NULL)
return 0;
return max((1+TreeDepth(pRoot->left)),(1+TreeDepth(pRoot->right)));
}
};
//求树中叶子节点
//方法一:————化成子问题(左子树和右子树都为空,则返回1 其结果就是:左边叶子节点+右边叶子节点)
/*int LeafSize()
{
return _LeafSize(_root);
}
size_t _LeafSize(Node* root)
{
if(root == NULL)
return 0;
if(root->_left == NULL && root->_right == NULL)
{
return 1;
}
return _LeafSize(root->_left)+_LeafSize(root->_right);
}*/
//方法二:遍历
size_t LeafSize()
{
size_t size = 0;
_LeafSize(_root,size);
return size;
}
void _LeafSize(Node* root,size_t& size)
{
if(root == NULL)
return;
if(root->_left == NULL && root->_right == NULL)
++size;
_LeafSize(root->_left,size);
_LeafSize(root->_right,size);
}
//________________________________________________
//求第k层的结点数——————————————————递归(子问题)
//________________________________________________
size_t GetKLevelSize(size_t k)
{
return _GetKLevelSize(_root,k);
}
size_t _GetKLevelSize(Node* root,size_t k)
{
if(root == NULL)
return NULL;
if(k == 1)
return 1;
return _GetKLevelSize(root->_left,k-1)+ _GetKLevelSize(root->_right,k-1);
}
思想:如果根节点就是该节点则返回true;如果不是,就在该树的左子树找,找不到就在右子树找,直到找到为止。而如果都没有的话,就证明该节点不在这棵树中。
//________________________________________________
//6. 判断一个节点是否在一棵二叉树中
//________________________________________________
bool FindKey(const T& key)
{
return _FindKey(_root,key);
}
bool _FindKey(Node* _root,const T& key)
{
if(_root == NULL)
return false;
if(_root->_data == key)
return true;
// 子问题
if(_FindKey(_root->_left,key))
return true;
if(_FindKey(_root->_right,key))
return true;
return false;
}
思想:自己也是自己的祖先。(因为如果一个节点是root节点,那么他们的最近公共祖先就是根节点)
第一种情况:两个节点中,如果其中一个节点是根节点,则最近公共祖先就是根节点root
第二种情况:两个节点,一个在左子树,一个在右子树,两个节点的最近公共祖先是根节点root
第三种情况:如果都在左子树或者右子树,则化为子问题,继续重复第一或者第二种情况。
而这种方法的时间复杂度是:O(n^2),所以我们应该对其做优化,使其时间复杂度为:O(n)
//________________________________________________
// 7. 求两个节点的最近公共祖先
//________________________________________________
// 时间复杂度为O(n^2)
Node* LowestCommonAncestors(const T& x1,const T& x2)
{
return GetLCA(_root,x1,x2);
}
Node* GetLCA(Node* root,const T& x1,const T& x2)
{
if(root == NULL)
return NULL;
// 1. 其中一个节点如果是根节点,则最近公共祖先就是根节点root
if(x1 == root->_data || x2 == root->_data )
return root;
// 判断两个节点在左子树还是右子树
bool x1Inleft,x1Inright,x2Inleft,x2Inright;
x1Inleft = _FindKey(root->_left,x1);
if( x1Inleft == false)
{
x1Inright = true;
}
else
{
x1Inright = false;
}
x2Inleft = _FindKey(root->_left,x2);
if(x2Inleft == false)
{
x2Inright = true;
}
else
{
x2Inright = false;
}
// 2. 两个节点,一个在左子树,一个在右子树,两个节点的最近公共祖先是根节点root
if( (x1Inleft&&x2Inright) || (x2Inleft&&x1Inright) )
return root;
// 3. 如果都在左子树或者右子树,则化为子问题
if( x1Inleft&&x2Inleft )
return GetLCA(root->_left,x1,x2);
else
return GetLCA(root->_right,x1,x2);
}
思想:平衡二叉树的条件就是:1. 左右子树的高度之差的绝对值 <= 1 2.并且左右子树都是平衡二叉树
其主要的方法请看我的另外一篇博客:
https://blog.csdn.net/qq_37941471/article/details/79748878
//________________________________________________
// 8. 判断一棵树是否是平衡二叉树
//________________________________________________
//1. 递归——时间复杂度:O(n^2)
// (递归的次数*每次递归的次数)
// 每个节点的遍历*高度(也是遍历整个树)
// bool IsBalance()
// {
// int depth = 0;
// return _IsBalance(_root);
// }
// int MaxDepth(Node* root)
// {
// if (NULL == root)
// return 0;
// int left = MaxDepth(root->_left)+1;
// int right = MaxDepth(root->_right) + 1;
// return left > right ? left : right;
// }
// bool _IsBalance(Node* root)
// {
// //递归的终止条件
// if(root == NULL)
// {
// return true;
// }
// int leftHeight = MaxDepth(root->_left);
// int rightHeight = MaxDepth(root->_right);
// return abs(rightHeight-leftHeight) < 2
// && _IsBalance(root->_left)
// && _IsBalance(root->_right);
// }
//2. 优化——时间复杂度O(n)——高度只遍历一次
bool IsBalance()
{
int depth = 0;
return _IsBalance(_root,depth);
}
bool _IsBalance(Node* root,int& depth)
{
if(root == NULL)
{
return true;
}
int left = 0;
int right = 0;
if(_IsBalance(root->_left,left)&&_IsBalance(root->_right,right))
{
if( abs(left-right) > 1 )
return false;
depth = (left > right ? left : right)+1;
return true;
}
return false;
}
必须用优化后的代码,时间复杂度为O(n)
class Solution {
public:
bool IsBalanced(TreeNode* root,int& depth){
if(root == NULL){
return true;
}
int left = 0;
int right = 0;
if(IsBalanced(root->left,left)&&IsBalanced(root->right,right)){
if( abs(left-right) > 1 )
return false;
depth = (left > right ? left : right)+1;
return true;
}
return false;
}
bool IsBalanced_Solution(TreeNode* pRoot) {
int depth = 0;
return IsBalanced(pRoot,depth);
}
};