概述
二叉树(Binary Tree)是n (n>0)个结点所构成的集合,它或为空树( n=0);或为非空树。对于非空树T满足:
1)有且仅有一个称为根的结点;
2)除根结点以外,其余结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身都是二叉树。
1.初始化
此处对于二叉树的初始化需要利用到递归的特性,'#'代表的是空节点,这将不会再建立新的子树
如下图,若要存储该树,则需要输入123##4##56### ,最后一个#代表的是5节点的右子树为空
typedef struct Bnode
{
char data;
Bnode* lchild, * rchild;
}Bnode, * BTree;
void initBTree(BTree& T)
{
char ch;
cin >> ch;
if (ch == '#')
{
T = NULL;
}
else
{
T = new Bnode; //建立新的节点
T->data = ch;
initBTree(T->lchild); //建立左子树
initBTree(T->rchild); //建立右子树
}
2.递归先序
按照根的访问顺序不同,根在前面称为先序遍历(DLR),根在中间称为中序遍历(LDR),根在最后称为后序遍历(LRD)。
算法步骤:
先序遍历是指先访问根,然后先序遍历左子树,再先序遍历右子树,即 DLR。
void recursion_F(BTree& T)
{
if (T == nullptr)
{
return;
}
cout << T->data << " ";
recursion_F(T->lchild);
recursion_F(T->rchild);
}
3.递归中序
和先序思想一致,不过是先访问左子树,再根,再右子树.
void recursion_M(BTree& T)
{
if (T == NULL)
{
return;
}
recursion_M(T->lchild);
cout << T->data << " ";
recursion_M(T->rchild);
}
4.递归后序
先左再右再根
void recursion_L(BTree& T)
{
if (T == NULL)
{
return;
}
recursion_L(T->lchild);
recursion_L(T->rchild);
cout << T->data << " ";
}
5.层次遍历
思想:
根节点先入队,如果队列不为空,则该根节点的孩子节点全部入队,没有就算了,首先入的是左孩子,再右孩子.判断队列不为空,继续出队,该左孩子出队后,其左孩子的左孩子与右孩子入队,如果没有就算了,如此反复,知道队列为空结束.
bool level_traverse(BTree T)
{
BTree e; //保留节点的数据
if (T == NULL)
{
return false;
}
queue<BTree>Q;
Q.push(T);
while (!Q.empty())
{
e = Q.front();
Q.pop();
cout << e->data << " ";
if (e->lchild != NULL)
{
Q.push(e->lchild);
}
if (e->rchild != NULL)
{
Q.push(e->rchild);
}
}
return true;
}
6.树的深度
思想:
对于人来说,树的深度就是数一数树的层数,上图的深度就为3,可是计算机却不能如此计算,拿一个最简单的二叉树举例.
如果节点的度数为0,那么深度为0+1,这就是为什么当节点为空要返回0的原因,该根节点的左子树深度为1,右子树深度为2,比较哪个大,谁大就+1 那么该值就是树的深度
int Depth(BTree T)
{
int m, n;
if (T == NULL)
{
return 0;
}
else
{
m = Depth(T->lchild);//左子树深度
n = Depth(T->rchild);//右子树深度
if (m > n)
{
return m + 1;
}
else
{
return n + 1;
}
}
}
7.叶子节点
利用递归特性找到树的最底层(叶子节点),判断是否为叶子节点的方法就是看他的左右子树是否为空,是就记录下这是个叶子节点返回1,给上一次递归的代码
int Leaf_Node(BTree T)
{
if (T == NULL)
{
return 0;
}
else
{
if (T->lchild == NULL && T->rchild == NULL)
{
return 1;
}
else
{
return Leaf_Node(T->lchild) + Leaf_Node(T->rchild);
}
}
}
8.节点总数
举一个简单的例子
左孩子的左右子树都为空,所以左孩子这棵树的节点个数为0(左)+0(右)+1,剩下来的复杂树就交给递归好了
int Calculate_BT_Node(BTree T)
{
if (T == NULL)
{
return 0;
}
else
{
return Calculate_BT_Node(T->lchild) + Calculate_BT_Node(T->rchild) + 1;
}
}
9.先序序列与中序遍历还原二叉树
想要写出代码,首先需要自己了解怎样还原才行
1.根据先序找到根节点
2.在中序的根节点左边为左子树,右边为右子树
3.找到左子树的根左右
4.找到右子树的根左右
BTree F_M_CreatBTree(char* pre, char* mid, int len)
{
if (len == 0)//当序列长度为0,说明已经还原完成
{
return NULL;
}
char ch = pre[0]; 记录根节点
int index = 0; 记录根节点在中序的位置
while (mid[index] != ch)
{
index++;
}
BTree T = new Bnode; // 找到了根节点,创建根节点
T->data = ch;
T->lchild = F_M_CreatBTree(pre + 1, mid, index); //左子树的递归
T->rchild = F_M_CreatBTree(pre + index + 1, mid + index + 1, len - index - 1);//右子树的递归
return T;
}
10后序序列与中序序列还原二叉树
和9是基本一致不过多赘述,自己画个图就理解了
BTree L_M_CreatBTree(char* last, char* mid, int len)
{
if (len == 0)
{
return NULL;
}
char ch = last[len - 1];
int index = 0;
while (mid[index] != ch)
{
index++;
}
BTree T = new Bnode;
T->data = ch;
T->lchild = L_M_CreatBTree(last, mid, index);
T->rchild = L_M_CreatBTree(last + index, mid + index + 1, len - index - 1);
return T;
}
完整代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include <queue>
using namespace std;
typedef struct Bnode
{
char data;
Bnode* lchild, * rchild;
}Bnode, * BTree;
void initBTree(BTree& T)
{
char ch;
cin >> ch;
if (ch == '#')
{
T = NULL;
}
else
{
T = new Bnode;
T->data = ch;
initBTree(T->lchild);
initBTree(T->rchild);
}
}
void recursion_F(BTree& T)
{
if (T == nullptr)
{
return;
}
cout << T->data << " ";
recursion_F(T->lchild);
recursion_F(T->rchild);
}
void recursion_M(BTree& T)
{
if (T == NULL)
{
return;
}
recursion_M(T->lchild);
cout << T->data << " ";
recursion_M(T->rchild);
}
void recursion_L(BTree& T)
{
if (T == NULL)
{
return;
}
recursion_L(T->lchild);
recursion_L(T->rchild);
cout << T->data << " ";
}
bool level_traverse(BTree T)
{
BTree e;
if (T == NULL)
{
return false;
}
queue<BTree>Q;
Q.push(T);
while (!Q.empty())
{
e = Q.front();
Q.pop();
cout << e->data << " ";
if (e->lchild != NULL)
{
Q.push(e->lchild);
}
if (e->rchild != NULL)
{
Q.push(e->rchild);
}
}
return true;
}
BTree F_M_CreatBTree(char* pre, char* mid, int len)
{
if (len == 0)
{
return NULL;
}
char ch = pre[0];
int index = 0;
while (mid[index] != ch)
{
index++;
}
BTree T = new Bnode;
T->data = ch;
T->lchild = F_M_CreatBTree(pre + 1, mid, index);
T->rchild = F_M_CreatBTree(pre + index + 1, mid + index + 1, len - index - 1);
return T;
}
void F_M_Test(BTree& T)
{
int n = 0;
char pre[100], mid[100];
cout << "请输入二叉树有多少元素" << endl;
cin >> n;
cout << "请输入先序序列" << endl;
for (int i = 0; i < n; i++)
{
cin >> pre[i];
}
cout << "请输入中序序列" << endl;
for (int i = 0; i < n; i++)
{
cin >> mid[i];
}
T = F_M_CreatBTree(pre, mid, n);
cout << "还原后的二叉树后序序列为:" << endl;
recursion_L(T);
}
BTree L_M_CreatBTree(char* last, char* mid, int len)
{
if (len == 0)
{
return NULL;
}
char ch = last[len - 1];
int index = 0;
while (mid[index] != ch)
{
index++;
}
BTree T = new Bnode;
T->data = ch;
T->lchild = L_M_CreatBTree(last, mid, index);
T->rchild = L_M_CreatBTree(last + index, mid + index + 1, len - index - 1);
return T;
}
void L_M_Test(BTree& T)
{
int n = 0;
char last[100], mid[100];
cout << "请输入有多少元素" << endl;
cin >> n;
cout << "请输入后序序列" << endl;
for (int i = 0; i < n; i++)
{
cin >> last[i];
}
cout << "请输入中序序列" << endl;
for (int i = 0; i < n; i++)
{
cin >> mid[i];
}
T = L_M_CreatBTree(last, mid, n);
cout << "还原后的二叉树先序序列为:" << endl;
recursion_F(T);
}
int Depth(BTree T)
{
int m, n;
if (T == NULL)
{
return 0;
}
else
{
m = Depth(T->lchild);
n = Depth(T->rchild);
if (m > n)
{
return m + 1;
}
else
{
return n + 1;
}
}
}
void Depth_Test(BTree T)
{
int ret = Depth(T);
cout << "树深度为:" << endl << ret << endl;
}
int Leaf_Node(BTree T)
{
if (T == NULL)
{
return 0;
}
else
{
if (T->lchild == NULL && T->rchild == NULL)
{
return 1;
}
else
{
return Leaf_Node(T->lchild) + Leaf_Node(T->rchild);
}
}
}
void Leaf_Node_Test(BTree T)
{
int ret = Leaf_Node(T);
cout << "叶子数为:" << endl << ret << endl;
}
int Calculate_BT_Node(BTree T)
{
if (T == NULL)
{
return 0;
}
else
{
return Calculate_BT_Node(T->lchild) + Calculate_BT_Node(T->rchild) + 1;
}
}
void Calculate_BT_Node_Test(BTree T)
{
int ret = Calculate_BT_Node(T);
cout << "节点总数为:" << endl << ret << endl;
}
void show_menu()
{
cout << "1.先序遍历" << endl;
cout << "2.中序遍历" << endl;
cout << "3.后序遍历" << endl;
cout << "4.层次遍历" << endl;
cout << "5.计算二叉树深度" << endl;
cout << "6.计算二叉树叶子数" << endl;
cout << "7.计算二叉树节点总数" << endl;
cout << "8.先序序列与中序遍历还原二叉树" << endl;
cout << "9.后序序列与中序序列还原二叉树" << endl;
cout << "------------------------------------" << endl;
cout << "请输入二叉树,#表示无节点" << endl;
}
int main()
{
show_menu();
BTree T;
initBTree(T);
int select = 0;
while (true)
{
cin >> select;
switch (select)
{
case 1:
recursion_F(T);
cout << endl;
break;
case 2:
recursion_M(T);
cout << endl;
break;
case 3:
recursion_L(T);
cout << endl;
break;
case 4:
level_traverse(T);
break;
case 5:
Depth_Test(T);
break;
case 6:
Leaf_Node_Test(T);
break;
case 7:
Calculate_BT_Node_Test(T);
break;
case 8:
F_M_Test(T);
break;
case 9:
L_M_Test(T);
default:
break;
}
}
system("pause");
return EXIT_SUCCESS;
}