这里着重讲解一下非递归不用栈遍历二叉树:
无论先序,中序还是后序遍历,都是这种记录线索进行遍历的思想.不过后序有一点不同,后序是先输出左子树,然后右子树,最后是根.这里我们使用了一种小技巧.我们还是先看图:
我们先回忆一下递归遍历二叉树.在递归遍历二叉树的时候,我们使用系统栈做临时存储空间,记录节点的后继节点以便下一次查找.所以递归遍历所用的系统栈空间为O(h),h为二叉树的深度.一般情况下二叉树深度为lg(n),即二叉树遍历的空间复杂度为O(lg(n)),当二叉树的深度退化为n时候,即二叉树退化为链表时候,空间复杂度猛增为O(n).
如果不用系统栈做临时存储空间,那么就一定要想一个办法,可以找到节点的后继节点,以便后续的查找.在使用自定义的栈时候就是这种思想.我们使用自定义的栈做临时存储空间,所以空间复杂度为O(h),同上,这里不再详细讲述.
如果我们不想用栈呢,我们就一定要找到一种方法可以索引到每一个节点的后继节点.这里我们使用一种类似于线索二叉树中用到的方法,即使用指向子节点的指针为空的节点做线索,记录我们要遍历的后继节点,以便后续使用,当我们使用完成后,再把该节点重新置为空.
这里我们要实现的是怎么才能把
指向子节点的指针为空的节点作为线索,我来画一张图,这样就更清晰了.
第一次找到节点2,节点2的特点是右子树为空,所以记录2的后继节点为1,即把2的m_pright指向1.
然后设置7的右子树为2.
恢复7的右子树:
好了,我们总结一下规律,每次遍历到一个节点pRoot时候,我们总是首先找到这样一个节点prev:
prev = pRoot -> m_pLeft;
while ( prev -> m_pRight && prev ->m_pRight != pRoot ){
prev = prev -> m_pRight;
}
然后设置该节点的左子树为pRoot,这样我们就把线索记住了.
当使用完后,我们还要把线索删除.
我们再次遍历到该节点时候,如下列代码,我们检测是不是第二次遍历到该节点,因为我们第一次遍历到该节点是设置线索,即if里面执行的语句,我们第二次遍历该节点时候是取消线索,即else里面执行的语句.
if ( !prev -> m_pRight ){
prev ->m_pRight = pRoot;
pRoot = pRoot -> m_pLeft;
} else {
cout <<pRoot -> m_value<< " " ;
prev ->m_pRight = NULL;
pRoot = pRoot -> m_pRight;
}
无论先序,中序还是后序遍历,都是这种记录线索进行遍历的思想.不过后序有一点不同,后序是先输出左子树,然后右子树,最后是根.这里我们使用了一种小技巧.我们还是先看图:
对于这样一棵二叉树,后序遍历先输出9->11,4->12->13,6,2.....
大家注意到没,对于一棵二叉树的某一个左子树来说我们总是这样输出:
先输出9,
再输出11,14
再输出12,
再输出13,6,2
现在总结一下后序遍历的输出:
1.如果该节点左子树为空,直接输出,
2.如果第二次遍历到线索节点(第一次是设置线索,第二次是取消线索,这里的11,13都是线索节点),则倒着输出,例如输出 11,4 13,6,2 等等,具体可以看代码,很好懂的.
#include <iostream>
#include <stack>
using namespace std;
//二叉树的结构:
struct BST_node {
int m_value;
BST_node * m_pLeft ;
BST_node * m_pRight ;
};
struct flage_BST_node {
BST_node * p ;
bool flage;
};
//利用先序和中序构造二叉树
BST_node * build_BST_core ( const int * startpre, const int * endpre,
const int * startmid, const int * endmid)
{
if ( startpre> endpre || startmid > endmid ){
return NULL ;
}
BST_node * root = new BST_node;
root-> m_value = *startpre ;
root-> m_pLeft = root -> m_pRight = NULL ;
const int * pRootPos = startmid ;
while ( pRootPos <= endmid && * pRootPos!=* startpre ){
++ pRootPos ;
}
int leftLength = pRootPos -startmid ;
if ( pRootPos<= endmid && pRootPos > startmid ){
root ->m_pLeft = build_BST_core( startpre +1,startpre + leftLength, startmid ,pRootPos -1);
}
if ( pRootPos < endmid ){
root ->m_pRight = build_BST_core( startpre +leftLength +1, endpre, pRootPos +1,endmid );
}
return root ;
}
//利用先序和中序构造二叉树
BST_node * build_BST ( int * preorder, int *midorder , const int nSize)
{
if ( ! preorder || ! midorder || nSize <=0){
return NULL ;
}
return build_BST_core (preorder , preorder+ nSize -1,
midorder ,midorder + nSize-1);
}
//中序递归遍历二叉树
void print_preorder_reserve ( BST_node * pRoot )
{
if ( pRoot ){
cout <<pRoot -> m_value<< " " ;
print_preorder_reserve (pRoot -> m_pLeft);
print_preorder_reserve (pRoot -> m_pRight);
}
}
//非递归使用栈中序遍历二叉树
void print_preorder_noreserve ( BST_node* pRoot )
{
if ( pRoot ){
stack <BST_node *> s;
do {
while ( pRoot ){
cout <<pRoot -> m_value<< " " ;
s .push ( pRoot);
pRoot = pRoot -> m_pLeft;
}
pRoot = s . top();
s .pop ();
pRoot = pRoot -> m_pRight;
} while ( pRoot || ! s. empty() );
cout <<endl ;
}
}
//非递归不用栈中序遍历二叉树
void print_preorder_nostack ( BST_node * pRoot )
{
BST_node * prev = NULL ;
while ( pRoot ){
if ( !pRoot -> m_pLeft ){
cout <<pRoot -> m_value<< " " ;
pRoot = pRoot -> m_pRight;
} else {
prev = pRoot -> m_pLeft;
while ( prev -> m_pRight && prev ->m_pRight != pRoot ){
prev = prev -> m_pRight;
}
if ( !prev -> m_pRight ){
cout <<pRoot -> m_value<< " " ;
prev ->m_pRight = pRoot;
pRoot = pRoot -> m_pLeft;
} else {
prev ->m_pRight = NULL;
pRoot = pRoot -> m_pRight;
}
}
}
cout<< endl ;
}
void print_inorder_reserve ( BST_node * pRoot )
{
if ( pRoot ){
print_preorder_reserve (pRoot -> m_pLeft);
cout <<pRoot -> m_value<< " " ;
print_preorder_reserve (pRoot -> m_pRight);
}
}
void print_inorder_noreserve ( BST_node * pRoot )
{
if ( pRoot ){
stack <BST_node *> s;
do {
while ( pRoot ){
s .push ( pRoot);
pRoot = pRoot -> m_pLeft;
}
pRoot = s . top();
s .pop ();
cout <<pRoot -> m_value<< " " ;
pRoot = pRoot -> m_pRight;
} while ( !s . empty() || pRoot );
cout <<endl ;
}
}
void print_inorder_nostack ( BST_node * pRoot )
{
BST_node * prev ;
while ( pRoot ){
if ( !pRoot -> m_pLeft ){
cout <<pRoot -> m_value<< " " ;
pRoot = pRoot -> m_pRight;
} else {
prev = pRoot -> m_pLeft;
while ( prev -> m_pRight && prev ->m_pRight != pRoot ){
prev = prev -> m_pRight;
}
if ( !prev -> m_pRight ){
prev ->m_pRight = pRoot;
pRoot = pRoot -> m_pLeft;
} else {
cout <<pRoot -> m_value<< " " ;
prev ->m_pRight = NULL;
pRoot = pRoot -> m_pRight;
}
}
}
cout<< endl ;
}
void print_postorder_reserve ( BST_node * pRoot )
{
if ( pRoot ){
print_postorder_reserve (pRoot -> m_pLeft);
print_postorder_reserve (pRoot -> m_pRight);
cout <<pRoot -> m_value<< " " ;
}
}
void print_postorder_noreserve ( BST_node * pRoot )
{
if ( pRoot ){
stack <flage_BST_node > s;
flage_BST_node node ;
do {
while ( pRoot ){
node .flage = false;
node .p = pRoot;
s .push ( node);
pRoot = pRoot -> m_pLeft;
}
node = s . top();
s .pop ();
if ( node . flage ){
cout <<node . p-> m_value<< " " ;
} else {
node .flage = true;
s .push ( node);
pRoot = node . p-> m_pRight;
}
} while ( pRoot || ! s. empty() );
cout <<endl ;
}
}
void print_postorder_nostack_print ( BST_node * pRoot )
{
if ( pRoot ){
print_postorder_nostack_print (pRoot -> m_pRight);
cout <<pRoot -> m_value<< " " ;
}
}
void print_postorder_nostack ( BST_node* pRoot )
{
BST_node * prev ;
BST_node * pRoot_temp = pRoot ;
while ( pRoot ){
if ( !pRoot -> m_pLeft ){
pRoot = pRoot -> m_pRight;
} else {
prev = pRoot -> m_pLeft;
while ( prev -> m_pRight && prev ->m_pRight != pRoot){
prev = prev -> m_pRight;
}
if ( !prev -> m_pRight ){
prev ->m_pRight = pRoot;
pRoot = pRoot -> m_pLeft;
} else {
prev ->m_pRight = NULL;
print_postorder_nostack_print (pRoot -> m_pLeft);
pRoot = pRoot -> m_pRight;
}
}
}
print_postorder_nostack_print( pRoot_temp );
cout<< endl ;
}
int main ()
{
int pre[]={1,2,4,7,3,5,6,8};
int mid[]={4,7,2,1,5,3,8,6};
BST_node* pRoot = build_BST ( pre, mid,8);
// print_preorder_reserve(pRoot);
// cout<<endl;
// print_preorder_noreserve(pRoot);
// print_preorder_nostack(pRoot);
/* print_inorder_reserve(pRoot);
cout<<endl;
print_inorder_noreserve(pRoot);
print_inorder_nostack(pRoot);*/
//print_postorder_noreserve(pRoot);
print_postorder_reserve( pRoot );
cout<< endl ;
print_postorder_nostack( pRoot );
}