根据二叉搜索树的后序遍历重建二叉树/C++非递归遍历二叉树

二叉搜索树后序遍历序列

这是一种递归的算法思想,后续再优化
持续更新。。

#include<iostream>
using namespace std;
struct BiTree{
	int NodeData = 0;
	struct BiTree *pLeft = nullptr;
	struct BiTree *pRight = nullptr;
};
//二叉搜索树是指所有左子树的节点值均小于根节点值
//所有右子树的节点值均大于根节点值 
//现在已知二叉搜索树后序遍历序列[2,4,3,6,8,7,5]
//根据后序遍历规则,最后一个数即是根节点,假设位置是r 
//再根据搜索二叉树的规律,找出左边区间[0,r-1]小于根节点的区间
//这个区间就是左子树,再对左子树递归上述
//同理,比根节点大的值就是右子树的区间,对右子树递归 
BiTree* process(BiTree* root, int postArry[], int left, int right){
	if(left>right){
		return nullptr;
	}
	root = new BiTree;
	root->NodeData = postArry[right];
	if(left==right){//当序列只有一个数 
		return root;
	}
	//注意体会此处m的初始值
	//是为了当存在极端情况,比如只有左子树或只有右子树
	//那么序列里就全是小于根节点的数或者是全部大于根节点的数
	//在这种情况下考虑m的值 
	int m=left-1; 
	for(int i=left; i<right; i++){
		if(postArry[i]<postArry[right]){
			m=i;
		}
	}
	root->pLeft = process(root->pLeft, postArry, left, m);
	root->pRight = process(root->pRight, postArry, m+1, right-1);
	return root;
}
int main(){
	int arry[] = {2,4,3,6,8,7,5};
	int len = sizeof(arry)/sizeof(arry[0]);
	BiTree* re = nullptr;
	re = process(re, arry, 0, len-1);
	cout<<re->NodeData;
	return 0;
}

非递归遍历二叉树

#include<iostream>
#include<vector>
#include<stack>
using namespace std;
struct BiTree{
	int NodeData = 0;
	struct BiTree *pLeft = nullptr;
	struct BiTree *pRight = nullptr;
};
//二叉搜索树是指所有左子树的节点值均小于根节点值
//所有右子树的节点值均大于根节点值 
//现在已知二叉搜索树后序遍历序列[2,4,3,6,8,7,5]
//根据后序遍历规则,最后一个数即是根节点,假设位置是r 
//再根据搜索二叉树的规律,找出左边区间[0,r-1]小于根节点的区间
//这个区间就是左子树,再对左子树递归上述
//同理,比根节点大的值就是右子树的区间,对右子树递归 
BiTree* process(BiTree* root, int postArry[], int left, int right){
	if(left>right){
		return nullptr;
	}
	root = new BiTree;
	root->NodeData = postArry[right];
	if(left==right){//当序列只有一个数 
		return root;
	}
	//注意体会此处m的初始值
	//是为了当存在极端情况,比如只有左子树或只有右子树
	//那么序列里就全是小于根节点的数或者是全部大于根节点的数
	//在这种情况下考虑m的值 
	int m=left-1; 
	for(int i=left; i<right; i++){
		if(postArry[i]<postArry[right]){
			m=i;
		}
	}
	root->pLeft = process(root->pLeft, postArry, left, m);
	root->pRight = process(root->pRight, postArry, m+1, right-1);
	return root;
}
//对重建出来的二叉树前序中序后序遍历(递归)
//前序,中序,后序递归模式一样,此处只做前序示例 
void preorder(BiTree* root, vector<int>&re){
	if(root){
		re.push_back(root->NodeData);
		cout<<root->NodeData<<" ";
		if(root->pLeft){
			preorder(root->pLeft, re);
		}
		if(root->pRight){
			preorder(root->pRight, re);
		}
	}
}
vector<int> show1(BiTree* root){
	vector<int>re;
	preorder(root,re);
	return re;
}
//非递归前序遍历
void preorder2(BiTree* root){
	stack<BiTree*>s;
	BiTree *p=root;
	while(p!=nullptr||!s.empty()){
		while(p!=nullptr){
			cout<<p->NodeData<<" ";
			s.push(p); 
			p=p->pLeft;
		}
		p=s.top();
		s.pop();
		p=p->pRight;
	}
} 
//非递归中序遍历 
void inorder(BiTree* root){
	stack<BiTree*>s;//存放着二叉树节点的栈 
	BiTree *p=root;
	while(p!=nullptr||!s.empty()){
		while(p!=nullptr){
			s.push(p);
			p=p->pLeft; 
		}
		p=s.top();
		cout<<p->NodeData<<" ";
		s.pop();
		p=p->pRight;
	}
} 
//非递归后序遍历
//保证根节点在左孩子和右孩子之后访问,因此对于任一结点P,先将其入栈 
//如果P不存在左孩子和右孩子,则可以直接访问它;
//或者P存在左孩子或者右孩子,但左孩子和右孩子都已访问,则同样可以直接访问该结点
//若非上述两种情况,则将P的右孩子和左孩子依次入栈
void postorder(BiTree* root){
	stack<BiTree*>s;
	BiTree *pre=nullptr;//记录前一次访问的节点
	BiTree *cur;//当前节点
	s.push(root);//先将根节点入栈 
	while(!s.empty()){
		cur=s.top();
		if(cur->pLeft==nullptr&cur->pRight==nullptr||
		(pre!=nullptr&&(pre==cur->pLeft||pre==cur->pRight))){
			cout<<cur->NodeData<<" ";
			s.pop();
			pre=cur;//更新记录 
		}
		else{
			//先让右子树节点入栈再左子树节点入栈
			//保证最后是左子树节点先被访问 
			if(cur->pRight!=nullptr){
				s.push(cur->pRight);
			}
			if(cur->pLeft!=nullptr){
				s.push(cur->pLeft);
			}
		}
	} 
}
int main(){
	int arry[] = {2,4,3,6,8,7,5};
	int len = sizeof(arry)/sizeof(arry[0]);
	BiTree* re = nullptr;
	re = process(re, arry, 0, len-1);
	//cout<<re->pLeft<<endl;
	cout<<"递归前序遍历:"; 
	show1(re);//前序遍历调用 
	cout<<endl<<"非递归中序遍历:";
	inorder(re);
	cout<<endl<<"非递归前序遍历:";
	preorder2(re);
	cout<<endl<<"非递归后序遍历:";
	postorder(re); 
	return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值