文章目录
前言
- 链式二叉树增删查改的价值
- 堆的意义:插入数据的意义—排序、topk
- 普通链式二叉树没有意义
- 我们学习当前链式二叉树有以下两目的
- 更复杂的二叉搜索树->AVL 红黑树(以后打基础)——高阶
- 排序二叉树
- 搜索二叉树——左边比根小,右边比根大
- 很多二叉树的题是在这一块(笔试面试O阶题)
- 所以二叉树这块的重点不是增删查改,而是学习二叉树的结构,为之后学习打基础。
定义结构—BinaryTreeNode
typedef int BTDataType;
typedef struct BinaryrTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
BTDataType val;
}BTNode;
手动构建—BuyNode
构建如下树:
BTNode* BuyTreeNode(BTDataType x)
{
//malloc申请空间并检查
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
if (node == NULL)
{
perror("malloc error\n");
exit(-1);
}
//初始化
node->val = x;
node->left = NULL;
node->right = NULL;
return node; //注意返回所创建的节点
}
int main()
{
//手动构建
BTNode* node1 = BuyTreeNode(1);
BTNode* node2 = BuyTreeNode(2);
BTNode* node3 = BuyTreeNode(3);
BTNode* node4 = BuyTreeNode(4);
BTNode* node5 = BuyTreeNode(5);
BTNode* node6 = BuyTreeNode(6);
node1->left = node2;
node1->right = node4;
node2->left = node3;
node4->left = node5;
node4->right = node6;
}
三种遍历
前序遍历 PrevOrder
void PreOrder(BTNode* node)
{
//遍历到空就停止
if (node == NULL)
{
printf("NULL "); //为了更好观察,我们打印空节点
return;
}
printf("%d ", node->val);
PreOrder(node->left);
PreOrder(node->right)
}
中序遍历 InOrder
void InOrder(BTNode* node)
{
if (node == NULL)
{
return;
}
InOrder(node->left);
printf("%d ", node->val);
PreOrder(node->right);
}
后序遍历 PostlOrder 同理可得
void PostOrder(BTNode* node)
{
if (node == NULL)
{
return;
}
InOrder(node->left);
PreOrder(node->right);
printf("%d ", node->val);
}
图示(中序为例)
为了更好理解其中过程我画了如下函数图(以中序为例):
如图得到中序的结果;
每个函数调用都建立一个栈帧:
【注意:空内存也调用栈帧】
结束后销毁回到调用处
调用栈帧
递归展开图画到NULL后回调
- 前序后序同上原理,大家可以画图练习;
如何求树中节点个数
节点个数
一般方法
- 遍历一般计数器++
//-遍历一遍,计数器++
int size = 0; //为了多次应该定义全局变量。
int treesize(btnode* root)
{
//int size = 0; //不可取,每次进入递归都会被初始化为0;
//static int size = 0;
//一般可取,静态变量无法再次被初始化在前面基础上累加,只能计算一棵树的节点
if (root == null)
return;
else
size++;
treesize(root->left);
size = 0;
treesize(root->right);
return size;
}
牛逼方法(递归思路)
int TreeSize(BTNode* root)
{
if (root == NULL)
return 0;
else
return TreeSize(root->left)
+ TreeSize(root->right)+1; //+1是加自己的个数,如果没有返回0
//三目操作符
//return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
在返回时先求左子树在求右子树最后求自己,所以本质是求其后序。
叶子节点个数
”分而治之“的思想
是叶子的条件:左右节点为NULL
- 判断左右节点是否为NULL,其后将叶子节点相加
- 左右都为NULL,返回1
- 左子树+右子树
//叶子节点个数
int TreeLeaveSize(BTNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
return TreeLeaveSize(root->left)
+ TreeLeaveSize(root->right);
//分而治之
}
第k层节点个数
假设求第三层——>求第二层的子树的节点个数——>第一层的子树的节点个数
- k层=左子树k-1层 + 右子树k-1层(作为递进条件)
->> 访问到空节点返回0;(作为回归条件)
->> 访问到节点。
//第k层节点个数
int TreeKLevel(BTNode* root ,int k)
{
if (root == NULL)
return 0;
if (root != NULL)
return 1;
return TreeKLevel(root->left, k - 1)
+ TreeKLevel(root->right, k - 1);
}
将问题化为最小子问题。
练习
单值二叉树
递进条件
左子树
回归条件
- ture
左/右子树为NULL
左右子树和根相等
- false
左子树不等于根
右子树不等于根
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };*/
bool isUnivalTree(struct TreeNode* root){
if(root==NULL)
return true;
if(root->left && root->left->val != root->val)
return false;
if(root->right && root->right->val != root->val)
return false;
return isUnivalTree(root->left)
&&isUnivalTree(root->right);
}
今日份总代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef int BTDataType;
typedef struct BinaryrTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
BTDataType val;
}BTNode;
BTNode* BuyTreeNode(BTDataType x)
{
//malloc申请空间并检查
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
if (node == NULL)
{
perror("malloc error\n");
exit(-1);
}
//初始化
node->val = x;
node->left = NULL;
node->right = NULL;
return node; //注意返回所创建的节点
}
void PreOrder(BTNode* node)
{
if (node == NULL)
{
printf("NULL "); //打印叶子节点
return;
}
printf("%d ", node->val);
PreOrder(node->left);
PreOrder(node->right);
}
void InOrder(BTNode* node)
{
if (node == NULL)
{
printf("NULL ");
return;
}
InOrder(node->left);
printf("%d ", node->val);
PreOrder(node->right);
}
void PostOrder(BTNode* node)
{
if (node == NULL)
{
printf("NULL ");
return;
}
InOrder(node->left);
PreOrder(node->right);
printf("%d ", node->val);
}
//节点个数
//-遍历一遍,计数器++
//int size = 0; //为了多次应该定义全局变量。
//int treesize(btnode* root)
//{
// //int size = 0; //不可取,每次进入递归都会被初始化为0;
// //static int size = 0; //一般可取,静态变量无法再次被初始化在前面基础上累加,只能计算一棵树的节点
// if (root == null)
// return;
// else
// size++;
// treesize(root->left);
// size = 0;
// treesize(root->right);
// return size;
//}
int TreeSize(BTNode* root)
{
//if (root == NULL)
// return 0;
//else
// return TreeSize(root->left) + TreeSize(root->right)+1; //+1是加自己的个数,如果没有返回0
return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
//叶子节点个数
int TreeLeaveSize(BTNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
return TreeLeaveSize(root->left) + TreeLeaveSize(root->right); //分而治之
}
//第k层节点个数
int TreeKLevel(BTNode* root ,int k)
{
if (root == NULL)
return 0;
if (root != NULL)
return 1;
return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}
int main()
{
//手动构建
BTNode* node1 = BuyTreeNode(1);
BTNode* node2 = BuyTreeNode(2);
BTNode* node3 = BuyTreeNode(3);
BTNode* node4 = BuyTreeNode(4);
BTNode* node5 = BuyTreeNode(5);
BTNode* node6 = BuyTreeNode(6);
node1->left = node2;
node1->right = node4;
node2->left = node3;
node4->left = node5;
node4->right = node6;
//前序遍历:根-左-右
PreOrder(node1);
printf("\n");
InOrder(node1);
printf("\n");
PostOrder(node1);
printf("\n");
printf("%d\n", TreeSize(node1));
printf("%d\n", TreeSize(node1));
printf("%d\n", TreeLeaveSize(node1));
return 0;
}
**感谢各位老铁能看到这里,还请给个免费的赞哦~**❤️❤️❤️❤️❤️