1.二叉树
1.1二叉树定义
1.2二叉树定特点
1.2二叉树定五种基本的形态
1.3特殊二叉树
-
斜树:单边斜,
-
满二叉树
-
完全二叉树
完全二叉树的定义:若设二叉树的高度为h,除第h层外,其它各层(1~h-1)的结点数都达到最大个数,且第h层所有的节点都连续集中在最左边,这就是完全二叉树。
完全二叉树的特点:
2.二叉树的性质
-
在二叉树的第i层上至多有2^(i-1)个节点(i>=1)
-
深度为k的二叉树至多有 2^k-1 个节点 (k>=1)
-
对于任意一棵树T, 如果叶节点数量有n0个,度为2的节点数量有n2个,则n0=n2+1
推导过程: 假设度为1的节点个数为n1,那么树T的总结点数量为:n=n0+n2+n1;
从连接线的角度来看,总连接线数目 = 总结节点数-1 ,即 n-1; 而且总连接线数量 = n1 + 2*n2 (n1条线 + 度为2的节点必然拥有2个连接线);
那么有:n-1= n1 + 2*n2
所以:n0+n2+n1-1 = n1 +2 *n2
最后:n0 = n2+1
2.1二叉树的存储结构(顺序存储结构和链式存储结构)
-
二叉树顺序存储结构(二叉树直接用一个数组存储即可)
-
二叉树链式存储结构(二叉树直接用节点)
二叉树链表节点代码结构
2.1二叉树的遍历
-
前提:限定为从左至右访问
-
前序遍历规则:若为二叉树,则空操作返回,否则,先访问双亲节点,先前序遍历左子树,再前序遍历右子树 (即:双亲节点-->左子树 --> 右子树)。遍历顺序如下:
-
中序遍历规则:若为二叉树,则空操作返回,先 访问双亲节点的左子树,然后访问双亲节点,最后访问右子树 (即:左节点--> 双亲节点--->右节点)。遍历顺序如下:
第7步小心:因为F没有左节点,
-
后序遍历规则:若为二叉树,则空操作返回,否则,从最左边的子节点开始, 从左到右的方式遍历左右子树,最后访问双亲节点。遍历顺序如下:
-
层序遍历:若为二叉树,则空操作返回,否则从树的第一层(即根节点开始) 从上而下逐层遍历,在同一层中,按从左到右的顺序对节点逐个访问。遍历顺序如下:
3.二叉树的建立与遍历算法
-
建立二叉树节点:包括数据域,左指针,右指针
-
创建一个二叉树
思路:
- 函数输入参数:树节点地址的引用
- 输入节点的data,以‘#’作为递归的结束方式
- 否则给节点创建一个内存空间,给节点的data赋值,递归左节点,再递归右节点
-
前序遍历二叉树
思路:
- 以节点等于NULL为结尾
- 输出根节点的data
- 递归遍历左子树
- 递归遍历右子树
-
中序遍历二叉树
思路:
- 以节点等于NULL为结尾
- 递归遍历左子树
- 输出根节点的data
- 递归遍历右子树
-
后序遍历二叉树
思路:
- 以节点等于NULL为结尾
- 递归遍历左子树
- 递归遍历右子树
- 输出根节点的data
完整代码:
在指针的语法上要注意:
在写函数参数 void creTree(Tnode* &T) //参数编写,这里要特别小心 Tnode* &T
Tnode * T; 是定义了一个Tnode类型的指针T,;
creTnode(T); //给函数传入一个地址
#define _CRT_SECURE_NO_DEPRECATE
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class Tnode
{
public:
char data;
Tnode* lnext;
Tnode* rnext;
};
void creTree(Tnode* &T) //注意,这里的参数,不是直接传入地址,而是传入地址的引用!!否则会无法访问T地址
{
char c;
cin >> c;
if (c == '#') //递归结束标志
{
T = NULL; //将树的叶节点赋值NULL
}
else
{
T = (Tnode*)malloc(sizeof(Tnode));
T->data = c;
creTree(T->lnext);
creTree(T->rnext);
}
}
void PreTrav(Tnode* &T)//注意,这里的参数,不是直接传入地址,而是传入地址的引用!!否则会无法访问T地址,前序遍历输出
{
if (T)
{
cout << T->data;
PreTrav(T->lnext);
PreTrav(T->rnext);
}
}
int main()
{
std::cout << "Hello World!\n";
Tnode* T;
//前序遍历二叉树的方式进行输入:测试例子AB#CD##E##F#GH###
creTree(T);
PreTrav(T);
}
对应的二叉树为:
输出结果: