author:
- luixiao1223
title: 非递归和堆栈遍历二叉树
前导知识
我们都知道遍历二叉树的方法是用递归,也可以用stack来模拟递归。那么下面我们来看看如何实现二叉树的三中基本遍历方法。
中序
递归方法
Inorder_traverse(p)
if p == NULL
return
Inorder_traverse(p.left)
print(p.value)
Inorder_traverse(p.left)
stack方法
由于stack方法明显要难于递归方法,所以这里我给出了c++的实现代码片段。
stack<node *> s;
node* p = root;
while(p!=NULL || !s.empty()){
while(p!=NULL){
s.push(p);
p=p->left;
}
if (!s.empty()){
p=s.top();
cout<<p->value<<" ";
s.pop();
p=p->right;
}
}
cout<<endl;
前序
递归方法
Inorder_traverse(p)
if p == NULL
return
print(p.value)
Inorder_traverse(p.left)
Inorder_traverse(p.left)
stack方法
由于stack方法明显要难于递归方法,所以这里我给出了c++的实现代码片段。
stack<node *> s;
s.push(root);
while(!(s.empty())){
node* current = s.top();
s.pop();
cout<<current->value<<" ";
if (current->right){
s.push(current->right);
}
if (current->left)
s.push(current->left);
}
后序
递归方法
Inorder_traverse(p)
if p == NULL
return
Inorder_traverse(p.left)
Inorder_traverse(p.left)
print(p.value)
stack方法
这个方法比较难于理解,不过我稍微再后面讲到无stack无递归实现遍历的算法里面讲解这个方法。
stack<node*> s;
node* cursor= root;
s.push(cursor);
cursor=cursor->left;
node* p=NULL;
while(!s.empty()){
while(cursor!=NULL){
s.push(cursor);
cursor = cursor->left;
p=NULL;
}
while(!s.empty()){
cursor = s.top();
if (p==cursor->left && cursor->right == NULL){
cout<<cursor->value<<" "<<std::flush;
s.pop();
p=cursor;
}else if(p==cursor->left){
cursor = cursor->right;
break;
}else if(p==cursor->right){
cout<<cursor->value<<" "<<std::flush;
p=cursor;
s.pop();
}
}
}
cout<<endl;
问题
我们看到二叉树的递归实现和stack方法实现。现在来看一个更难的实现。这个实现不适用递归也不实用stack而且额外分配的空间数量维持再常数(constant)级别。当然这个算法也比前面的所有算法复杂。
思路和实现
前面实现后续遍历的时候,我其实利用了一些思路来自于无stack和无递归的遍历实现。
其实无stack和无递归的实现,主要使用的是记录回溯的前导指针是目前指针的左孩子还是右孩子。
前序遍历
- 首先访问根节点
- 然后访一直访问左孩子,直到没有左孩子的节点。并设置prev指针为NULL,current指针为当前最后一个左孩子。
- 如果prev指针为当前节点的左孩子,判断current指针是否有右孩子。
- 如果没有设置prev为当前指针,current=current->parent
- 如果有访问右孩子,并设置current为右孩子。回到步骤2
- 如果prev指针为当前节点的右孩子。则直接设置prev=current,并current=current->parent。然后执行3.
这个过程中并没有使用堆栈,也不是递归,只有循环。
实现代码
node* cursor = root;
node* prev = NULL;
if (cursor != NULL){
cout<<cursor->value<<" "<<std::flush;
}
while(cursor!=NULL){
while(cursor->left && prev == cursor->parent){
prev = cursor;
cursor = cursor->left;
if (cursor!=NULL){
cout<<cursor->value<<" "<<flush;
}
}
if (prev == cursor->left && cursor->right == NULL){
prev = cursor;
cursor = cursor->parent;
}else if(prev == cursor->left){
prev = cursor;
cout<<cursor->right->value<<" "<<flush;
cursor = cursor->right;
}else{
prev = cursor;
cursor = cursor->parent;
}
}
cout<<endl;
中序遍历
- 从根节往左孩子移动,移动到最左边的一个左孩子。设置prev=NULL,current为当前节点。
- 如果prev指针为当前节点的左孩子,访问当前current节点,判断current指针是否有右孩子。
- 如果没有设置prev为当前指针,current=current->parent
- 如果有,并设置current为右孩子。回到步骤1
- 如果prev指针为当前节点的右孩子。则直接设置prev=current,并current=current->parent。然后执行2.
这个过程中并没有使用堆栈,也不是递归,只有循环。
实现代码
node* cursor = root;
node* prev = NULL;
while(cursor!=NULL){
while(cursor && prev == cursor->parent){
prev = cursor;
cursor = cursor->left;
}
if (cursor == NULL){
cursor = prev;
prev = NULL;
}
if (prev == cursor->left && cursor->right == NULL){
cout<<cursor->value<<" "<<flush;
prev = cursor;
cursor = cursor->parent;
}else if(prev == cursor->left){
cout<<cursor->value<<" "<<flush;
prev = cursor;
cursor = cursor->right;
}else{
prev = cursor;
cursor = cursor->parent;
}
}
cout<<endl;
后序遍历
- 从根节往左孩子移动,移动到最左边的一个左孩子。设置prev=NULL,current为当前节点。
- 如果prev指针为当前节点的左孩子,判断current指针是否有右孩子。
- 访问当前current节点,如果没有设置prev为当前指针,current=current->parent
- 如果有,并设置current为右孩子。回到步骤1
- 如果prev指针为当前节点的右孩子。访问当前current节点,设置prev=current,并current=current->parent。然后执行2.
这个过程中并没有使用堆栈,也不是递归,只有循环。
node* cursor = root;
node* prev = NULL;
while(cursor!=NULL){
while(cursor && prev == cursor->parent){
prev = cursor;
cursor = cursor->left;
}
if (cursor == NULL){
cursor = prev;
prev = NULL;
}
if (prev == cursor->left && cursor->right == NULL){
cout<<cursor->value<<" "<<flush;
prev = cursor;
cursor = cursor->parent;
}else if(prev == cursor->left){
prev = cursor;
cursor = cursor->right;
}else{
cout<<cursor->value<<" "<<flush;
prev = cursor;
cursor = cursor->parent;
}
}
cout<<endl;