目录  
 1. 二叉搜索树 1.1 二叉搜索树的结构 1.2 二叉搜索树的接口及其优点与不足 1.3 二叉搜索树自实现 1.3.1 二叉树结点结构 1.3.2 查找 1.3.3 插入 1.3.4 删除 1.3.5 中序遍历   
    
  2. 二叉树进阶相关练习 2.1 根据二叉树创建字符串 2.2 二叉树的层序遍历I 2.3 二叉树层序遍历II 2.4 二叉树最近公共祖先结点 2.5 二叉树搜索与双向链表 2.6 从前序与中序遍历序列构造二叉树 2.7 从中序与后序遍历序列构造二叉树 2.8 二叉树前序遍历(非递归) 2.9 二叉树中序遍历(非递归) !!!3.10 二叉树后序遍历(非递归)   
   
  
 
 1. 二叉搜索树  
 1.1 二叉搜索树的结构  
 
 搜索二叉树中的所有结点都满足  <1> 若左子树不为空,则其所有结点的键值都小于父结点  <2> 若右子树不为空,则其所有结点的键值都大于父节点  <3> 左右子树都为二叉搜索树   
  
 
 1.2 二叉搜索树的接口及其优点与不足  
 
 搜索二叉树的功能接口  <1> 数据插入(Insert)  <2> 数据删除(Erase)  <3> 数据查寻(Find)  <4> 中序遍历(InOrder)   
  
 
 二叉搜索树的优点:  <1> 正如其名,此种数据存储结构,尤其擅长数据搜索,其进行数据搜索的效率极高。  <2> 在其结构为近似完全二叉树或满二叉树的情况时,其的搜索效率可以达到O( 
       
        
         
         
           l 
          
         
           o 
          
         
           g 
          
         
           N 
          
         
        
          logN 
         
        
       l o g N  )  <3> 当以中序遍历的方式遍历整棵搜索树时,得到的数据即为升序序列   
  
 
 
 二叉搜索树的不足:  <1> 根据二叉搜索树的插入逻辑,当数据以完全升序或降序插入时,会使得二叉树退化为单枝结构,此种结构下其搜索效率也退化为O(N)   
  
 
 1.3 二叉搜索树自实现  
 1.3.1 二叉树结点结构  
 
 搜索树结点:由左右孩子结点指针与key组成 搜索树:由根节点与类方法构成   
  
template < class  T > 
struct  BinarySearchNode 
{ 
	typedef  BinarySearchNode< T>  BSNode; 
	BSNode*  _left; 
	BSNode*  _right; 
	T _key; 
	BinarySearchNode ( T key) 
		: _left ( nullptr ) 
		, _right ( nullptr ) 
		, _key ( key) 
	{ } 
} ; 
template < class  T > 
class  BinarySearchTree 
{ 
public : 
	typedef  BinarySearchNode< T>  BSNode; 
	
	
	bool  Find ( T key) ; 
	
	bool  Insert ( T key) ; 
	
	bool  Erase ( T key) ; 
	
	void  InOrder ( ) ; 
private : 
	BSNode*  _root =  nullptr ; 
} ; 
  
 1.3.2 查找  
 
 查找实现:在一颗搜索树中搜寻一个数据是否存在 查找逻辑:  <1> 若查找值小于当前结点的key值,向左搜寻,向左孩子查找  <2> 若查找值大于当前结点的key值,向右搜寻,向右孩子查找  <3> 查找遍历至空结点,则证明搜索树中不存在此值   
  
