重建二叉树

我看剑指offer上写的代码很长,于是我就没看,我就根据书中的两张图,其实有那两张图就够了,这两张图就表示的二叉树的结构关系

                                                          

(图中应该是中序遍历,写错了)

我们根据这张图,就可以知道,当输入一个数组,在前序遍历中,第一个节点肯定是根节点,那么在后序遍历中,在root节点前的肯定是左子树,root节点后肯定是右子树,那么我就把这个结构分清楚了,然后递归,将左子树作为一个子树再一次这样分,同理右子树,也是这样;

我是怎么递归的:

我首先记录当来了一个数组时,前序遍历和后序遍历分别在哪开始的,比如分到左子树:

                                                         

那么前序应该从数组的1位置开始,后序应该从0开始;

怎么 知道有没有左子树呢?

在前序遍历中,数组的第一个节点就是根节点,那么从后序遍历的数组开始遍历,比如根节点为1时,那么后序遍历了3次遇到根节点1,就停止,那么我就知道遍历的次数大于0,就知道是有左子树的;

怎么知道有没有右子树呢?

我每一次都会记录子树的长度,当遍历完左子树,知道次数也就是左子树的个数,那么数组总长度length - 左子树的个数 - 1(根节点) =右子树的个数,如果右子树的个数大于0,则说明是右子树,那么进行递归,将前序遍历开始的位置移动到右子树的开始,后序遍历的位置移动到右子树的开始

code

//树的节点
struct Node
{
	Node(int v = 0) :val(v),left(nullptr),right(nullptr) {};
	int val;
	Node *left;
	Node *right;
};

//先序遍历
void preorder_recursion(Node *node)
{
	if (node)
		cout << node->val << "  ";
	if (node->left)
		preorder_recursion(node->left);
	if (node->right)
		preorder_recursion(node->right);
}

//中序遍历
void inorder_recursion(Node *node)
{
	if (node)
	{
		if (node->left)
			inorder_recursion(node->left);
		cout << node->val << "  ";
		if (node->right)
			inorder_recursion(node->right);
	}

}


//重建二叉树
Node* Rebuild_Tree(vector<int> &preorder, vector<int> &inorder,int pre_P,int in_P,int length)
{
	if (preorder.empty())
		return nullptr;
	int i = 0;
	int j = in_P;
	while (true)
	{
		if (inorder[j++] != preorder[pre_P])
			++i;
		else
			break;	 
	}
	Node *node = new Node(preorder[pre_P]);
	if (i > 0)	//i表示左子树的个数
	{
		node->left = Rebuild_Tree(preorder, inorder, pre_P + 1, in_P ,i);
	}
	if (length > i + 1)	//i表示左子树的个数,length> i+1 则表示还有右子树,这个1表示根节点
		node->right = Rebuild_Tree(preorder, inorder, pre_P + i + 1, in_P + i + 1, length - i - 1);
	return node;
}

void check_Tree(Node *node)
{
     preorder_recursion(node);
     inorder_recursion(node);
}

int main()
{
    vector<int> pre = { 1,2,4,7,3,5,6,8 };
    vector<int> in = { 4,7,2,1,5,3,8,6 };


    Node *node=Rebuild_Tree(pre_ds, in_ds, 0, 0,pre_ds.size());
    
    //可以通过先序遍历和中序遍历来检验重建的二叉树是否正确
    check_Tree(node);
    return  0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值