zoukankan      html  css  js  c++  java
  • C++编程练习(17)----“二叉树非递归遍历的实现“

    二叉树的非递归遍历

    最近看书上说道要掌握二叉树遍历的6种编写方式,之前只用递归方式编写过,这次就用非递归方式编写试一试。

    C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)

    递归的思想也就是栈的思想,既然不用递归,那就改用栈的方式。



    “递归=栈”



    1、前序遍历

    前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。

    a)递归实现前序遍历:

    void PreOrderTraverse(BiTNode *T)	/*递归前序遍历*/
    {
    	if (T==NULL)
    		return;
    	std::cout<<T->data<<"	";
    	PreOrderTraverse(T->lchild);
    	PreOrderTraverse(T->rchild);
    }

    b)非递归实现前序遍历:

    对于根结点P:
    1)访问结点P,并将结点P入栈;
    2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
    3)直到P为NULL并且栈为空,则遍历结束。

    void nPreOrderTraverse(BiTNode *T)	/*非递归前序遍历*/
    {
    	if (T==NULL)
    		return;
    	BiTNode *p;
    	p = T;
    	std::stack<BiTNode*> stk;
    	while(p!=NULL||!stk.empty())
    	{
    		while(p!=NULL)
    		{
    			std::cout<<p->data<<"	";
    			stk.push(p);
    			p = p->lchild;
    		}
    		if(!stk.empty())
    		{
    			p = stk.top();
    			stk.pop();
    			p = p->rchild;
    		}
    	}	
    }

    2、中序遍历

    中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。

    a)递归实现中序遍历

    void InOrderTraverse(BiTNode *T)	/*递归中序遍历*/
    {
    	if (T==NULL)
    		return;
    	InOrderTraverse(T->lchild);
    	std::cout<<T->data<<"	";
    	InOrderTraverse(T->rchild);
    }

    b)非递归实现中序遍历

    对于根结点P:
    1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
    2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
    3)直到P为NULL并且栈为空则遍历结束。

    void nInOrderTraverse(BiTNode *T)	/*非递归中序遍历*/
    {
    	if(T==NULL)
    		return;
    	std::stack<BiTNode*> stk;
    	BiTNode* p;
    	p = T;
    	while(p!=NULL || !stk.empty())
    	{
    		while(p!=NULL)
    		{
    			stk.push(p);
    			p = p->lchild;
    		}
    		if(!stk.empty())
    		{
    			p = stk.top();
    			stk.pop();
    			std::cout<<p->data<<"	";
    			p = p->rchild;
    		}
    	}
    }

    3、后序遍历

    后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。

    a)递归实现后序遍历

    void PostOrderTraverse(BiTNode *T)	/*递归后序遍历*/
    {
    	if(T==NULL)
    			return;
    	PostOrderTraverse(T->lchild);
    	PostOrderTraverse(T->rchild);
    	std::cout<<T->data<<"	";
    }

    b)非递归实现后序遍历

    这里实现略复杂,当初想出来的方法过于笨重,后参考http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html,改写如下:

    要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

    对于根结点P:

    1)将P入栈,设置当前结点 cur

    2)将当前的 cur 置为栈顶结点,如果 cur 不存在左孩子和右孩子,或者 cur 存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则可以直接访问该结点并进行出栈操作。否则将 cur 的右孩子和左孩子依次入栈;

    3)直到栈为空则遍历结束。

    void nPostOrderTraverse(BiTNode *T)		/*非递归后序遍历*/
    {
    	if(T==NULL)
    		return;
    	BiTNode* cur;		/*当前结点*/
    	BiTNode* pre = NULL;		/*前一次输出的结点*/
    	std::stack<BiTNode*> stk;
    	stk.push(T);
    	while(!stk.empty())
    	{
    		cur = stk.top();
    		if((cur->lchild==NULL && cur->rchild==NULL) ||
    			(pre!=NULL && (cur->lchild==pre || cur->rchild==pre)))	
    		{								/*如果当前结点没有孩子结点或者孩子节点都已被访问过*/
    			std::cout<<cur->data<<"	";
    			stk.pop();
    			pre = cur;
    		}
    		else
    		{
    			if(cur->rchild!=NULL)
    				stk.push(cur->rchild);
    			if(cur->lchild!=NULL)
    				stk.push(cur->lchild);
    		}
    	}
    }

    4、完整测试代码

    1)BiTree.h头文件

    /* BiTree.h头文件 */
    #include<iostream>
    #include<stack>
    typedef char TElemType;
    
    class BiTNode{					/*创建结点类,使用的是左右孩子表示法*/
    public:
    	BiTNode():data(0),lchild(NULL),rchild(NULL){}
    	TElemType data;
    	BiTNode *lchild,*rchild;
    };
    
    void CreateBiTree(BiTNode **T)		/*二叉树的建立,这里形参用的是双指针,需要注意*/
    {											/*这里输入的是一个扩展二叉树,每个结点若有空指针,*/
    	TElemType ch;								/*则将其值设为一个特定值,本代码中是'#'*/
    	std::cin>>ch;
    	std::cin.clear();
    	if(ch=='#')
    		*T=NULL;
    	else
    	{
    		*T=new BiTNode;
    		if(!*T)
    			exit(1);
    		(*T)->data=ch;
    		CreateBiTree(&(*T)->lchild);
    		CreateBiTree(&(*T)->rchild);
    	}
    }
    
    void PreOrderTraverse(BiTNode *T)	/*递归前序遍历*/
    {
    	if (T==NULL)
    		return;
    	std::cout<<T->data<<"	";
    	PreOrderTraverse(T->lchild);
    	PreOrderTraverse(T->rchild);
    }
    
    void nPreOrderTraverse(BiTNode *T)	/*非递归前序遍历*/
    {
    	if (T==NULL)
    		return;
    	BiTNode *p;
    	p = T;
    	std::stack<BiTNode*> stk;
    	while(p!=NULL||!stk.empty())
    	{
    		while(p!=NULL)
    		{
    			std::cout<<p->data<<"	";
    			stk.push(p);
    			p = p->lchild;
    		}
    		if(!stk.empty())
    		{
    			p = stk.top();
    			stk.pop();
    			p = p->rchild;
    		}
    	}	
    }
    
    
    void InOrderTraverse(BiTNode *T)	/*递归中序遍历*/
    {
    	if (T==NULL)
    		return;
    	InOrderTraverse(T->lchild);
    	std::cout<<T->data<<"	";
    	InOrderTraverse(T->rchild);
    }
    
    void nInOrderTraverse(BiTNode *T)	/*非递归中序遍历*/
    {
    	if(T==NULL)
    		return;
    	std::stack<BiTNode*> stk;
    	BiTNode* p;
    	p = T;
    	while(p!=NULL || !stk.empty())
    	{
    		while(p!=NULL)
    		{
    			stk.push(p);
    			p = p->lchild;
    		}
    		if(!stk.empty())
    		{
    			p = stk.top();
    			stk.pop();
    			std::cout<<p->data<<"	";
    			p = p->rchild;
    		}
    	}
    }
    
    void PostOrderTraverse(BiTNode *T)	/*递归后序遍历*/
    {
    	if(T==NULL)
    			return;
    	PostOrderTraverse(T->lchild);
    	PostOrderTraverse(T->rchild);
    	std::cout<<T->data<<"	";
    }
    
    void nPostOrderTraverse(BiTNode *T)		/*非递归后序遍历*/
    {
    	if(T==NULL)
    		return;
    	BiTNode* cur;		/*当前结点*/
    	BiTNode* pre = NULL;		/*前一次输出的结点*/
    	std::stack<BiTNode*> stk;
    	stk.push(T);
    	while(!stk.empty())
    	{
    		cur = stk.top();
    		if((cur->lchild==NULL && cur->rchild==NULL) ||
    			(pre!=NULL && (cur->lchild==pre || cur->rchild==pre)))	
    		{								/*如果当前结点没有孩子结点或者孩子节点都已被访问过*/
    			std::cout<<cur->data<<"	";
    			stk.pop();
    			pre = cur;
    		}
    		else
    		{
    			if(cur->rchild!=NULL)
    				stk.push(cur->rchild);
    			if(cur->lchild!=NULL)
    				stk.push(cur->lchild);
    		}
    	}
    }


    2)main文件

    #include"BiTree.h"
    using namespace std;
    int main()
    {
    	BiTNode *T=new BiTNode;
    	std::cout<<"请前序遍历输入各节点:";
    	CreateBiTree(&T);
    	cout<<"
    该树的前序遍历输出为:"<<endl;
    	PreOrderTraverse(T);
    	cout<<endl;
    	nPreOrderTraverse(T);
    	cout<<"
    该树的中序遍历输出为:"<<endl;
    	InOrderTraverse(T);
    	cout<<endl;
    	nInOrderTraverse(T);
    	cout<<"
    该树的后序遍历输出为:"<<endl;
    	PostOrderTraverse(T);
    	cout<<endl;
    	nPostOrderTraverse(T);
    	cout<<endl;
    	return 0;
    }

    5、测试结果



  • 相关阅读:
    【Docker】 CentOS7 安装 Docker 及其使用方法 ( 一 )
    js加密解密
    JSON.parse和eval()的区别
    复选框(全选/全不选/反选)
    圆形进度条
    C# JToken类,实现解析动态json数据、遍历、查找
    使IIS服务器支持下载 apk/ipa 安装包
    Python关键字
    C#泛型(二)泛型类
    C#泛型(一)泛型方法
  • 原文地址:https://www.cnblogs.com/fengty90/p/3768831.html
Copyright © 2011-2022 走看看