bool  Find ( T key) 
{ 
	BSNode*  cur =  _root; 
	while  ( cur) 
	{ 
		if  ( key <  cur-> _key) 
		{ 
			cur =  cur-> _left; 
		} 
		else  if  ( key >  cur-> _key) 
		{ 
			cur =  cur-> _right; 
		} 
		else 
		{ 
			return  true ; 
		} 
	} 
	return  false ; 
} 
bool  _FindR ( BSNode*  cur,  T key) 
{ 
	if  ( cur ==  nullptr ) 
	{ 
		return  false ; 
	} 
	if  ( key <  cur-> _key) 
	{ 
		return  _FindR ( cur-> _left,  key) ; 
	} 
	else  if  ( key >  cur-> _key) 
	{ 
		return  _FindR ( cur-> _right,  key) ; 
	} 
	else 
	{ 
		return  true ; 
	} 
	
	assert ( true ) ; 
	return  - 1 ; 
} 
bool  FindR ( T key) 
{ 
	return  _FindR ( _root,  key) ; 
} 
  
 1.3.3 插入  
 
 搜寻插入位置:  <1> key小向左  <2> key大向右  <3> 直至遍历到空 <1> 若遇key相同的结点,停止插入,返回false  <2> 遍历至空,创建结点,链接结点   
  
bool  Insert ( T key) 
{ 
	
	if  ( _root ==  nullptr ) 
	{ 
		_root =  new  BSNode ( key) ; 
		return  true ; 
	} 
	BSNode*  cur =  _root; 
	BSNode*  parent =  nullptr ; 
	while  ( cur) 
	{ 
		if  ( key <  cur-> _key) 
		{ 
			parent =  cur; 
			cur =  cur-> _left
		} 
		else  if  ( key >  cur-> _key) 
		{ 
			parent =  cur; 
			cur =  cur-> _right; 
		} 
		else 
		{ 
			return  false ; 
		} 
	} 
	
	if  ( key <  parent-> _key) 
	{ 
		parent-> _left =  new  BSNode ( key) ; 
	} 
	else 
	{ 
		parent-> _right =  new  BSNode ( key) ; 
	} 
	return  true ; 
} 
bool  _InsertR ( BSNode* &  cur,  T key) 
{ 
	
	
	if  ( cur ==  nullptr ) 
	{ 
		cur =  new  BSNode ( key) ; 
		return  true ; 
	} 
	if  ( key <  cur-> _key) 
	{ 
		return  _InsertR ( cur-> _left,  key) ; 
	} 
	else  if  ( key >  cur-> _key) 
	{ 
		return  _InsertR ( cur-> _right,  key) ; 
	} 
	else 
	{ 
		return  false ; 
	} 
	assert ( true ) ; 
	return  false ; 
} 
bool  InsertR ( T key) 
{ 
	if  ( _root ==  nullptr ) 
	{ 
		_root =  new  BSNode ( key) ; 
		
		return  true ; 
	} 
	return  _InsertR ( _root,  key) ; 
} 
  
 1.3.4 删除  
 
 删除结点后,不能破坏搜索树的结构 删除不同类型结点的场景,删除逻辑:  <1> 叶子结点,直接删除,父节点链接指针置空  <2> 单子树结点,托孤,即,将自己的子树链接给父结点  <3> 双子树结点,寻找key值最接近的结点(左子树的最右结点,右子树的最左结点),值替换被删除的结点,而后删除被替换的结点   
  
