链式二叉树的遍历、节点个数和单值二叉树问题

@TOC
4800a8cfac90f4fa2fd18b8d7035f36c_MD5

前言

  • 链式二叉树增删查改的价值
  • 堆的意义:插入数据的意义—排序、topk
  • 普通链式二叉树没有意义
  • 我们学习当前链式二叉树有以下两目的
  1. 更复杂的二叉搜索树->AVL 红黑树(以后打基础)——高阶
  2. 排序二叉树
  3. 搜索二叉树——左边比根小,右边比根大
  4. 很多二叉树的题是在这一块(笔试面试O阶题)
  • 所以二叉树这块的重点不是增删查改,而是学习二叉树的结构,为之后学习打基础。

定义结构—BinaryTreeNode

1
2
3
4
5
6
7
8
typedef int BTDataType;
typedef struct BinaryrTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
BTDataType val;

}BTNode;

手动构建—BuyNode

构建如下树:
759355dce625c70030586609fd834930_MD5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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

1
2
3
4
5
6
7
8
9
10
11
12
void PreOrder(BTNode* node)
{
//遍历到空就停止
if (node == NULL)
{
printf("NULL "); //为了更好观察,我们打印空节点
return;
}
printf("%d ", node->val);
PreOrder(node->left);
PreOrder(node->right)
}

中序遍历 InOrder

1
2
3
4
5
6
7
8
9
10
void InOrder(BTNode* node)
{
if (node == NULL)
{
return;
}
InOrder(node->left);
printf("%d ", node->val);
PreOrder(node->right);
}

后序遍历 PostlOrder 同理可得

1
2
3
4
5
6
7
8
9
10
void PostOrder(BTNode* node)
{
if (node == NULL)
{
return;
}
InOrder(node->left);
PreOrder(node->right);
printf("%d ", node->val);
}

图示(中序为例)

8e76af18036419b1a577f857e5423800_MD5

为了更好理解其中过程我画了如下函数图(以中序为例):
98574839291d7b04b3477fe99af6418a_MD5

如图得到中序的结果;

每个函数调用都建立一个栈帧:
注意空内存也调用栈帧】
结束后销毁回到调用处
调用栈帧
递归展开图画到NULL后回调

  • 前序后序同上原理,大家可以画图练习;

如何求树中节点个数

节点个数

一般方法

  • 遍历一般计数器++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//-遍历一遍,计数器++
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;
}

牛逼方法(递归思路)

1
2
3
4
5
6
7
8
9
10
11
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

  1. 判断左右节点是否为NULL,其后将叶子节点相加
  2. 左右都为NULL,返回1
  3. 左子树+右子树
1
2
3
4
5
6
7
8
9
10
11
//叶子节点个数
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;(作为回归条件
    ->> 访问到节点。
1
2
3
4
5
6
7
8
9
10
//第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);
}

将问题化为最小子问题。

练习

单值二叉树

c533781c0f6d74b15e074e6dd09ae818_MD5

递进条件

左子树

回归条件
  • ture

    左/右子树为NULL
    左右子树和根相等

  • false

    左子树不等于根
    右子树不等于根

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 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);
}

今日份总代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#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;
}

感谢各位老铁能看到这里,还请给个免费的赞哦~❤️❤️❤️❤️❤️