一、二叉树数的概念
1,概念
二叉树:一棵二叉树是结点的一个有限集合,该集合: 1. 或者为空 2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
![](https://img-blog.csdnimg.cn/d571aa2f6b384d5aa5e0ef49c8f5c36e.png)
注意:二叉树不存在度为3结点,它的子树有左右之分,次序不能跌倒,因此二叉树是有序数
特殊二叉数:
满二叉树:一个二叉树,如果其每一层的结点都达到最大值,即结点个数为2^k-1,k为二叉树层数,则该树为满二叉树。
完全二叉树:完全二叉树是由满二叉树引出,该树的最后一层结点没有达到最大值,其他层数结点都到达最大值,称为完全二叉树。
二、二叉树的性质
三、二叉树基本操作
1.二叉树结构
二叉树包括:根结点,左孩子,右孩子
typedef int DataType;
typedef struct Tree
{
DataType data; //定义结点值
struct Tree* left; //定义左孩子
struct Tree* right; //定义右孩子
}Tree;
2.二叉树创建
Tree*CreateTree()
{
Tree*T;
DataType x;
//输入结点的值
cin >> x;
//该节点为0,说明结点为空
if (x == 0)
{
T = NULL;
}
else
{
//为结点创建空间
T = (Tree*)malloc(sizeof(Tree));
if (T == NULL)
{
printf("空间申请失败!!!\n");
return NULL;
}
//为结点赋值
T->data = x;
//递归创建左右子树
T->left = CreateTree();
T->right = CreateTree();
}
return T;
}
3.二叉树遍历
(1)前序遍历
特点:先访问根结点,再遍历左子树,最后遍历右子树
void PreBinaryTree(Tree*T)
{
if (T == NULL)
{
return;
}
cout << T->data << " ";
PreBinaryTree(T->left);
PreBinaryTree(T->right);
}
(2)中序遍历
特点:先遍历左子树,再访问根结点,最后遍历右子树
void InOrderTree(Tree* T)
{
if (T == NULL)
{
return;
}
InOrderTree(T->left);
cout << T->data << " ";
InOrderTree(T->right);
}
(3)后序遍历
特点:先遍历左子树再遍历右子树,最后访问根结点
void InOrderTree(Tree* T)
{
if (T == NULL)
{
return;
}
InOrderTree(T->left);
cout << T->data << " ";
InOrderTree(T->right);
}
(4)层序遍历
层序遍历相对于前三种遍历,需要用队列进行辅助操作,具体操作:定义一个队列,首先将二叉树的第一个结点入队,while循环判断该队列是否为空,不为空的话,则先进行出队,然后判断该树的左又子树是否为空,不为空则入队。
void LevelTree(Tree*T)
{
//定义一个队列
queue<Tree*>q;
Tree*t=T;
//将二叉树第一个结点入队
q.push(t);
while (!q.empty())
{
//将t指向队头元素
t = q.front();
//输出队头元素,出队
cout << t->data << " ";
q.pop();
//将左右孩子入队
if (t->left!=NULL)
{
q.push(t->left);
}
if (t->right!=NULL)
{
q.push(t->right);
}
}
}
4.二叉树结点个数
int BinaryTreeSize(Tree* T)
{
//如果树为空,返回0
if (T == NULL)
{
return 0;
}
//如果左子树和右子树都为空,说明该结点为叶子结点,返回1
if (T->left == NULL && T->right == NULL)
{
return 1;
}
//树的结点等于 左子树的结点 + 右子树的结点 + 根结点(1)
return 1 + BinaryTreeSize(T->left) + BinaryTreeSize(T->right);
}
5.二叉树叶子结点
int BinaryTreeLeafSize(Tree* T)
{
if (T == NULL)
{
return 0;
}
//左子树为空且右子树为空,说明该结点为叶子结点,返回1
if (T->left == NULL && T->right == NULL)
{
return 1;
}
//树的叶子结点个数等于 左子树的叶子结点 + 右子树的叶子结点
return BinaryTreeLeafSize(T->left) + BinaryTreeLeafSize(T->right);
}
6.二叉树第k层结点个数
int BinaryTreeLevelKSize(Tree* T, int k)
{
//树为空或者k的值小于1时,不存在,返回0
if (T == NULL || k < 1)
{
return 0;
}
//层数为1时,返回1
if (k == 1)
{
return 1;
}
//第k层结点个数等于 左子树的第k-1层结点个数 + 右子树的第k-1层结点个数
return BinaryTreeLevelKSize(T->left,k-1) + BinaryTreeLevelKSize(T->right,k - 1);
}
7.二叉树的高度
int max(int a, int b)
{
return a > b ? a : b;
}
//二叉树的高度
int BinaryTreeHeight(Tree* T)
{
//树为空,返回0
if (T == NULL)
{
return 0;
}
//树的高度等于 左子树的高度和右子树高度的最大值 + 1
return 1 + max(BinaryTreeHeight(T->left), BinaryTreeHeight(T->right));
}
8.二叉树寻找结点
Tree* BinaryTreeFind(Tree*T,DataType x)
{
if (T == NULL)
{
return NULL;
}
//寻找到,返回
if (T->data == x)
{
return T;
}
//查找左子树,如果左子树中有与之相同是结点,则返回,否则查找右子树
Tree*t=BinaryTreeFind(T->left, x);
if (t != NULL)
{
return t;
}
return BinaryTreeFind(T->right, x);
}
9.二叉树的销毁
销毁的时候需传递二级指针,因为需要改变指针的指向,要传递指针的地址
在销毁时,不能先销毁根结点,因为其左子树和右子树是通过根结点访问的,如果根结点先被销毁,则其左子树和右子树在后序程序中无法被访问,会出现错误。
void BinaryTreeDestory(Tree** T)
{
if (*T == NULL)
{
return;
}
BinaryTreeDestory(&(*T)->left);
BinaryTreeDestory(&(*T)->right);
free(*T);
*T == NULL;
}