二叉树的基本操作以及二叉树部分oj题

一、k层节点的计算

k层问题相当于是求树叶子节点的计算的另一种变形,只不过多了一个限制条件,所以我们可以很轻松的写出如下代码:

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)//这不可加k==1的情况,因为前面有可能直接为空,会造成对空指针的解引用。
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

 注意!给第一个if条件不能加k==1,因为可能会出现下面的情况

 当左子树还没有到k==1时直接跳出循环,如果加上可能会导致对空指针的引用。

二、找节点

递归说到底,其实只需要考虑两个问题,一个是递归结束条件,另一个是思路,有了这两个就可以写出基本的递归形式。例如:

找节点结束有两种情况:

1、节点找到空也找不到。2、找到返回值。

思路:

先找左树,在找右树。

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	//结束条件
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	//开始从左树找
	BTNode* x1 = BinaryTreeFind(root->_left, x);
	if (x1)
	{
		return x1;//找到了返回
	}
	BTNode* x2 = BinaryTreeFind(root->_right, x);//左树找完找右树
	if (x2)
	{
		return x2;
	}
	//到这说明树找完了,找不到
	return NULL;
}

注意不可写出如下形式:

//结束条件
if (root == NULL)
{
	return NULL;
}
if (root->_data == x)
{
	return root;
}
BinaryTreeFind(root->_left, x);
BinaryTreeFind(root->_right, x);

递归不可能一次性将函数值直接返回给main函数,他只能返回给其上一层递归函数,所以我们要保存返回数据判断。

其次:

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	//结束条件
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	//BinaryTreeFind(root->_left, x);
	//BinaryTreeFind(root->_right, x);
	//开始从左树找
	BTNode* x1 = BinaryTreeFind(root->_left, x);
	BTNode* x2 = BinaryTreeFind(root->_right, x);//左树找完找右树

	if (x1)
	{
		return x1;//找到了返回
	}
	//BTNode* x2 = BinaryTreeFind(root->_right, x);//左树找完找右树
	if (x2)
	{
		return x2;
	}
	//到这说明树找完了,找不到
	return NULL;
}

这种写法虽然对,但是可能会导致无用的计算,如果左树找到直接返回即可,没必要到右树去找。(函数只有碰见返回值或者运行完函数才会停止,即这一层递归才能结束)。

递归展开图如上。

三、通过遍历创建树

通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 

后面的oj题会用到这个这里提前讲一下:
结束条件:
遇到#说明该节点为空,不向下继续插入。

思路:

先根,再建立左树,再建立右树。

BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
	arr[*pi]=='#'||arr[*pi]=='\0'
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*) malloc(sizeof(BTNode));//先根
	root->_data = a[(*pi)++];//读完一个pi要往后走
	root->_left = BinaryTreeCreate(a, pi);//再左
	root->_right = BinaryTreeCreate(a, pi);//再右
	return root;//完事返回根。
}

递归展开图

 

四、相同树问题

常见错误:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    
    if(p==NULL||q==NULL)
    {
        return false;
    }
    if(p->val==q->val)
    {
        return true;
    }
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

 条件判断一定要写递归终止时的情况,而不能写继续的情况。

结束条件:

两个数遍历完,两个值不相同,一个为空一个不为空。

思路:先检查左树再检查右树:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    if(q==NULL&&p==NULL)
    {
        return true;
    }
    if(p==NULL||q==NULL)
    {
        return false;
    }
    if(p->val !=q->val)
    {
        return false;
    }
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

五、对称二叉树

实际上就是相同树的另一种形式:

bool compare(struct TreeNode *left,struct TreeNode *right)
{
    if(left==NULL && right==NULL)
        return true;
    if(left==NULL || right ==NULL)
        return false;
    if(left->val != right->val)
        return false;
    return compare(left->left,right->right) && compare(left->right,right->left);
}

bool isSymmetric(struct TreeNode* root)
{
    return compare(root->left,root->right);
}   

六、另一颗树的子树

结束条件

当被比树为空时(递归到为空时说明这条路行不通,返回假),则一定不是

当是子树时返回真,不是则继续递归,

思路:分为左树和右树:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    if(q==NULL&&p==NULL)
    {
        return true;
    }
    if(p==NULL||q==NULL)
    {
        return false;
    }
    if(p->val !=q->val)
    {
        return false;
    }
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(root==NULL)
    {
        return false;
    }
    if(isSameTree(root,subRoot))
    {
        return true;
    }
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

七、二叉树的构建及遍历。

前面我们已经打好了基础这直接写:
 

#include <stdio.h>
#include<stdio.h>
typedef struct TreeNode
{
    char val;
    struct TreeNode* left;
    struct TreeNode* right;
}TreeNode;

TreeNode* maketree(char*arr,int*count)
{
    if(arr[*count]=='#'||arr[*count]=='\0')
    {
        return NULL;
    }
    TreeNode* newnode = (TreeNode*)malloc(sizeof(TreeNode));
    newnode->val = arr[(*count)++];
    
    newnode->left = maketree(arr,count);
    (*count)++;
    newnode->right = maketree(arr,count);
    return newnode;
}

void Inorder(TreeNode* root)
{
    if(root==NULL)
    {
        return;
    }
    Inorder(root->left);
    printf("%c ",root->val);
    Inorder(root->right);
}

int main()
{
    char arr[101];
    scanf("%s",arr);
    int count = 0;
    TreeNode* tree = maketree(arr,&count);
    Inorder(tree);
    return 0;
}

关于这里为什么下标传指针接下来一道题给大家解释

八、前序遍历

这里比较特殊的是他要将值放入在一个数组中,所有我们很容易有下面的思路

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int BinaryTreeSize(struct TreeNode * root)
{
	if (root == NULL) 
	{
		return 0;
	}
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
void preorder(struct TreeNode* root, int* a,int i)
{
    if(root==NULL)
    {
        return ;
    }
    a[i++]=root->val;
    preorder(root->left,a,i);
    preorder(root->right,a,i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    *returnSize=BinaryTreeSize(root);
    int *a =(int *)malloc(sizeof(int)*(*returnSize));
    int i=0;
    preorder(root,a,i);
    return a;
}

 如果我们这么写就会报出这样的错误,因为i为局部变量,在递归给下一层时不会对上一层经行修改,所以会出现数据覆盖的错误;

所以我们得传i的地址,这样在递归回去时i的值就会发生变化。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int BinaryTreeSize(struct TreeNode * root)
{
	if (root == NULL) 
	{
		return 0;
	}
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
void preorder(struct TreeNode* root, int* a,int* i)
{
    if(root==NULL)
    {
        return ;
    }
    a[(*i)++]=root->val;
    preorder(root->left,a,i);
    preorder(root->right,a,i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    *returnSize=BinaryTreeSize(root);
    int *a =(int *)malloc(sizeof(int)*(*returnSize));
    int i=0;
    preorder(root,a,&i);
    return a;
}

 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suiyi_freely

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值