一、二叉树的分类和其性质
- 二叉树的第 i i i层最多有2(i-1)个结点。
- 满二叉树:所有层的节点都是满的。一个 n n n层的二叉树,共有 2 n − 1 2^n-1 2n−1个结点。
- 完全二叉树:仅在最后一层有缺失结点,但缺失的结点编号都在最后。
二、完全二叉树的性质
设节点数量为
k
k
k,1号为根节点,
i
i
i为编号。
- i > 1 i>1 i>1的结点,其父节点是 i / 2 i/2 i/2;
- 若 2 ∗ i > k 2*i>k 2∗i>k,则 i i i没有孩子;若 2 ∗ i + 1 > k 2*i+1>k 2∗i+1>k,则 i i i没有右孩子。
- 若 i 有 孩 子 i有孩子 i有孩子,则左孩子为 2 ∗ i 2*i 2∗i,右孩子为 2 ∗ i + 1 2*i+1 2∗i+1。
三、二叉树的储存
1、指针实现:
struct node
{
string value; //结点值
node *l, *r; //指向左右结点
node() //初始化
{
l = r = NULL;
}
};
新建一个node时,用new
运算符动态申请内存。结束时,用delete
释放内存。
2、数组实现:
//利用i的左结点是2*i,右结点是2*i+1.
int heap[MAXN];
四、二叉树的遍历
我们有两种搜索方式,dfs和bfs遍历二叉树,这时候根据题干的要求来选择对应的遍历方式。
1、bfs—广度优先搜索
利用队列实现。
2、dfs—深度优先搜索
这时候分为三种遍历方式:先序遍历,中序遍历,后续遍历。
先、中、后代表的是根结点的相对位置。
①:先序遍历
遍历顺序: 父节点、左儿子、右儿子。
伪代码:
void pre_order(node *root) //先序遍历
{
if (root != NULL) //根据题干来添加判断,并进行输出和递归
{
cout << root->value << endl; //输出结点值
pre_order(root->l); //递归左子树
pre_order(root->r); //递归右子树
}
}
图示:
②:中序遍历
遍历顺序 :左儿子、父结点、右儿子。
性质、特征:
- 在二叉搜索树中,中序遍历实现了排序的功能,返回的结果是有序的。
- 若根结点已知,返回的结果中,排在根结点左端的序列在左子树上,排在根结点右端的序列在右子树上。
伪代码:
void in_order(node *root) //中序遍历
{
if (root != NULL) //根据题干来添加判断,并进行输出和递归
{
in_order(root->l); //递归左子树
cout << root->value << endl; //输出结点值
in_order(root->r); //递归右子树
}
}
图示:
③:后序遍历
遍历顺序:左儿子、右儿子、父结点。
后序遍历的最后一个结点是树的根。
伪代码:
void post_order(node *root) //后序遍历
{
if (root != NULL) //根据题干来添加判断,并进行输出和递归
{
post_order(root->l); //递归左子树
post_order(root->r); //递归右子树
cout << root->value << endl; //输出结点值
}
}
图示:
④:利用两种两种不同的已知遍历顺序来确定一棵树
先序+中序或者中序+后序。但是先序+后序不能确定一棵树
例题:P1030 求先序排列
ACcode:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
char in_order[15], post_order[15];
int len;
void dfs(int in_l, int in_r, int post_l, int post_r)
{
for (int i = in_l; i <= in_r; i++) //中序遍历
{
if (post_order[post_r] == in_order[i])
{
cout << in_order[i];
dfs(in_l, i - 1, post_l, post_l + (i - in_l - 1)); //左儿子
dfs(i + 1, in_r, post_l + (i - in_l), post_r - 1); //右儿子
return;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin >> in_order;
cin >> post_order;
len = strlen(in_order);
dfs(0, len - 1, 0, len - 1);
cout << endl;
return 0;
}
五、二叉树的生成和二叉树的释放空间
1、二叉树的生成:
步骤:
先序遍历输入要生成的二叉树数据,#代表空结点 。
伪代码:
void create_tree(node *&root)
{
char ch;
cin >> ch; //输入先序遍历
if (ch != '#')
{
root = new node; //动态申请内存
root->value = ch; //读入
create_tree(root->l); //建立左子树
create_tree(root->r); //建立右子树
}
}
2、二叉树的释放空间:
伪代码:
void remove_tree(node *root) //二叉树的释放空间
{
if (root == NULL)
return;
remove_tree(root->l);
remove_tree(root->r);
delete root;
}
六、二叉树结点的查找
若查找成功返回其指针,同样也能改写成bool类型。
node *find_node(node *&root, string aim) //若查找到返回其指针
{
node *p;
if (root == NULL) //空树
return NULL;
else if (root->value == aim) //找到该值
return root;
else //暂时未找到,递归进行查找
{
p = find_node(root->l, aim); //递归查找左树
if (p != NULL)
return p;
else
return find_node(root->r, aim); //递归查找右树
}
}
七、二叉树高度查询
伪代码:
int high_node(node *root) //二叉树的高度
{
int l_high, r_high;
if (root == NULL) //空树
return 0;
else
{
l_high = high_node(root->l);
r_high = high_node(root->r);
return max(l_high + 1, r_high + 1);
}
}