< div id=”article_content” class=”article_content clearfix”>

二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒。

树的术语:

Name Function
路径 顺着连接点的边从一个节点走向另一个节点,所经过的节点的顺序排列就称为路径。
树顶端的节点就称为根,一棵树只有一个根,如果要把一个节点和边的集合定义为树,那么从根到其他任何一个节点都必须有一条路径。
父节点 每个节点(除了根)都恰好有一条边向上连接到另一个节点,上面的节点就称为下面节点的“父节点”。
子节点 每个节点都可能有一条或多条边向下连接其他节点,下面的这些节点就称为它的“子节点”。
叶节点 没有子节点的节点称为“叶子节点”或简称“叶节点”。树只能有一个根,但是可以有很多叶节点
子树 每个节点都可以作为子树的根,它和它所有的子节点,子节点的子节点等都含在子树中。
访问 当程序控制流程到达某个节点的时候,就称为“访问”这个节点,通常是为了在这个节点处执行某种操作,例如查看节点某个数据字段的值或者显示节点。
遍历 遍历树意味着要遵循某种特定的顺序访问树中的所有节点。
一个节点的层数是指从根开始到这个节点有多少“代”。
关键字 可以看到,对象中通常会有一个数据域被指定为关键字值。这个值通常用于查询或者其他操作。
二叉树 如果树中的每个节点最多只能有两个子节点,这样的树就称为“二叉树”。

满二叉树:在一棵二叉树中,如果所有分支结点都有左孩子和右孩子结点,并且叶子结点都集中在二叉树的最下层,这样的树叫做满二叉树
如:
在这里插入图片描述
根据满二叉树的定义,得到其特点为:

  1. 叶子只能出现在最下一层。
  2. 非叶子结点度一定是2.
  3. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。

完全二叉树:若二叉树中最多只有最下面两层的结点的度数可以小于2,并且最下面一层的叶子结点都是依次排列在该层最左边的位置上,则称为完全二叉树。
如:
在这里插入图片描述
满二叉树与完全二叉树的区别:满二叉树是完全二叉树的特例,因为满二叉树已经满了,而完全并不代表满。所以形态你也应该想象出来了吧,满指的是出了叶子节点外每个节点都有两个孩子,而完全的含义则是最后一层没有满,并没有满。 结合完全二叉树定义得到其特点:

  1. 叶子结点只能出现在最下一层和次下层(满二叉树继承而来)
  2. 最下层叶子结点一定集中在左 部连续位置。
  3. 倒数第二层,如有叶子节点,一定出现在右部连续位置。
  4. 同样结点树的二叉树,完全二叉树的深度最小(满二叉树也是对的)。

一般二叉树的性质:

  • 左节点下标是其父节点的二倍,右节点的下标是其父节点的二倍加一(左节点加一)。
  • 第n层的节点个数最多为2n-1。
  • 前n层的节点个数最多为2n-1。
  • 对于任何一棵非空的二叉树,如果叶节点个数为n0,度数为2的节点个数为n2,则有: n0 = n2 + 1。
    4的证明:在一棵二叉树中,除了叶子结点(度为0)之外,就剩下度为2(n2)和1(n1)的结点了。则树的结点总数为T = n0+n1+n2;在二叉树中结点总数为T,而连线数为T-1.所以有:n0+n1+n2-1 = 2*n2 +n1;最后得到n0 = n2+1;
    在这里插入图片描述

完全二叉树的性质:

  • 具有n个结点的完全二叉树的深度为log2n+1.
    证明: 满二叉树是完全二叉树,对于深度为k的满二叉树中结点数量是2k-1 = n,完全二叉树结点数量肯定最多2k-1,同时完全二叉树倒数第二层肯定是满的(倒数第一层有结点,那么倒是第二层序号和满二叉树相同),所以完全二叉树的结点数最少大于少一层的满二叉树,为2k-1-1。
    根据上面推断得出: 2k-1-1< n=<2k\-1,因为结点数Nn为整数那么n<=2k\-1可以推出n<=2k ,n>2(k-1)-1可以推出 n>=2k-1,所以2k-1k 。即可得k-1<=log2n
  • 如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有
  • 如果i=1,则节点是二叉树的根,无双亲,如果i>1,则其双亲节点为[i/2],向下取整
  • 如果2i>n那么节点i没有左孩子,否则其左孩子为2i
  • 如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1
    在这里插入图片描述