叶子结点   单子树结点   双子树结点     
bool  Erase ( T key) 
{ 
	BSNode*  cur =  _root; 
	BSNode*  parent =  nullptr ; 
	while  ( cur) 
	{ 
		
		if  ( key <  cur-> _key) 
		{ 
			parent =  cur; 
			cur =  cur-> _left; 
		} 
		else  if  ( key >  cur-> _key) 
		{ 
			parent =  cur; 
			cur =  cur-> _right; 
		} 
		else 
		{ 
			
			
			if  ( cur-> _left ==  nullptr  ||  cur-> _right ==  nullptr ) 
			{ 
				
				if  ( cur ==  _root) 
				{ 
					if  ( cur-> _left) 
					{ 
						_root =  cur-> _left; 
					} 
					else 
					{ 
						_root =  cur-> _right; 
					} 
					delete  cur; 
				} 
				else 
				{ 
					
					if  ( cur-> _left) 
					{ 
						if  ( cur ==  parent-> _left) 
						{ 
							parent-> _left =  cur-> _left; 
						} 
						else 
						{ 
							parent-> _right =  cur-> _left; 
						} 
						delete  cur; 
					} 
					else 
					{ 
						if  ( cur ==  parent-> _left) 
						{ 
							parent-> _left =  cur-> _right; 
						} 
						else 
						{ 
							parent-> _right =  cur-> _right; 
						} 
						delete  cur; 
					} 
				} 
				return  true ; 
			} 
			else 
			{ 
				
				BSNode*  RightParent =  cur; 
				BSNode*  RightMin =  cur-> _right; 
				while  ( RightMin-> _left) 
				{ 
					RightParent =  RightMin; 
					RightMin =  RightMin-> _left; 
				} 
				
				cur-> _key =  RightMin-> _key; 
				
				
				
				if  ( RightMin ==  RightParent-> _left) 
				{ 
					RightParent-> _left =  RightMin-> _right; 
				} 
				else 
				{ 
					RightParent-> _right =  RightMin-> _right; 
				} 
				
				delete  RightMin; 
				return  true ; 
			} 
		} 
	} 
	
	return  false ; 
} 
bool  _EraseR ( BSNode* &  cur,  T key) 
{ 
	if  ( cur ==  nullptr ) 
	{ 
		return  false ; 
	} 
	
	if  ( key <  cur-> _key) 
	{ 
		return  _EraseR ( cur-> _left,  key) ; 
	} 
	else  if  ( key >  cur-> _key) 
	{ 
		return  _EraseR ( cur-> _right,  key) ; 
	} 
	else 
	{ 
		
		if  ( cur-> _left ==  nullptr  ||  cur-> _right ==  nullptr ) 
		{ 
			BSNode*  del =  cur; 
			if  ( cur-> _left) 
			{ 
				cur =  cur-> _left; 
			} 
			else 
			{ 
				cur =  cur-> _right; 
			} 
			delete  del; 
			return  true ; 
		} 
		else 
		{ 
			
			BSNode*  RightMin =  cur-> _right; 
			while  ( RightMin-> _left) 
			{ 
				RightMin =  RightMin-> _left; 
			} 
			
			cur-> _key =  RightMin-> _key; 
			
			
			_EraseR ( cur-> _right,  cur-> _key) ; 
		} 
	} 
	assert ( true ) ; 
	return  false ; 
} 
  
 1.3.5 中序遍历  
void  _InOrder ( BSNode*  cur) 
{ 
	if  ( cur ==  nullptr ) 
	{ 
		return ; 
	} 
	
	_InOrder ( cur-> _left) ; 
	cout <<  cur-> _key <<  " " ; 
	_InOrder ( cur-> _right) ; 
} 
void  InOrder ( ) 
{ 
	_InOrder ( _root) ; 
	cout <<  endl; 
} 
  
 2. 二叉树进阶相关练习  
 2.1 根据二叉树创建字符串  
 
 题目信息:   题目连接:  根据二叉树创建字符串   
  
class  Solution  
{ 
public : 
    void  _tree2str ( string&  str,  TreeNode*  cur) 
    { 
        if ( cur ==  nullptr ) 
        { 
            return ; 
        } 
        
        str +=  to_string ( cur-> val) ; 
        
        if ( cur-> left ||  cur-> right) 
        { 
            str +=  "(" ; 
            _tree2str ( str,  cur-> left) ; 
            str +=  ")" ; 
        } 
        if ( cur-> right) 
        { 
            str +=  "(" ; 
            _tree2str ( str,  cur-> right) ; 
            str +=  ")" ; 
        } 
    } 
    string tree2str ( TreeNode*  root)  
    { 
        string ret; 
        
        _tree2str ( ret,  root) ; 
        return  ret; 
    } 
} ; 
  
 2.2 二叉树的层序遍历I  
 
 题目信息:   题目连接:  二叉树的层序遍历I 思路:levelsize计数   
  
