本程序调试时使用的二叉树如图:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<queue>
typedef struct Tree
{
int data;//存放数据域
struct Tree* lchild;//遍历左子树指针
struct Tree* rchild;//遍历右子树指针
}Tree, * BitTree;
BitTree CreateLink()
{
int data;
int temp;
BitTree T;
scanf("%d", &data);//输入数据
temp = getchar(); //吸收空格
if (data == -1)
{
//输入-1 代表此节点下子树不存数据,也就是不继续递归创建
return NULL;
}
else
{
T = (BitTree)malloc(sizeof(Tree)); // 分配内存空间
T->data = data; //把当前输入的数据存入当前节点指针的数据域中
printf("请输入%d的左子树: ", data);
T->lchild = CreateLink(); //开始递归创建左子树
printf("请输入%d的右子树: ", data);
T->rchild = CreateLink(); //开始到上一级节点的右边递归创建左右子树
return T;//返回根节点
}
}
//先序遍历
void ShowXianXu(BitTree T)
{
if (T == NULL)//递归中遇到NULL,返回上一层节点
{
return;
}
printf("%d ", T->data);
ShowXianXu(T->lchild);//递归遍历左子树
ShowXianXu(T->rchild);//递归遍历右子树
}
//中序遍历
void ShowZhongXu(BitTree T)
{
if (T == NULL)//递归中遇到NULL,返回上一层节点
{
return;
}
ShowZhongXu(T->lchild);//递归遍历左子树
printf("%d ", T->data);
ShowZhongXu(T->rchild);//递归遍历右子树
}
//中序非递归遍历
void Inorder(BitTree T)
{
stack<BitTree>s;//建立一个栈,让所有根结点入栈
BitTree t = T;
while (t != NULL || !s.empty())
{
if (t)//若结点非空,则该结点就是一个根结点,让他入栈,然后继续遍历左子树
{
s.push(t);
t = t->lchild;
}
else
{//若该结点为空,说明其父结点就是最左边的左结点,让其出栈,然后遍历右子树
BitTree q = s.top();
cout << q->data << " ";
s.pop();
t = q->rchild;
}
}
}
//后序遍历
void ShowHouXu(BitTree T)
{
if (T == NULL)//递归中遇到NULL,返回上一层节点
{
return;
}
ShowHouXu(T->lchild); //递归遍历左子树
ShowHouXu(T->rchild); //递归遍历右子树
printf("%d ", T->data);
}
void ShowCengci(BitTree T)//层次遍历
{
if (T == NULL)
return;
std::queue<BitTree>q;//创建队列
q.push(T); //让根结点入队
while (!q.empty())
{
BitTree first = q.front();//保存队首的结点
printf("%d", first->data);//打印数据
q.pop(); //然后出队
if (first->lchild)//让队首结点的左子树入队
q.push(first->lchild);
if (first->rchild)//让队首结点的右子树入队
q.push(first->rchild);
}
}
void LevelorderTraversal(BitTree T) //用数组层次遍历
{
/*
层序遍历就是一层一层地输出,定义两个BitTree数组,a和b
a、b数组都是存的一层的所有结点,且a为输出的当前层,b为下一层
*/
if (!T)
return;
BitTree a[10000];
a[0] = T;//先放入根结点
int len = 1;//len记录当前层的结点数量
while (1)
{
if (len == 0)
return;
int pos = 0;
BitTree b[10000];
for (int i = 0; i < len; i++)
{
if (a[i] != NULL)//不为空输出
printf(" %d", a[i]->data);
if (a[i]->lchild != NULL)//如果它的左子树结点不为空,就存到b数组里
b[pos++] = a[i]->lchild;
if (a[i]->rchild != NULL)//如果它的右子树结点不为空,就存到b数组里
b[pos++] = a[i]->rchild;
}
len = pos;//更新下一层宽度,为下一次循环做准备
for (int i = 0; i < len; i++)//将下层的b赋给a,为下一次循环做准备
a[i] = b[i];
}
}
//计算结点个数
int BinaryTreeSize(BitTree T)
{
if (T == NULL)
return 0;
return (BinaryTreeSize(T->lchild) + BinaryTreeSize(T->rchild) + 1);
//其递归过程是:先一直左子树,直到走到最左边的叶子节点后,其左子树为NULL,返回数值0同时返回到该叶子结点
//然后走到该叶子结点的右子树,也为NULL,返回数值0。然后执行+1,返回到该叶子结点的父结点,继续走该父结点的右子树。
//循环执行这个过程。本质上仍然是后序遍历法,只是访问结点之后的操作不同
}
int size = 0;//全局变量计算结点的个数
void BinaryTreeSize_C(BitTree T)//全局变量计算结点个数
{
if (T == NULL)
return;
size++;//size累加放在前面,中间,后面都可以,本质上仍然是前序,中序,后序遍历法。
//其递归过程同上
BinaryTreeSize_C(T->lchild);
BinaryTreeSize_C(T->rchild);
}
//求二叉树叶子结点个数
int BinaryTreeLeafSize(BitTree T)
{//计算叶子结点个数的递归过程为:
//走到最左边叶子结点后,该叶子结点的左右子树都为NULL,遂返回1并回到了父结点
//然后走到了该父结点的右子树,也是一个叶子结点,遂也返回1并回到了该父结点
//该父结点的左右子树的返回值就是2了然后回到根节点,此时根结点的左子树返回值即为2
//然后走根结点的右子树,重复上述步骤
if (T == NULL)
return 0;
if (T->lchild == NULL && T->rchild == NULL)
return 1;
return BinaryTreeLeafSize(T->lchild) + BinaryTreeLeafSize(T->rchild);
}
int size1 = 0;//全局变量计算叶子结点个数
void BinaryTreeLeafSize_C(BitTree T)
{
if (T == NULL)
return;
if (T->lchild == NULL && T->rchild == NULL)//符合条件的就累加,其余同前序遍历
size1++;
BinaryTreeLeafSize_C(T->lchild);
BinaryTreeLeafSize_C(T->rchild);
}
//求二叉树的高度
int BinaryTreeHigh(BitTree T)
{//该函数递归的过程见图
if (T == NULL)
return 0;
int h1 = BinaryTreeHigh(T->lchild);
int h2 = BinaryTreeHigh(T->rchild);
return h1 > h2 ? h1 : h2 + 1;
}
//查找父结点
BitTree BinaryTreeFindParent(BitTree T, int n)
{
if (T == NULL || T->data == n)//T->data == n是因为要查找的结点可能是二叉树的根结点
return NULL;
//以该结点为父结点,分别查找其左右子树,若子树的data==n,则返回该父结点
//否则,继续到该父结点的左子树,按先序遍历的方式重复查找
if (T->lchild)
{
if (T->lchild->data == n)
return T;
}
if (T->rchild)
{
if (T->rchild->data == n)
return T;
}
BitTree ret = BinaryTreeFindParent(T->lchild, n);//遍历左子树
if (ret != NULL)//没查找到会返回空,查找到了会返回其父结点,用ret接收父结点
return ret;
ret = BinaryTreeFindParent(T->rchild, n);//遍历右子树
if (ret != NULL)
return ret;
return NULL;//左右子树都为NULL,返回给该父结点的父结点NULL,意为没有找到要找的数据
}
//求二叉树第k层的结点个数
int BinaryTreeLevelKSize(BitTree T, int k)
{
if (T == NULL)//若第k层为NULL,返回0
return 0;
if (k == 1)//k==1表示到达了第k层
return 1;
return BinaryTreeLevelKSize(T->lchild, k - 1) + BinaryTreeLevelKSize(T->rchild, k - 1);
}
//销毁二叉树
void BinaryTreeDestroy(BitTree T)//传入的参数是一个指向二叉树的指针
{
if (T == NULL)
return;
//要用后序遍历销毁,如果用前序或中序遍历的话,会导致根节点被销毁从而找不到后面的结点
BinaryTreeDestroy(T->lchild);
BinaryTreeDestroy(T->rchild);
free(T);
T = NULL;
}
int main()
{
BitTree S;
printf("请输入第一个节点的数据:\n");
S = CreateLink(); //接受创建二叉树完成的根节点
printf("先序遍历结果: \n");
ShowXianXu(S); //先序遍历二叉树
printf("\n中序遍历结果: \n");
ShowZhongXu(S); //中序遍历二叉树
printf("\n中序非递归遍历结果:\n);
Inorder(S); //中序非递归遍历二叉树
printf("\n后序遍历结果: \n");
ShowHouXu(S); //后序遍历二叉树
printf("\n层次遍历的结果:\n");
ShowCengci(S); //层次遍历二叉树
printf("\n用数组层次遍历的结果:\n");
LevelorderTraversal(S);
int n = BinaryTreeSize(S); //求二叉树的结点个数
printf("\n二叉树节点的个数为:%d", n);
BinaryTreeSize_C(S); //全局变量求二叉树的结点个数
printf("\n全局变量计算二叉树结点的个数为:%d", size);
int n1 = BinaryTreeLeafSize(S);//求二叉树的叶子结点个数
printf("\n二叉树叶子结点的个数为:%d", n1);
BinaryTreeLeafSize_C(S); //全局变量求二叉树的叶子结点个数
printf("\n全局变量计算二叉树叶子结点的个数为:%d", size1);
int n2 = BinaryTreeHigh(S); //求二叉树的高度
printf("\n二叉树的高度为:%d", n2);
int n3 = 6;
BitTree t = BinaryTreeFindParent(S, n3);//求二叉树的父结点
printf("\n%d的父结点为:%d", n3, t->data);
int n4 = BinaryTreeLevelKSize(S, 3); //求二叉树第k层有几个结点
printf("\n第3层有%d个结点",n4);
BinaryTreeDestroy(S); //销毁二叉树
return 0;
}