二叉树各种遍历算法(递归以及非递归)6

如对于上图二叉树:
前序遍历:ABDECFG
中序遍历:DBEAFCG
后序遍历:DEBFGCA
深度遍历:ABDECFG
广度遍历:ABCDEFG
前序遍历:先父节点,再左右节点
递归算法:
void   inorder(treenode<T>*root){
	if(root==NULL)return;
	else{<pre name="code" class="cpp">       
          cout<<root->ele<<" ";
inorder(root->left);inorder(root->right);}}//递归后序
 
 
 
 
非递归算法: 
非递归算法一般引入堆栈,较递归算法比较复杂,分析如下:
void preorder(treenode<T>*root){
	if(root==NULL)return;
	stack<treenode<T>* >ss;
	while(root!=NULL||!ss.empty()){
		if(root!=NULL){
			cout<<root->ele<<" ";
			ss.push(root);
			root=root->left;}
		else{
			root=ss.top();
			ss.pop();
			root=root->right;}}}//前序遍历

中序遍历:先左子树再父节点再右子树
递归算法:
void   inorder(treenode<T>*root){
	if(root==NULL)return;
	else{
         inorder(root->left);
	cout<<root->ele<<" ";
	inorder(root->right);}}//递归中序
非递归:也是引入堆栈。算法分析:
void norder(treenode<T>*root){
	if(root==NULL)return;
	stack<treenode<T>*> heapin;
	while(root!=NULL||!heapin.empty()){
		if(root!=NULL){heapin.push(root);
		root=root->left;}
		else{
			root=heapin.top();
			heapin.pop();
			cout<<root->ele<<" ";
			root=root->right;}
		
}
}//中序遍历
//代码段(ii)当root为空时,说明已经到达左子树最下边,这时需要出栈了
		//进入右子树,开始新的一轮左子树遍历(这是递归的自我实现)

 
 假设,你面前有一棵二叉树,现要求你写出它的中序遍历序列。如果你对中序遍历理解透彻的话,你肯定先找到左子树的最下边的节点。那么下面的代就是理所当然的: 
中序代码段(i)
stack<treenode<T>*> s;  //STL中的栈
//一直遍历到左子树最下边,边遍历边保存根节点到栈中
while (root)
{
     s.push(root);
    root = root->lchild;
}
保存一路走过的根节点的理由是:中序遍历的需要,遍历完左子树后,需要借助根节点进入右子树。代码走到这里,指针p为空,此时无非两种情况:a 当前保存的根节点是叶子节点: b当前保存的根节点无左子树但非叶节点
对于情况b:
由于没有左孩子,根节点就是中序序列中第一个,然后直接是进入右子树:p=p->rchild;在右子树中,又会新一轮的代码段(i)、代码段(ii)……直到栈空且p空。
                        root=heapin.top();
			heapin.pop();
			cout<<root->ele<<" ";
                       root=root->right;
对于a包含叶节点,所以: a接下来的代码段(ii)这样的:
                        root=heapin.top();
                        heapin.pop();
			cout<<root->ele<<" ";
                        <pre name="code" class="cpp">                         root=heapin.top();
			heapin.pop();
			cout<<root->ele<<" ";
 
  a的代码段(ii)也可写成b的理由是:由于是叶子节点,p=-=p->rchild;之后p肯定为空。为空,还需经过新一轮的代码段(i)吗?显然不需。(因为不满足循环条件)那就直接进入代码段(ii)。 
 
所以统一一下
中序代码段(ii)
                      root=heapin.top();
			heapin.pop();
			cout<<root->ele<<" ";
                       root=root->right;
后序遍历:先左右子树再父节点,所以不同于前序和中序围绕根节点,这也决定了其算法的略有差异:
递归:
void   postorder(treenode<T>*root){
	if(root==NULL)return;
	else{
	postorder(root->left);
	postorder(root->right);
cout<<root->ele<<" ";}}//递归后序
非递归算法:后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。
void postorder(treenode<T>*root){
if(root==NULL) return;
treenode<T>*p=NULL;
stack<treenode<T>*>s;
treenode<T>*cu;
s.push(root);
while(!s.empty()){
	cu=s.top();
	if((cu->left==NULL&&cu->right==NULL)||
		(p!=NULL&&(p==cu->left||p==cu->right)))
        {
			cout<<cu->ele<<" ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过 
              s.pop();
            p=cu; 
        }
else
        {
			if(cu->right!=NULL)
				s.push(cu->right);
			if(cu->left!=NULL)    
				s.push(cu->left);
        }}
}//后序


深度遍历算法:
//深度优先遍历
void depthFirstSearch(treenode<T>*root){
    stack<treenode<T> *> nodeStack;  //使用C++的STL标准模板库
    nodeStack.push(root);
    treenode<T> *node;
    while(!nodeStack.empty()){
        node = nodeStack.top();
		cout<<node->ele<<" ";  //遍历根结点
        nodeStack.pop();
		if(node->right){
            nodeStack.push(node->right);  //先将右子树压栈
        }
		if(node->left){
            nodeStack.push(node->left);  //再将左子树压栈
        }
    }
}
广度优先算法:
void breadthFirstSearch(treenode<T>* root){
    queue<treenode<T> *> nodeQueue;  //使用C++的STL标准模板库
	nodeQueue.push(root);
    treenode<T> *node;
    while(!nodeQueue.empty()){
        node = nodeQueue.front();
        nodeQueue.pop();
		cout<<node->ele<<" ";
        if(node->left){
            nodeQueue.push(node->left);  //先将左子树入队
        }
        if(node->right){
            nodeQueue.push(node->right);  //再将右子树入队
        }
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值