class  Solution 
{ 
public : 
    vector< vector< int >>  levelOrder ( TreeNode*  root) 
    { 
        
        vector< vector< int >>  ret; 
        queue< TreeNode* >  q; 
        int  levelsize =  1 ; 
        q. push ( root) ; 
        
        if ( root ==  nullptr ) 
        { 
            return  ret; 
        } 
        while  ( ! q. empty ( ) ) 
        { 
            vector< int >  count; 
            while  ( levelsize-- ) 
            { 
                
                TreeNode*  top =  q. front ( ) ; 
                q. pop ( ) ; 
                count. push_back ( top-> val) ; 
                
                if  ( top-> left) 
                    q. push ( top-> left) ; 
                if  ( top-> right) 
                    q. push ( top-> right) ; 
            } 
            levelsize =  q. size ( ) ; 
            ret. push_back ( count) ; 
        } 
        return  ret; 
    } 
} ; 
  
 2.3 二叉树层序遍历II  
 
 题目信息:   题目连接:  二叉树层序遍历II 思路:反转自上至下的层序遍历   
  
class  Solution  
{ 
public : 
    vector< vector< int >>  levelOrderBottom ( TreeNode*  root)  
    { 
        
        
        vector< vector< int >>  ret; 
        if ( root ==  nullptr ) 
        { 
            return  ret; 
        } 
        queue< TreeNode* >  q; 
        int  levelsize =  1 ; 
        q. push ( root) ; 
        while ( ! q. empty ( ) ) 
        { 
            vector< int >  count; 
            while ( levelsize-- ) 
            { 
                TreeNode*  cur =  q. front ( ) ; 
                q. pop ( ) ; 
                count. push_back ( cur-> val) ; 
                if ( cur-> left) 
                    q. push ( cur-> left) ; 
                if ( cur-> right) 
                    q. push ( cur-> right) ; 
            } 
            levelsize =  q. size ( ) ; 
            ret. push_back ( count) ; 
        } 
        reverse ( ret. begin ( ) ,  ret. end ( ) ) ; 
        return  ret; 
    } 
} ; 
  
 2.4 二叉树最近公共祖先结点  
 
 题目信息:   二叉树最近公共祖先结点 思路:  <1> 方法1:p与q一定分别在祖先结点的左侧与右侧,祖先结点可能是自己  <2> 方法2:栈记录遍历路径,路径上的所有祖先结点   
  