在上图中验证 第一条:
当i=1时,为根节点。当i>1时,比如结点为7,他的双亲就是7/2= 3;结点9双亲为4. 第二条:
结点6, 6* 2 = 12>10,所以结点6无左孩子,是叶子结点。结点5,5*2 = 10,左孩子是10,结点4,为8. 第三条:
结点5,2*5+1>10,没有右孩子,结点4,则有右孩子。 二叉树可以用数组建立也可以用结构体建立。
数组建立二叉树://前序遍历方式建立二叉树

1
2
3
4
5
6
7
8
9
10
11
12
char s[MAXn]; //开辟数组用来模拟存储二叉树
void scan(int n) //n为节点下标 (从1开始)
{
char c;
cin>>c;
s[n]=c;
if(c!='#') //#表示空节点
{
scan(n*2); //左节点(上面提到了,左节点下坐标=其父节点的二倍
scan(n*2+1); //右节点
}
}

结构体建立二叉图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct node{
node *l; //左节点
node *r; //右节点
char c;
node()
{
l=r=NULL; //初始化
}
};
void scan(node *& root)
{
char c;
cin>>c;
if(c!='#')
{
root=new node; //创建一个新的node型的变量,变量名为root
root->c=c;
scan(root->l);
scan(root->r);
}
}

上述二种代码输入: HDB#A##C##G#FE###
构造出的二叉图如下:
在这里插入图片描述
数组二叉树的遍历:

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
void qian(int n) //n为节点下标 从一开始
{ //前序遍历 顺序:根 左 右
if(s[n]!='#')
{
cout<<s[n];
qian(n*2);
qian(n*2+1);
}
return ;
}
void zhong(int n)
{ //中序遍历 顺序:左 根 右
if(s[n]=='#')
return;
zhong(n*2);
cout<<s[n];
zhong(n*2+1);
return ;
}
void hou(int n)
{ //后序遍历 顺序:左 右 根
if(s[n]!='#')
{
hou(n*2);
hou(n*2+1);
cout<<s[n];
}
return ;
}

结构体二叉树遍历:

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
void qian(node *root)
{ //前序遍历 顺序:根 左 右
if(root)
{
cout<<root->c;
qian(root->l);
qian(root->r);
}
}
void zhong(node *root)
{ //中序遍历 顺序:左 根 右
if(root)
{
zhong(root->l);
cout<<root->c;
zhong(root->r);
}
}
void hou(node *root)
{ //后序遍历 顺序:左 右 根
if(root)
{
hou(root->l);
hou(root->r);
cout<<root->c;
}
}

数组二叉树遍历代码:

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
#include <cstdio>
#include <stack>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;

using namespace std;
//const int MAXn=1e4+5;
//const int mod=;
char s[MAXn];
void scan(int n)
{
char c;
cin>>c;
s[n]=c;
if(c!='#')
{
scan(n*2);
scan(n*2+1);
}
}
void qian(int n)
{
if(s[n]!='#')
{
cout<<s[n];
qian(n*2);
qian(n*2+1);
}
return ;
}
void zhong(int n)
{
if(s[n]=='#')
return;
zhong(n*2);
cout<<s[n];
zhong(n*2+1);
return ;
}
void hou(int n)
{
if(s[n]!='#')
{
hou(n*2);
hou(n*2+1);
cout<<s[n];
}
return ;
}
int main()
{
scan(1);
qian(1);
cout<<endl;
zhong(1);
cout<<endl;
hou(1);
cout<<endl;
return 0;
}

结构体二叉树遍历代码:

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
#include <cstdio>
#include <stack>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;

using namespace std;
//const int MAXn=1e4+5;
//const int mod=;
struct node{
node *l;
node *r;
char c;
node()
{
l=r=NULL;
}
};
void scan(node *& root)
{
char c;
cin>>c;
if(c!='#')
{
root=new node;
root->c=c;
scan(root->l);
scan(root->r);
}
}
void qian(node *root)
{
if(root)
{
cout<<root->c;
qian(root->l);
qian(root->r);
}
}
void zhong(node *root)
{
if(root)
{
zhong(root->l);
cout<<root->c;
zhong(root->r);
}
}
void hou(node *root)
{
if(root)
{
hou(root->l);
hou(root->r);
cout<<root->c;
}
}
int main()
{
node *root;
scan(root);
qian(root);
cout<<endl;
zhong(root);
cout<<endl;
hou(root);
cout<<endl;
return 0;
}

评论




博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议

载入天数...载入时分秒... 本站使用 Volantis 作为主题 鲁ICP备-20012065号