105. 从前序与中序遍历序列构造二叉树
思路:
题目给出了前序和中序遍历,那么就得先从这个两种遍历方式入手:前序遍历可以确定每棵树的根节点(后序也是可以),中序遍历则可以根据根节点划分出左右子树;
大致过程如下:
先根据前序遍历所确定的根节点,到中序遍历中锁定根节点,然后划分出左右子树的区间范围,让根节点与其左右子树相连接;我们不断的依据前序遍历的根节点来对中序遍历进行划分,来使中序遍历形成左中序与右中序,直至中序遍历中无法继续划分出左右子树(即节点个数小于等于0);
struct TreeNode* _BuildTree(int* preorder, int* pi, int* inorder, int inorderSize)
{
//无法继续划分左右子树
if(inorderSize <= 0)
return 0;
//创建对应前序遍历中的根节点
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
root->left = NULL;
root->right = NULL;
root->val = preorder[*pi];
//在中序遍历中查找根节点
int index = 0;
for(int i = 0; i < inorderSize; i++)
{
//找到对应的根节点
if(preorder[*pi] == inorder[i])
{
index = i;
}
}
//依据中序遍历的根节点划分左右子树
int lefti = index;
int righti = inorderSize - index - 1;
int* left_inorder = inorder;
int* right_inorder = inorder + index + 1;
//左子树链接
if(lefti > 0)
(*pi)++;
root->left = _BuildTree(preorder,pi,left_inorder,lefti);
//右子树链接
if(righti > 0)
(*pi)++;
root->right = _BuildTree(preorder,pi,right_inorder,righti);
return root;
}
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize)
{
int i = 0;
return _BuildTree(preorder,&i,inorder,inorderSize);
}
114. 二叉树展开为链表
思路:
我们采用后序的方式,先将右子树给存储起来,再把左子树连接到原右子树的位置,最后遍历寻找连接后的左子树的尾部,在尾部插入原右子树;
struct TreeNode* Build_List(struct TreeNode* root)
{
if(root == NULL)
return NULL;
//先将左子树转换到右子树中
struct TreeNode* left = Build_List(root->left);
struct TreeNode* right = Build_List(root->right);
//将左子树连接到原右子树的位置
root->right = left;
root->left = NULL;
//找到左子树转换为链表后的尾节点
struct TreeNode* cur = root;
while(cur->right)
{
cur = cur->right;
}
//将原右子树连接到左子树的尾部
cur->right = right;
return root;
}
void flatten(struct TreeNode* root)
{
Build_List(root);
}