二叉树的遍历(基于栈的非递归方式实现)

原文链接:二叉树的遍历(基于栈的非递归方式实现)

二叉树的遍历(基于栈的非递归方式实现)

在写二叉树的时候如果用递归实现二叉树的遍历很简单,但是用非递归来实现二叉树的遍历就不那么简单了需要一些技巧。

那为什么还要非递归实现呢?个人理解:如果树的高度很大,超过了允许递归的次数,那么就会出错,比如我记得python只允许递归100次(不知道记错没)

这时候用迭代就要保险的多,不会出错。

下面先来做基本的准备说明:

复制代码

 1 #include<iostream>
 2 #include<stack>
 3 
 4 #define null NULL
 5 
 6 template<typename Entry>
 7 class binary_node
 8 {
 9     public:
10         friend class binary_tree;
11         Entry data;
12         binary_node* lchild;
13         binary_node* rchild;
14         binary_node():lchild(null),rchild(null){}
15         ~binary_node(){}
16 };
17 
18 template<typename Entry>
19 class binary_tree
20 {
21     binary_node* root;
22     
23     public:
24         binary_tree():root(null){}
25         ~binary_tree(){}
26         void preordertraversal(binary_node*,void (*visit)(Entry& bt));
27         void ineordertraversal(binary_node*,void (*visit)(Entry& bt));
28         void posteordertraversal(binary_node*,void (*visit)(Entry& bt));
29         
30 };

复制代码

先来看看前序遍历:

复制代码

 1 //递归实现先序遍历
 2 template <typename Entry>
 3 void binary_tree<Entry>::preordertraversal(binary_node* root,void (*visit)(Entry& bt))
 4 {
 5     if(root != null)
 6     {
 7         visit(root->data);
 8         preorder(root->lchild,visit);
 9         preorder(root->rchild,visit);
10     }
11 }

复制代码

栈实现前序遍历较简单,由于每次先输出根节点,再输出左节点随后是右节点。

算法是:

1、若栈非空输出根节点,并出栈
2、将右节点压栈(如果存在)
3、将左节点压栈(如果存在)
4、重复第1步直到栈空
注意:之所以先压右节点是考虑了栈的特性,这样在迭代过程中可以先拿到左节点处理。(栈的先入后出)

复制代码

 1 template <typename Entry>
 2 void binary_tree<Entry>::preordertraversal(binary_node* root,void (*visit)(Entry& bt))
 3 {
 4     if(root == null) return;
 5     binary_node* cur = root;
 6     stack<binary_node*> s;
 7     s.push(cur);
 8     while(!s.empty())
 9     {
10         cur = s.top();
11         visit(cur->data);
12         s.pop();
13         if(cur->rchild != null) s.push(cur->rchild);
14         if(cur->lchild != null) s.push(cur->lchild);
15     }
16 }

复制代码

再来看看中序遍历:

复制代码

 1 //递归实现的中序遍历
 2 template <typename Entry>
 3 void binary_tree<Entry>::inordertraversal(binary_node* root,void (*visit)(Entry& bt))
 4 {
 5     if(root != null)
 6     {
 7         preorder(root->lchild,visit);
 8         visit(root->data);
 9         preorder(root->rchild,visit);
10     }
11 }

复制代码

栈的中序遍历需要套两层循环,由于需要先输出左节点,因此必须向下查找直到左节点为空才能输出。处理逻辑如下:

1、如果栈顶元素非空且左节点存在,将其入栈,重复该过程。若不存在则进入第2步
2、若栈非空,输出栈顶元素并出栈。判断刚出栈的元素的右节点是否存在,不存在重复第2步,存在则将右节点入栈,跳至第1步

复制代码

 1 template <typename Entry>
 2 void binary_tree<Entry>::inordertraversal(binary_node* root,void (*visit)(Entry& bt))
 3 {
 4     if(root == null) return;
 5     binary_node* cur = root;
 6     stack<binary_node*> s;
 7     s.push(cur);
 8     while(!s.empty())
 9     {
10         while(s.top()->lchild!=null)
11             s.push(s.top()->lchild);
12         while(!s.empty())
13         {
14             binary_node* cur = s.top();
15             visit(cur->data);
16             s.pop();
17             if(cur->rchild != null)
18             {
19                 s.push(cur->rchild);
20                 break;
21             }
22         }
23     
24     }
25     
26 }

复制代码

再来看看后序遍历:

复制代码

 1 //递归实现的后序遍历
 2 template <typename Entry>
 3 void binary_tree<Entry>::postordertraversal(binary_node* root,void (*visit)(Entry& bt))
 4 {
 5     if(root != null)
 6     {
 7         preorder(root->lchild,visit);
 8         preorder(root->rchild,visit);
 9         visit(root->data);
10     }
11 }

复制代码

后序遍历在中序的双层循环的基础上需要加入一个记录,专门记录上一次出栈的节点。步骤如下:

