树的前序遍历和后序遍历

非二叉树的前后序遍历

采用按层次序来建立树的孩子兄弟表示法(一个指针指向第一个孩子,一个指针指向第一个右兄弟)存储结构,实现前序和后序遍历树的操作,并编写算法求树的深度。输出的参考样张如下所示。
参考样例
PS:①这个样例没有显示深度,此样例深度为4
②样例输入采用层次序输入结点对的方式。

思路
①首先要明确,此树并非是二叉树,一个结点可能有多个兄弟节点,因此不管是遍历还是深度的计算都要包括所有的兄弟节点。
②前序遍历:根节点->前序遍历左子树->前序遍历右子树
后序遍历:后序遍历左子树->后序遍历右子树->根节点。
③由①可得,最简单的方式是采用递归的方法对树进行遍历,前序和后序唯一不同的是访问父亲结点的顺序不用。
④深度的计算同样采用递归的方法,与二叉树的深度计算不同的是,比较的是本结点深度与兄弟结点的深度哪一个更大,而不是左右子树的深度哪一个更大。

1、准备

#include <iostream>
#include<algorithm>
using namespace std;

#define max(a,b)    (((a) > (b)) ? (a) : (b))

const int Max = 20;  // 假定树最多有20个结点
struct TNode
{
	char data;	// 假定树的元素类型为char型
	TNode *firstchild, *rightsib;
};

class Tree
{
public:
	Tree( );
	~Tree( ){Release(root);}          //析构函数,释放各结点的存储空间
	void PreOrder( ){PreOrder(root);}
	void PostOrder( ){PostOrder(root);}
	int Depth(){return Depth(root);};
private:
	TNode *root;
	void PreOrder(TNode *bt);
	void PostOrder(TNode *bt);
	void Release(TNode *bt);  // 析构函数的调用
	int Depth(TNode *bt);
};

Tree::Tree( )
{
	TNode *Q[Max] = {NULL}; // TNode型的数组指针
	char ch1 = '#', ch2 = '#';
	int front = -1, rear = -1;
	TNode *p = NULL, *q = NULL;
	
	cout<<"请输入根结点:";
	cin>>ch1;
	p = new TNode; p->data = ch1; 
	p->firstchild = p->rightsib = NULL;
	root = p;								// 建立根结点
	Q[++rear] = p;							// 根结点入队
    
	cout<<"请输入结点对,以空格分隔:";
	fflush(stdin);						        // 清空键盘缓冲区
    ch1 = getchar(); getchar(); ch2 = getchar();// 中间getchar注释掉中间的空格,ch1是父结点,ch2是孩子结点
	while (ch1 != '#' || ch2 != '#')			// 输入结束的条件是有序对(# #)
	{
		p = new TNode; p->data = ch2; 
		p->firstchild = p->rightsib = NULL;
		Q[++rear] = p;			// 入队
		while (front != rear)   // 当队列非空
		{
			q = Q[front + 1];	// 取队头元素,存储为q
			if (q->data != ch1)	// 当队头元素不是有序对的第一个字符
				front++;		// 出队
			else 
			{
				if (q->firstchild == NULL)
					q->firstchild = p;	// 设置结点p是结点q的第一个孩子
				else
				{
					q = q->firstchild;
					while (q->rightsib != NULL) // 查找结点q的最右兄弟
						q = q->rightsib;
					q->rightsib = p;			// 设置结点p为结点q的右兄弟
				}
				break;
			}
		}
		cout<<"请输入结点对,以空格分隔:";
		fflush(stdin);
        ch1 = getchar(); getchar(); ch2 = getchar();
	}
}

void Tree::Release(TNode *bt)
{
	if (bt == NULL)  return;     //递归调用的结束条件
	else
	{
		Release(bt->firstchild);  //后序递归释放bt的第一棵子树  
		Release(bt->rightsib);    //后序递归释放bt的右兄弟子树  
		delete bt;                //释放根结点
	}
}

2、前序遍历

void Tree::PreOrder(TNode *bt)
{
	if(bt==NULL)
		return ;//注意这里的return含义,根节点为空或者遍历到叶子节点则本次递归结束,回溯到上一次的递归。
	cout<<bt->data;//先访问根节点/父亲节点
	PreOrder(bt->firstchild);//递归前序遍历本结点的第一个孩子结点
	//第一个孩子结点遍历结束后则return回来再进行兄弟节点的遍历(下面一行代码)
	PreOrder(bt->rightsib);//递归前序遍历本结点的第一个兄弟节点
}

3、后序遍历

void Tree::PostOrder(TNode *bt)
{
	if(bt==NULL)
		return ;
	PostOrder(bt->firstchild);
	cout<<bt->data;//后序遍历完孩子结点后,然后再访问根节点,再遍历兄弟结点(要在兄弟节点之前访问根节点)
	PostOrder(bt->rightsib);
}

4、计算树的深度

int Tree::Depth(TNode *bt)
{
	TNode *p;
	if(bt==NULL) return 0;
	if(bt->firstchild==NULL) return 1; //没有孩子结点,则返回本层的深度1 
	int d,max=0;
	p = bt->firstchild;
	while(p!=NULL){  //遍历本层所有的兄弟结点,找到深度最大的
		d=Depth(p);
		if(d>max)
			max=d;
		p = p->rightsib;
	}
	return max+1; //深度要加上根节点1 
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
中序遍历和后序遍历前序遍历的方法如下: 1. 首先,我们需要知道前序遍历的特点,即根节点在前面。 2. 对于中序遍历和后序遍历,我们可以通过递归来转换为前序遍历。 3. 首先,我们需要找到后序遍历的最后一个节点,即根节点。然后,在中序遍历中找到根节点的位置。 4. 根据中序遍历的性质,根节点的左边是左子的中序遍历结果,右边是右子的中序遍历结果。 5. 然后,我们可以根据这个划分来确定后序遍历的左右子。 6. 继续递归地将左子和右子进行转换。 7. 最后,我们可以将根节点添加到前序遍历结果的最前面。 下面是转换的示例代码: ``` // 中序遍历和后序遍历前序遍历 function inorderPostorderToPreorder(inorder, postorder) { if (inorder.length === 0 || postorder.length === 0) { return []; } const rootValue = postorder[postorder.length - 1]; const rootIndex = inorder.indexOf(rootValue); const leftInorder = inorder.slice(0, rootIndex); const rightInorder = inorder.slice(rootIndex + 1); const leftPostorder = postorder.slice(0, rootIndex); const rightPostorder = postorder.slice(rootIndex, postorder.length - 1); const leftPreorder = inorderPostorderToPreorder(leftInorder, leftPostorder); const rightPreorder = inorderPostorderToPreorder(rightInorder, rightPostorder); return [rootValue, ...leftPreorder, ...rightPreorder]; } // 示例调用 const inorder = [4, 2, 5, 1, 6, 3, 7]; const postorder = [4, 5, 2, 6, 7, 3, 1]; const preorder = inorderPostorderToPreorder(inorder, postorder); console.log(preorder); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值