class  Solution  
{ 
public : 
    bool  SearchNode ( TreeNode*  cur,  TreeNode*  search) 
    { 
        if ( cur ==  nullptr ) 
        { 
            return  false ; 
        } 
        if ( cur ==  search) 
        { 
            return  true ; 
        } 
        return  SearchNode ( cur-> left,  search)  ||  SearchNode ( cur-> right,  search) ; 
    } 
    TreeNode*  lowestCommonAncestor ( TreeNode*  root,  TreeNode*  p,  TreeNode*  q)  
    { 
        bool  qInleft =  false ; 
        bool  qInright =  false ; 
        bool  pInleft =  false ; 
        bool  pInright =  false ; 
        TreeNode*  cur =  root; 
        while ( cur) 
        { 
            
            if ( cur ==  p) 
            { 
                pInleft =  pInright =  true ; 
            } 
            else  if ( SearchNode ( cur-> left,  p) ) 
            { 
                pInleft =  true ; 
                pInright =  false ; 
            } 
            else 
            { 
                pInright =  true ; 
                pInleft =  false ; 
            } 
            if ( cur ==  q) 
            { 
                qInleft =  qInright =  true ; 
            } 
            else  if ( SearchNode ( cur-> left,  q) ) 
            { 
                qInleft =  true ; 
                qInright =  false ; 
            } 
            else 
            { 
                qInright =  true ; 
                qInleft =  false ; 
            } 
            if ( ( pInleft &&  qInright)  ||  ( pInright &&  qInleft) ) 
                break ; 
            else  if ( pInleft &&  qInleft) 
                cur =  cur-> left; 
            else 
                cur =  cur-> right; 
        } 
        return  cur; 
    } 
} ; 
class  Solution  
{ 
public : 
    bool  PreOrder ( TreeNode*  cur,  TreeNode*  search,  stack< TreeNode* > &  count) 
    { 
        if ( cur ==  nullptr ) 
        { 
            return  false ; 
        } 
        count. push ( cur) ; 
        if ( cur ==  search) 
        { 
            return  true ; 
        } 
        if ( ! PreOrder ( cur-> left,  search,  count)  &&  ! PreOrder ( cur-> right,  search,  count) ) 
        { 
            count. pop ( ) ; 
        } 
        else 
        { 
            return  true ; 
        } 
        assert ( true ) ; 
        return  false ; 
    } 
    TreeNode*  lowestCommonAncestor ( TreeNode*  root,  TreeNode*  p,  TreeNode*  q)  
    { 
        
        
        
        stack< TreeNode* >  p_st; 
        stack< TreeNode* >  q_st; 
        PreOrder ( root,  p,  p_st) ; 
        PreOrder ( root,  q,  q_st) ; 
        
        while ( p_st. size ( )  !=  q_st. size ( ) ) 
        { 
            if ( p_st. size ( )  >  q_st. size ( ) ) 
                p_st. pop ( ) ; 
            else 
                q_st. pop ( ) ; 
        } 
        while ( p_st. top ( )  !=  q_st. top ( ) ) 
        { 
            p_st. pop ( ) ; 
            q_st. pop ( ) ; 
        } 
        return  p_st. top ( ) ; 
    } 
} ; 
  
 2.5 二叉树搜索与双向链表  
 
 题目信息:   题目链接:  二叉搜索树与双向链表 思路:记录前置结点,中序遍历,注意调整指针链接的时机   
  
class  Solution  
{ 
public : 
	void  InOrder ( TreeNode*  cur,  TreeNode* &  pre) 
	{ 
		if ( cur ==  nullptr ) 
		{ 
			return ; 
		} 
		InOrder ( cur-> left,  pre) ; 
		cur-> left =  pre; 
		if ( pre) 
			pre-> right =  cur; 
		
		pre =  cur; 
		InOrder ( cur-> right,  pre) ; 
	} 
    TreeNode*  Convert ( TreeNode*  pRootOfTree)  
	{ 
		if ( pRootOfTree ==  nullptr ) 
		{ 
			return  nullptr ; 
		} 
		TreeNode*  pre =  nullptr ; 
		InOrder ( pRootOfTree,  pre) ; 
		while ( pRootOfTree-> left) 
		{ 
			pRootOfTree =  pRootOfTree-> left; 
		} 
		return  pRootOfTree; 
    } 
} ; 
  
 2.6 从前序与中序遍历序列构造二叉树  
 
 题目信息:   题目链接:  从前序与中序遍历序列构造二叉树 思路:根据根分割出左右子树,区域分割,引用   
  
class  Solution  
{ 
public : 
    TreeNode*  buildNode ( vector< int > &  preorder,  vector< int > &  inorder,  int &  i,  int  left,  int  right) 
    { 
        if ( left >  right) 
        { 
            return  nullptr ; 
        } 
        
        int  j =  0 ; 
        while ( inorder[ j]  !=  preorder[ i] ) 
        { 
            j++ ; 
        } 
        
        
        TreeNode*  newnode =  new  TreeNode ( preorder[ i++ ] ) ; 
        
        newnode-> left =  buildNode ( preorder,  inorder,  i,  left,  j -  1 ) ; 
        
        newnode-> right =  buildNode ( preorder,  inorder,  i,  j +  1 ,  right) ; 
        
        return  newnode; 
    } 
    TreeNode*  buildTree ( vector< int > &  preorder,  vector< int > &  inorder)  
    { 
        int  i =  0 ; 
        return  buildNode ( preorder,  inorder,  i,  0 ,  inorder. size ( )  -  1 ) ; 
    } 
} ; 
  
 2.7 从中序与后序遍历序列构造二叉树  
 
 题目信息:   题目链接:  从中序与后序遍历序列构造二叉树 思路:区域分割判断,引用,逆向遍历,根右左   
  
