二叉树、树和森林的遍历和转换

本文详细介绍了二叉树、树和森林的遍历方法,包括二叉树的先序、中序、后序和层次遍历,以及树的先根和后根遍历。同时阐述了森林的先序和中序遍历,并讨论了它们的时间复杂度和空间复杂度。此外,还探讨了二叉树、树与森林之间的转换规则,通过特定的对应关系,可以实现它们之间的相互转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 遍历

(1)二叉树的遍历

遍历方式:先序、中序、后序和层次(熟记:三个递归算法+三个非递归算法+层次遍历算法)


时间复杂度:遍历二叉树的算法中的基本操作都是访问节点,且不论按哪一种次序进行遍历,对含有n个结点的二叉树,其时间复杂度为O(n)。

空间复杂度:为遍历过程中栈的最大容量,即树的深度,最坏情况下为n,则空间复杂度为O(n)。


(2)树的遍历:

树有两种次序遍历方法:先根次序遍历树和后根次序遍历树。


当树采用二叉链表作为存储结构时,树的先根后根遍历可借用二叉树的先序遍历和中序遍历实现。


(3)森林的两种遍历算法:




森林的先序和中序遍历对应于二叉树的二叉树的先序和中序遍历。


二叉树、树与森林间的转换

(1)二叉树与树的转换:


由于二叉树与树都可用二叉链表作为存储结构,则以二叉链表作为媒介可导出树与二叉树之间的一个对应关系。也就是说给定一棵树,可以找到唯一的一棵二叉树与之对应。

如下图:



(2)二叉树与森林的转换:


任何一棵树对应的二叉树的根节点的右子树必空。若把第二棵树的根节点看成是第一棵树的根节点的兄弟,则同样可导出森林与二叉树的对应关系。

如下如:


三 二叉树遍历代码:

#include<iostream>
#include<queue>
#include<stack>
#include<set>
using namespace std;
struct BTNode
{
	int data;
	BTNode *left,*right;
	bool visit;
};
/*先序创建二叉树*/
void create_binary(BTNode *&root)
{
	int data;
	cin>>data;
	if(data==0)
		return;
	if((root=(struct BTNode*)malloc(sizeof(BTNode)))==NULL)
		return;
	root->data=data;
	root->visit=false;
	root->left=root->right=NULL;
	create_binary(root->left);
	create_binary(root->right);
}

/*递归遍历*/
void PreOrderTraverse(BTNode *root)
{
	if(root==NULL)return;
	else
	{
		cout<<root->data<<endl;
		PreOrderTraverse(root->left);
		PreOrderTraverse(root->right);
	}
}
void InOrderTraverse(BTNode *root)
{
	if(root==NULL)
		return;
	else
	{
		InOrderTraverse(root->left);
		cout<<root->data<<endl;
		InOrderTraverse(root->right);
	}
}
void PostOrderTraverse(BTNode *root)
{
	if(root==NULL)
		return;
	else
	{
		PostOrderTraverse(root->left);
		PostOrderTraverse(root->right);
		cout<<root->data<<endl;
	}
}

void LevelTraverse(BTNode*root)
{
	if(root==NULL)return;
	queue<BTNode*>que;
	que.push(root);
	while(!que.empty())
	{
		BTNode *ptr=que.front();
		cout<<ptr->data<<endl;
		que.pop();
		if(ptr->left)que.push(ptr->left);
		if(ptr->right)que.push(ptr->right);
	}
}