1、如果栈顶元素非空且左节点存在,将其入栈,重复该过程。若不存在则进入第2步(该过程和中序遍历一致)
2、判断上一次出栈节点是否当前节点的右节点,或者当前节点是否存在右节点,满足任一条件,将当前节点输出,并出栈。否则将右节点压栈。跳至第1步

复制代码

 1 template <typename Entry>
 2 void binary_tree<Entry>::postordertraversal(binary_node* root,void (*visit)(Entry& bt))
 3 {
 4     if(root == null) return;
 5     stack<binary_node*> s;
 6     s.push(root);
 7     binary_node* lastpop = null;
 8     while(!s.empty())
 9     {
10         while(s.top()->lchild != null)
11             s.push(s.top()->lchild);
12         while(!s.empty())
13         {
14             if(lastpop == s.top()->rchild || s.top()->rchild == null)
15             {
16                 visit(s.top()->data);
17                 lastpop = s.top();
18                 s.pop();
19             }
20             else if(s.top()->rchild != null)
21             {
22                 s.push(s.top()->rchild);
23                 break;
24             }
25         }
26     }
27 }

复制代码

if(lastpop == s.top()->rchild || s.top()->rchild == null)
是判断上次弹出的结点是不是当前结点的右结点,或者当前节点没有右结点,因为访问次序是“左-右-中”。

而二叉树的层次遍历可以通过队列来实现:

 1 //用队列来实现二叉树的层次遍历
 2 template <typename Entry>
 3 void binary_tree<Entry>::leveltraversal(binary_node* root,void (*visit)(Entry& bt))
 4 {
 5     if(root == null) return;
 6     queue<binary_node*> q;
 7     q.push(root);
 8     while(!q.empty())
 9     {
10         visit(q.front());
11         if(q.front()->lchild != null)
12             q.push(q.front()->lchild);
13         if(q.front()->rchild != null)
14             q.push(q.front()->rchild);
15         q.pop();
16     }
17 }

整个程序完全源代码如下:

#include<iostream>
#include<queue>
#include<stack>
using namespace std;
 
struct btnode{
	int value;
	btnode *left;
	btnode *right;
};

void create(btnode *&root,int arr[],int length);
void addBTNode(btnode *&myBT,int val);

void preshow(btnode *root);//前序遍历 
void inordershow(btnode *root);//中序遍历 
void postshow(btnode *root);//后序遍历 
 
int main(){
	
	btnode *myBT = nullptr;

	int arr[] = {12,2,15,1,3,18,16};
	create(myBT,arr,sizeof(arr)/sizeof(int));
	
	preshow(myBT);
	cout<<endl;
	
	inordershow(myBT);
	cout<<endl;
	
	postshow(myBT);
	cout<<endl;
	
	return 0;
}

void create(btnode *&root,int arr[],int length){
	for(int i=0;i<length;i++)
		addBTNode(root,arr[i]);
}
 
 
void addBTNode(btnode *&myBT,int val){
	if(myBT == nullptr){
		myBT = new btnode();
		myBT->value = val;
		myBT->left = nullptr;
		myBT->right = nullptr;
		return;	
	}
	if(val == myBT->value){
		return;
	}
	else if(val < myBT->value){
		addBTNode(myBT->left,val);
	}
	else{
		addBTNode(myBT->right,val);
	}			
}

void preshow(btnode *root){//前序遍历 
	if(root == nullptr)return;
	stack<btnode*> s;
	s.push(root);
	btnode *cur;
	while(!s.empty()){
		cur = s.top();
		cout<<s.top()->value<<" ";
		s.pop();
		if(cur->right != nullptr)
			s.push(cur->right);
		if(cur->left != nullptr)//注意都是if 
			s.push(cur->left);
	}
}

void inordershow(btnode *root){//中序遍历 
	if(root == nullptr)return;
	stack<btnode*> s;
	s.push(root);
	btnode *cur;
	while(!s.empty()){
		while(s.top()->left != nullptr)
			s.push(s.top()->left);
		while(!s.empty()){
			cur = s.top();
			cout<<s.top()->value<<" ";
			s.pop();
			if(cur->right != nullptr){
				s.push(cur->right);
				break;
			}
		}
	}
}

void postshow(btnode *root){//后序遍历 
	if(root == nullptr)return;
	stack<btnode*> s;
	s.push(root);
	btnode *lastnode;
	while(!s.empty()){
		while(s.top()->left != nullptr)
			s.push(s.top()->left);
		while(!s.empty()){
			if(s.top()->right == nullptr || lastnode == s.top()->right){
				lastnode = s.top();
				cout<<s.top()->value<<" ";
				s.pop();
			}
			else if(s.top()->right != nullptr){//注意这里要是else if !!!
				s.push(s.top()->right);
				break;
			}
		}
	}
}
 

程序运行结果如下:

猜你喜欢

转载自blog.csdn.net/qq_29762941/article/details/82703530