二叉树形式与性质
首先,二叉树有这么几种性质,他的性质在编辑程序的时候是至关重要的,绝不可以忘记那么,我们来看一下这几种性质吧:

  

二叉树还有五种形式,

 

这五种形式分别是:

满二叉树:每层都是满的;

完全二叉树:除最后一层外,每层都是满的,并且或者最后一层是满的,或者是在右边缺少连续若

干结点;

空树:没有节点

根树:一个节点

斜树:左斜树,右斜树

怎么求二叉树有多少节点呢?我们看一下代码:

1 int TreeSize(BTNode* root) {
2     return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
3 }

二叉树的深度与度:
深度
深度为n,最多有2ⁿ-1个结点【n≥1】第i层,最多有2的(i-1)次方个结点;具有n个结点的完全二

叉树的深度为 floor(log2n)+1


1、结点所拥有的子树的个数

2、树中各结点度的最大值称为该树的度,叶子结点就是度为0的结点

例 n0:度为0的结点数,n1:度为1的结点 n2:度为2的结点数

对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;

入度与出度:

入度即指共有多少边连接此节点,出度指从此节点出去共有几条边。

例题1:
一棵树度为4,其中度为1,2,3,4的结点个数分别为4,2,1,1,则这棵树的叶子节点个数为多少?

解:因为任一棵树中,结点总数=度数*该度数对应的结点数+1,所以:

n0+4+2+1+1 = (0*n0 + 1*4 + 2*2 + 3*1 + 4*1)+1

则:n0=8

其中:n0表示叶子结点。

例题2:
一颗二叉树的叶子节点有5个,度为1的结点有3个,该二叉树的结点总个数是?

N0 = N2+1

N0 = 5 则 N2 = 4

N = N0+N1+n2

=5+3+4

=12

例题3:
深度为7的完全二叉树共有125个结点,则该完全二叉树的叶子结点为?

h = 7 ->125

h = 6 ->满二叉树*2^6 - 1=63

则最后一层有125 - 63 = 62个

此外第六层有1个叶节点

62 + 1 = 63个

遍历:
二叉树还有三种特有的遍历方式,它们分别是:前序遍历、中序遍历、后序遍历。

这三种方式,其实他的意思就是前根序遍历,中根序遍历和后根序遍历。

三种方式的遍历方式分别是:根-左-右,左-根-右,左-右-根。

左子树比右子树的要靠前,举个例子:

 

 

 

前序遍历:先访问根,再左子树,接右子树。

顺序为:A,B,D,E,C,F

中序遍历:先访问左子树,再根,接右子树。

顺序为:D,B,E,A,F,C

后序遍历:先访问左子树,再右子树,接根。

顺序为:D,E,B,F,C,A

(二叉树为空直接返回)

知道了两种遍历的结果,就能把第三种推出来,来一道题试看一下

例题1:P1305 新二叉树

题目描述

输入一串二叉树,输出其前序遍历。

输入格式

第一行为二叉树的节点数 nn。(1≤n≤26)

后面 nn 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。

空节点用 * 表示

输出格式

二叉树的前序遍历。

输入输出样例

输入 #1复制

6
abc
bdi
cj*
d**
i**
j**
输出 #1复制

abdicj
解:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n, l[50], r[50], root;
 4 string str;
 5 void preorder(int t) {
 6     if (t == ('*' - 'a')) {
 7         return;
 8     }
 9     cout << char('a' + t);
10     preorder(l[t]);
11     preorder(r[t]);
12 }
13 int main() {
14     cin >> n;
15     for (int i = 0; i < n; i++) {
16         cin >> str;
17         if (!i) {
18             root = str[0] - 'a';
19         }
20         l[str[0] - 'a'] = str[1] - 'a';
21         r[str[0] - 'a'] = str[2] - 'a';
22     }
23     preorder(root);
24     return 0;
25 }

二叉树结点名称与关系
二叉树的某个节点与一指定节点的关系是有名称的,我们附图讲解一下:

 

 

 

八号节点是一个叶节点,他的父节点是四号,父节点的意思就是从这个节点往上的一个节点,这

个节点是一个枝节点。

祖先节点是指某一个节点往上直至根节点的所有点(包括此节点,就是自己也是自己的祖先),举

