二叉树的基础操作总结(C语言)

 本程序调试时使用的二叉树如图:

​​​​​​​

​
#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;		
}

​

 

 二叉树的高度递归过程:

二叉树的层次遍历过程: 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值