目录
1.关于二叉树的遍历
所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
二叉树的遍历有 四种 方法,分别是 前序遍历 中序遍历 后续遍历 以及 层序遍历;
1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。 ( 根 左子树 右子树 )
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中。( 左子树 根 右子树)
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。( 左子树 右子树 根)4. 层序遍历 设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
1.我们先简单的定义一个 二叉树;
像这样的二叉树:
代码实现:
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef struct BinaryTreeNode
{
int data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
BTNode* CreatTree()
{
BTNode* n1 = (BTNode*)malloc(sizeof(BTNode));
assert(n1);
BTNode* n2 = (BTNode*)malloc(sizeof(BTNode));
assert(n2);
BTNode* n3 = (BTNode*)malloc(sizeof(BTNode));
assert(n3);
BTNode* n4 = (BTNode*)malloc(sizeof(BTNode));
assert(n4);
BTNode* n5 = (BTNode*)malloc(sizeof(BTNode));
assert(n5);
BTNode* n6 = (BTNode*)malloc(sizeof(BTNode));
assert(n6);
BTNode* n7 = (BTNode*)malloc(sizeof(BTNode));
assert(n7);
n1->data = 1;
n2->data = 2;
n3->data = 3;
n4->data = 4;
n5->data = 5;
n6->data = 6;
n7->data = 7;
n1->left = n2;
n1->right = n4;
n2->left = n3;
n2->right = NULL;
n3->left = NULL;
n3->right = n7;
n4->left = n5;
n4->right = n6;
n5->left = NULL;
n5->right = NULL;
n6->left = NULL;
n6->right = NULL;
n7->left = NULL;
n7->right = NULL;
return n1;
}
1. 先序遍历 中序遍历 后续遍历
这里的遍历运用到了 递归的思想
// 先序遍历
void FrontBT(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%d ", root->data);
FrontBT(root->left);
FrontBT(root->right);
}
// 中序遍历
void MidBT(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
FrontBT(root->left);
printf("%d ", root->data);
FrontBT(root->right);
}
// 后序遍历
void BackBT(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
BackBT(root->left);
BackBT(root->right);
printf("%d ", root->data);
}
这里我们以后序遍历为例,用下图来说明递归的过程:
运行结果如下:
2.关于二叉树的其他函数实现
1.二叉树节点的个数,
static int count = 0;
int TreeSize(BTNode* root)
{
if (root == NULL)
{
return;
}
count++;
TreeSize(root->left);
TreeSize(root->right);
return count;
}
2.二叉树叶子的个数,
int TreeLeaSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return TreeLeaSize(root->left) + TreeLeaSize(root->right);
}
3.二叉树 的深度
int TreeHeight(BTNode* root)
{
if (root == NULL)
{
return 0;
}
int ldp = TreeHeight(root->left);
int rdp = TreeHeight(root->right);
return ldp > rdp ? ldp + 1 : rdp + 1;
}
4.第 k 层 二叉树节点的个数;
// 第 k 层 节点个数 -> 转换从 左右子树的问题
int TreeKLeavel(BTNode* root, int k)
{
if (root == NULL)
{
return;
}
static int count = 0;
k--;
if (k == 0)
{
if (root != NULL)
{
count++;
}
return;
}
TreeKLeavel(root->left, k);
TreeKLeavel(root->right, k);
return count;
}
// 这里 第k 层节点个数 还可以这样写
int TreeKLeavel(BTNode* root, int k)
{
assert(k > 0);
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return TreeKLeavel(root->left, k - 1) + TreeKLeavel(root->right, k - 1);
}
3.二叉树递归OJ题
1.单值二叉树
思路 :
一棵树的所有节点都有相同的值,当且仅当对于树上的每一条边的两个端点,它们都有相同的值(这样根据传递性,所有节点都有相同的值)。
因此,我们可以对树进行一次深度优先搜索。当搜索到节点 x 时,我们检查 x 与 x 的每一个子节点之间的边是否满足要求。例如对于左子节点而言,如果其存在并且值与 x 相同,那么我们继续向下搜索该左子节点;如果值与 x 不同,那么我们直接返回false。
bool isUnivalTree(struct TreeNode* root){
if(root == NULL)
{
return true;
}
if(root->left && root->val != root->left->val)
{
return false;
}
if(root->right && root->val != root->right->val)
{
return false;
}
return isUnivalTree(root->left) && isUnivalTree(root->right);
}
2.相同的树
思路:
如果两个二叉树都为空,则两个二叉树相同。如果两个二叉树中有且只有一个为空,则两个二叉树一定不相同。
如果两个二叉树都不为空,那么首先判断它们的根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别判断两个二叉树的左子树是否相同以及右子树是否相同。这是一个递归的过程,因此可以使用深度优先搜索,递归地判断两个二叉树是否相同。
ool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p == NULL&& q == NULL)
{
return true;
}
if((p == NULL && q != NULL) ||( q== NULL && p != NULL ))
{
return false;
}
if(p->val != q ->val)
{
return false;
}
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
3.另一颗子树
思路:
这一题相当于 上一题的延申,利用 判断 原树的 每个节点 是否与 suRoot 相等 就可以解决
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p == NULL&& q == NULL)
{
return true;
}
if((p == NULL && q != NULL) ||( q== NULL && p != 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);
// 左右子树有一个为 真 就为真
}