class  Solution  
{ 
public : 
    TreeNode*  buildNode ( vector< int > &  inorder,  vector< int > &  postorder,  int &  i,  int  left,  int  right) 
    { 
        if ( left >  right) 
        { 
            return  nullptr ; 
        } 
        int  j =  0 ; 
        while ( inorder[ j]  !=  postorder[ i] ) 
        { 
            j++ ; 
        } 
        TreeNode*  newnode =  new  TreeNode ( postorder[ i-- ] ) ; 
        newnode-> right =  buildNode ( inorder,  postorder,  i,  j +  1 ,  right) ; 
        newnode-> left =  buildNode ( inorder,  postorder,  i,  left,  j -  1 ) ; 
        return  newnode; 
    } 
    TreeNode*  buildTree ( vector< int > &  inorder,  vector< int > &  postorder)  
    { 
        
        int  i =  postorder. size ( )  -  1 ; 
        return  buildNode ( inorder,  postorder,  i,  0 ,  postorder. size ( )  -  1 ) ; 
    } 
} ; 
  
 2.8 二叉树前序遍历(非递归)  
 
 题目信息:   题目链接:  二叉树前序遍历 思路:根左右,插入右子树时就将根删除,栈记录   
  
class  Solution  
{ 
public : 
    vector< int >  preorderTraversal ( TreeNode*  root)  
    { 
        
        vector< int >  ret; 
        TreeNode*  cur =  root; 
        stack< TreeNode* >  st; 
        while ( cur ||  ! st. empty ( ) ) 
        { 
            while ( cur) 
            { 
                st. push ( cur) ; 
                ret. push_back ( cur-> val) ; 
                cur =  cur-> left; 
            } 
            TreeNode*  top =  st. top ( ) ; 
            st. pop ( ) ; 
            cur =  top-> right; 
        } 
        return  ret; 
    } 
} ; 
  
 2.9 二叉树中序遍历(非递归)  
 
 题目信息:   题目链接:  二叉树中序遍历 思路:插入时机,删除时插入,左右根   
  
class  Solution  { 
public : 
    vector< int >  inorderTraversal ( TreeNode*  root)  
    { 
        
        vector< int >  ret; 
        stack< TreeNode* >  st; 
        TreeNode*  cur =  root; 
        
        while ( cur ||  ! st. empty ( ) ) 
        { 
            while ( cur) 
            { 
                st. push ( cur) ; 
                cur =  cur-> left; 
            } 
            TreeNode*  top =  st. top ( ) ; 
            st. pop ( ) ; 
            ret. push_back ( top-> val) ; 
            cur =  top-> right; 
        } 
        return  ret; 
    } 
} ; 
  
 !!!3.10 二叉树后序遍历(非递归)  
 
 题目信息:   题目链接:  二叉树后续遍历 思路:二次遍历时删除,删除时插入,何时删除   
  
class  Solution  
{ 
public : 
    vector< int >  postorderTraversal ( TreeNode*  root)  
    { 
        
        vector< int >  ret; 
        stack< TreeNode* >  st; 
        TreeNode*  cur =  root; 
        TreeNode*  pre =  nullptr ; 
        while ( cur ||  ! st. empty ( ) ) 
        { 
            
            while ( cur) 
            { 
                st. push ( cur) ; 
                cur =  cur-> left; 
            } 
            
            
            TreeNode*  top =  st. top ( ) ; 
            
            if ( top-> right ==  nullptr  ||  pre ==  top-> right) 
            
            { 
                st. pop ( ) ; 
                pre =  top; 
                
                ret. push_back ( top-> val) ; 
                
            } 
            else 
            { 
                
                cur =  top-> right; 
                
                
            } 
        } 
        return  ret; 
    } 
} ;