个例子:13号节点的祖先节点是包括13号在内的13,6,3,1

12号节点与13号节点的公共祖先有6,3,1;最近公共祖先是6.

当然,还有子节点,子节点是指某节点所分支下来的一个节点,就是比这个节点所在的层下一层的

直接分支,举个例子,4号节点的子节点是8号与9号。

孙子节点:就是指某个节点的非直接分支(就是间接分支),通俗一点就是分支的分支。

例题:

P3379 【模板】最近公共祖先(LCA)

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入格式

第一行包含三个正整数 N,M,SN,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来 N-1N−1 行每行包含两个正整数 x, yx,y,表示 xx 结点和 yy 结点之间有一条直接连接的边(数据保证可以构成树)。

接下来 MM 行每行包含两个正整数 a, ba,b,表示询问 aa 结点和 bb 结点的最近公共祖先。

输出格式

输出包含 MM 行,每行包含一个正整数,依次为每一个询问的结果。

输入输出样例

输入 #1复制

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
输出 #1复制

4
4
1
4
4
说明/提示

对于 30\%30% 的数据,M< 10M≤10。

对于 70\%70% 的数据M\leq 10000M≤10000。

对于 100\%100% 的数据M\leq 500000M≤500000。

样例说明:

该树结构如下:

 

第一次询问:2, 42,4 的最近公共祖先,故为 44。

第二次询问:3, 23,2 的最近公共祖先,故为 44。

第三次询问:3, 53,5 的最近公共祖先,故为 11。

第四次询问:1, 21,2 的最近公共祖先,故为 44。

第五次询问:4, 54,5 的最近公共祖先,故为 44。

故输出依次为 4, 4, 1, 4, 44,4,1,4,4。

2021/10/4 数据更新 @fstqwq:应要求加了两组数据卡掉了暴力跳。

解:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #define int long long
 6 using namespace std;
 7 const int maxn=5e5+5;
 8 typedef struct Edge {
 9     int next,to;
10 } edg;
11 edg e[maxn<<1];
12 int n,m,s,cnt,head[maxn<<1];
13 void AddEdge(int u,int v) {
14     e[cnt].to=v;
15     e[cnt].next=head[u];
16     head[u]=cnt++;
17 }
18 int fa[maxn],son[maxn],depth[maxn],siz[maxn];
19 void dfs1(int u,int f) {
20     fa[u]=f;
21     depth[u]=depth[f]+1;
22     siz[u]=1;
23     int maxsize=-1;
24     for(int i=head[u]; ~i; i=e[i].next) {
25         int v=e[i].to;
26         if(v==f)
27             continue;
28         dfs1(v,u);
29         siz[u]+=siz[v];
30         if(siz[v]>maxsize) {
31             maxsize=siz[v];
32             son[u]=v;
33         }
34     }
35 }
36 int tim,dfn[maxn],top[maxn];
37 void dfs2(int u,int t) {
38     dfn[u]=++tim;
39     top[u]=t;
40     if(!son[u])
41         return;
42     dfs2(son[u],t);
43     for(int i=head[u]; ~i; i=e[i].next) {
44         int v=e[i].to;
45         if(v==fa[u]||v==son[u])
46             continue;
47         dfs2(v,v);
48     }
49 }
50 int query(int x,int y) {
51     while(top[x]!=top[y]) {
52         if(depth[top[x]]<depth[top[y]])
53             swap(x,y);
54         x=fa[top[x]];
55     }
56     if(depth[x]>depth[y])
57         swap(x,y);
58     return x;
59 }
60 signed main() {
61     memset(head,-1,sizeof(head));
62     scanf("%lld%lld%lld",&n,&m,&s);
63     int N=n-1;
64     while(N--) {
65         int u,v;
66         scanf("%lld%lld",&u,&v);
67         AddEdge(u,v);
68         AddEdge(v,u);
69     }
70     dfs1(s,s);
71     dfs2(s,s);
72     while(m--) {
73         int x,y;
74         scanf("%lld%lld",&x,&y);
75         int ans=query(x,y);
76         cout<<ans<<endl;
77     }
78 }

我的CSDN博客

 

posted on 2022-07-25 11:16  Larryhui  阅读(136)  评论(0)    收藏  举报