/*非递归遍历:前序容易,其余麻烦*/
void PreOrderTraverse1(BTNode *root)
{
	if(root==NULL)return;
	stack<BTNode *>stk;
	stk.push(root);
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();stk.pop();
		cout<<ptr->data<<endl;
		if(ptr->right)stk.push(ptr->right);
		if(ptr->left)stk.push(ptr->left);
	}
}
/*注意*/
void InOrderTraverse1(BTNode *root)
{
	/*数据结构写法,优先选择、
	if(root==NULL)return;
	stack<BTNode*> stk;
	stk.push(root);
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();
		while(ptr){stk.push(ptr->left);ptr=ptr->left;}
		stk.pop();
		if(!stk.empty())
		{
			ptr=stk.top();
			cout<<ptr->data<<endl;
			stk.pop();
			stk.push(ptr->right);
		}
	}

	*/
	//加标记法:在节点添加成员,或者利用set存储加入stack的节点,然后每次加入的时候进行判断。
	//(简单,但效率不高,脑子不转时用)
	/*if(root==NULL)return;
	stack<BTNode*>stk;stk.push(root);
	root->visit=true;//visit代表有没有进过栈。
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();
		while(ptr->left&&!ptr->left->visit){stk.push(ptr->left);ptr->left->visit=true;ptr=ptr->left;}
		if(!stk.empty())
		{
			ptr=stk.top();
			cout<<ptr->data<<endl;
			stk.pop();
			if(ptr->right)stk.push(ptr->right);
		}
	}*/


	/*这个方法可行,但是是一次性的,因为破坏了二叉树的结构,不要用。
	if(root==NULL)return;
	stack<BTNode*>stk;stk.push(root);
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();
		while(ptr->left){stk.push(ptr->left);ptr->left=NULL;ptr=stk.top();}
		if(!stk.empty())
		{
			ptr=stk.top();
			cout<<ptr->data<<endl;
			stk.pop();
			if(ptr->right)stk.push(ptr->right);
		}
	}
	*/
}

void PostOrderTraverse1(BTNode *root)
{
	/*某人做法:比较好*/
	/*
	stack<BTNode*> s;
    BTNode *cur;                      //当前结点 
    BTNode *pre=NULL;                 //前一次访问的结点 
    s.push(root);
    while(!s.empty())
    {
        cur=s.top();
        if((cur->left==NULL&&cur->right==NULL)||
           (pre!=NULL&&(pre==cur->left||pre==cur->right)))
        {
            cout<<cur->data<<endl;  //如果当前结点没有孩子结点或者孩子节点都已被访问过 
              s.pop();
            pre=cur; 
        }
        else
        {
            if(cur->right!=NULL)
                s.push(cur->right);
            if(cur->left!=NULL)    
                s.push(cur->left);
        }
    }*/

	//利用辅助存储标记节点是否进过栈。(简单,但效率不高,脑子不转时用)
	/*if(root==NULL)return;
	stack<BTNode*>stk;stk.push(root);
	root->visit=true;
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();
		while(ptr->left&&!ptr->left->visit){stk.push(ptr->left);ptr->left->visit=true;ptr=ptr->left;}
		if(!stk.empty())
		{
			ptr=stk.top();
			if(ptr->right&&!ptr->right->visit)
			{
				stk.push(ptr->right);
				ptr->right->visit=true;
			}
			else
			{cout<<ptr->data<<endl;stk.pop();}
		}
	}*/

	//利用辅助存储标记节点是否进过栈。(简单,但效率不高,脑子不转时用)
	/*if(root==NULL)return;
	stack<BTNode*>stk;stk.push(root);
	set<BTNode*>node_set;
	node_set.insert(root);
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();
		while(ptr->left&&!node_set.count(ptr->left)){stk.push(ptr->left);node_set.insert(ptr->left);ptr=ptr->left;}
		if(!stk.empty())
		{
			ptr=stk.top();
			if(ptr->right&&!node_set.count(ptr->right))
			{
				stk.push(ptr->right);
				node_set.insert(ptr->right);
			}
			else
			{cout<<ptr->data<<endl;stk.pop();}
		}
	}*/
	
	
	
	/*一次性算法,不要用,仅作参考。
	if(root==NULL)return;
	stack<BTNode*> stk;
	stk.push(root);
	while(!stk.empty())
	{
		BTNode *ptr=stk.top();
		while(ptr->left){stk.push(ptr->left);ptr->left=NULL;ptr=stk.top();}
		if(!stk.empty())
		{
			ptr=stk.top();
			if(ptr->right==NULL){cout<<ptr->data<<endl;stk.pop();}
			else{stk.push(ptr->right);ptr->right=NULL;}
		}
	}*/

}

int main()
{
BTNode *root;
create_binary(root);
cout<<"递归:"<<endl;
cout<<"先序:"<<endl;
PreOrderTraverse(root);
cout<<"中序:"<<endl;
InOrderTraverse(root);
cout<<"后序:"<<endl;
PostOrderTraverse(root);
cout<<"层次"<<endl;
LevelTraverse(root);
cout<<"非递归:"<<endl;
cout<<"先序:"<<endl;
PreOrderTraverse1(root);
cout<<"中序:"<<endl;
InOrderTraverse1(root);
cout<<"后序:"<<endl;
PostOrderTraverse1(root);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值