你好,我是oneNBmetal!
没错,我改名了
那不多废话,我们今天来讲:二叉树!
二叉树的定义
二叉树,这是一个广为人知的东西,之前我已经在递归算法研究报告 #主要内容里大概讲了一点点
每一个不是在最底下的点都叫做根节点,而在最底下的就叫叶子节点
如图,黑色的就是根节点,红色的就是叶子节点
我们的都知道,每一个根节点都会有至少一个伸出去的点,左边的就叫左子树,右边的就叫右子树
——————————————————我是一条分割线——————————————————
二叉树,是一种基于递归算法的算法,大概分为满二叉树与完全二叉树
满二叉树,是什么?完全二叉树,又是什么?
拿上我们上期画的图~
这就是一棵满二叉树
反之,就是完全二叉树,非常的简单
当然,考试里当然不会只有这种简单的判断题
二叉树的考点(敲黑板)
据本人有幸参加过的NOIP竞赛,里面的二叉树主要考这几个知识点:
二叉树遍历
这个比较广为人知,分为前序遍历,中序遍历,与后序遍历
前序遍历,就是先遍历现在的根节点,然后遍历左子树,最后遍历右子树
中序遍历,就是先遍历左子树,然后遍历现在的根节点,最后遍历右子树
后序遍历,就是先遍历左子树,然后遍历右子树,最后遍历现在的根节点
举个例子:下面有一棵二叉树,输出它的前序,中序和后序遍历
前序遍历:1(根节点)2(左子树的根节点)4(左子树的左子树)5(左子树的右子树)3(右子树的根节点)6(右子树的左子树)7(右子树的右子树)
合起来就是:1245367
中序和后序遍历同理
这是比较难理解的,大家可以多琢磨一下
知二求一
这是比较经典的题了
比如,知道二叉树的前序遍历和中序遍历,求后序遍历
又比如,知道二叉树的后序遍历和中序遍历,求前序遍历
那,知道二叉树的后序遍历和前序遍历,求中序遍历呢?
不行,求不出来
为什么呢?
如这几颗二叉树,它们的前序和后序遍历都是相同的,但中序遍历却各不相同
所以,中序遍历对二叉树的构建至关重要
那怎么“知二求一”呢?
比如,知道二叉树的前序遍历和中序遍历,求后序遍历
前序遍历里的第一个,是不是就是它的根节点?这样我们就求到了根节点,然后放进中序遍历里,左边的就是它的左子树,右边的就是右子树,再次放到前序遍历里,我们就求到了左子树和右子树的根节点,然后以此类推,直到到达叶子节点
C++参考代码:
#include <bits/stdc++.h>
using namespace std;
int Fsod(string pre, string mid) {
if (pre.size() == 0) {
return 0;
}
char c = pre[0];
int idx = mid.find(c);
Fsod(pre.substr(1, idx), mid.substr(0, idx));
Fsod(pre.substr(idx + 1), mid.substr(idx + 1));
cout << c;
}
int main() {
string pre, mid;
cin >> mid >> pre;
Fsod(pre, mid);
return 0;
}
pre是前序遍历里,mid是中序遍历
又比如,知道二叉树的后序遍历和中序遍历,求前序遍历
其实和前序中序求后序是一样的,后序遍历的最后一个是根节点,然后放中序遍历里面,求到左子树和右子树后,再次求得左子树和右子树的根节点,以此类推,直到到达叶子节点
C++参考代码:
#include <bits/stdc++.h>
using namespace std;
int Fpre(string mid, string sod) {
if (sod.size() == 0) {
return 0;
}
char c = sod[sod.size() - 1];
int idx = mid.find(c);
cout << c;
Fpre(mid.substr(0, idx), sod.substr(0, idx));
Fpre(mid.substr(idx + 1), sod.substr(idx, sod.size() - idx - 1));
}
int main() {
// P1827
string mid, sod;
cin >> mid >> sod;
Fpre(mid, sod);
return 0;
}
排列组合类问题
一看我这个标题,有的同学就会说了:这不是讲二叉树吗?怎么和排列组合扯上关系了?
因为啊,二叉树很适合做排列组合
比如,1 2 3,求他们的全排列
那是不是直接就可以画一棵二叉树,像这样:
其中,左边代表我这些排列里添加了节点,右边反之
这样,一个全排列不就出来了吗?
尾声
那二叉树的学习就到此结束了,大家可以好好练习