二叉树的概念及基本操作

一、二叉树概念

一颗二叉树是结点的一个有限集合,该集合:

        (1)为空

        (2)由一个根节点加上两棵称为左子树和右子树的二叉树组成

从上图可以看出:

        (1)二叉树不存在度大于2的结点

        (2)二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

二、特殊二叉树

 1、满二叉树:一个二叉树,如果每一层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树层数为k,且总结点数是2^k-1,则它就是满二叉树。

2、完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一 一对应时称为完全二叉树。要注意满二叉树是一种特殊的完全二叉树。

举例:

三、二叉树的性质

1、若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。

2、若规定根节点的层数为1,则深度为h的二叉树的最大结点数为2^h-1。

3、对任何一颗二叉树,如果度为0的叶子结点个数为n0,度为2的分支结点个数为n2,则有n0=n2+1。

4、若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1)(ps:2为底,n+1为对数)。

5、对于具有n个结点的完全二叉树,如果按照从上至下,从左至右的顺序对所有结点从0开始编号,则对于序号为i的结点有:

        (1)若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点

        (2)若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子

        (3)若2i+1<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

四、二叉树的基本操作

1、定义数据结构

typedef char DataType;

typedef struct BinaryTreeNode
{
	DataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

2、二叉树的遍历

(1)前序遍历----先访问根节点,再访问左子树,最后访问右子树

 对上述二叉树进行前序遍历得到的序列为:123456

//前序遍历递归方法
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
		return;
	printf("%c ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}

中序遍历和后序遍历与前序遍历大同小异,只需注意访问顺序即可

(2)中序遍历----先访问左子树,再访问根节点,最后访问右子树

对上述二叉树进行中序遍历得到的序列为:321546

// 中序遍历递归方法
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreeInOrder(root->left);
	printf("%c ", root->data);
	BinaryTreeInOrder(root->right);
}

(3)后序遍历----先访问左子树,再访问右子树,最后访问根节点

对上述二叉树进行后序遍历得到的序列为:325641

// 后序遍历递归方法
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%c ", root->data);
}

3、通过前序遍历构建二叉树

给出二叉树前序遍历序列(NULL用空格或者其他字符代替)

//创建新节点
BTNode* _BuyBTNode(DataType data)
{
	BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
	if (newNode == NULL)
	{
		printf("_BuyBTNode:malloc失败\n");
		exit(0);
	}
	newNode->data = data;
	newNode->left = NULL;
	newNode->right = NULL;
	return newNode;
}
//利用前序遍历构建二叉树
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* _BinaryTreeCreate(DataType* a, int n, int* pi)
{
	if (*pi < n && a[*pi] != '#')
	{
		BTNode* newNode = _BuyBTNode(a[*pi]);
		(*pi)++;
		newNode->left = _BinaryTreeCreate(a, n, pi);
		(*pi)++;
		newNode->right = _BinaryTreeCreate(a, n, pi);
		return newNode;
	}
	return NULL;
}
BTNode* BinaryTreeCreate(DataType* a, int n)
{
	int index = 0;
	return _BinaryTreeCreate(a, n, &index);
}

4、层序遍历

层序遍历就是对二叉树逐层访问。

对上述二叉树进行层序遍历得到的序列为:124356

实现思想:通过利用队列先进先出的性质,先将根节点入队,当队列不为空时,弹出队首元素,将元素的左右孩子入队(左右孩子不为空时),直到队列为空,即遍历结束。

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	if (root == NULL)
		return;
	Queue q;
	//创建队列
	QueueCreate(&q);
	//将根节点入队
	QueuePush(&q, root);
	//循环,弹出队首元素,并将队首元素的左孩子与右孩子入队
	while (!QueueEmpty(&q))
	{
		BTNode* pcur = QueueGetFront(&q)->data;
		printf("%c ", pcur->data);
		if (pcur->left != NULL)
			QueuePush(&q, pcur->left);
		if (pcur->right != NULL)
			QueuePush(&q, pcur->right);
		QueuePop(&q);
	}
	QueueDestroy(&q);
}

5、其他操作

结合二叉树的性质实现

(1)二叉树节点个数

根节点(1个)+左子树节点个数+右子树节点个数。遇到NULL时返回0。

 

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

(2)二叉树高度

根节点高度(1)+Max(左子树高度,右子树高度)。遇到NULL时返回0。

 

//二叉树高度
int BinaryTreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int LeftHeight = BinaryTreeHeight(root->left);
	int RightHeight = BinaryTreeHeight(root->right);
	return	LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}

(3)二叉树叶子节点个数

叶子节点性质:左右子树都为NULL。

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if ((root->left == NULL) && (root->right == NULL))
		return 1;
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

(4)二叉树第k层节点个数

给出层数k,若k>0则向下遍历,直至k=1(到达目标层),若该节点为NULL,返回0,否则返回1。

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if ((k < 1) || (root == NULL))
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

(5)二叉树查找节点值为x的节点

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, DataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* res;
	(res = BinaryTreeFind(root->left, x)) || (res = BinaryTreeFind(root->right, x));
	return res;
}

(6)判断二叉树是否为完全二叉树

实现思想:找出第一个不满足满二叉树性质的节点,若该节点只有右子树没有左子树,返回0。

否则,继续向下遍历,检查后续节点是否有左右子树,若有返回0,无返回1。

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	if (root == NULL)
		return 1;
	Queue q;
	QueueCreate(&q);
	QueuePush(&q, root);
	//标志是否找到第一个非满二叉树的节点
	int flag = 0;
	//1代表是完全二叉树,0代表不是
	int res = 1;
	while (!QueueEmpty(&q))
	{
		BTNode* pcur = QueueGetFront(&q)->data;
		QueuePop(&q);
		if (flag == 0)
		{
			if (pcur->left == NULL || pcur->right == NULL)
			{
				//当至少有一个孩子为空时,改节点为第一个非满二叉树节点
				flag = 1;
				if (pcur->left == NULL && pcur->right != NULL)
				{
					//当有右孩子无左孩子,res置0,退出循环
					res = 0;
					break;
				}
			}
			if (pcur->left != NULL)
				QueuePush(&q, pcur->left);
			if (pcur->right != NULL)
				QueuePush(&q, pcur->right);
		}
		else
		{
			if (pcur->left != NULL || pcur->right != NULL)
			{
				//后续节点如果有孩子,比不是完全二叉树
				res = 0;
				break;
			}
		}
	}
	QueueDestroy(&q);
	return res;
}

6、二叉树的销毁

形参为二级指针,若为一级指针,根节点销毁不了。

销毁时先销毁左右子树,若根节点先被销毁,左右子树无法被访问,出现错误。

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	assert(root != NULL);
	if (*root == NULL)
		return;
	BinaryTreeDestory(&(*root)->left);
	BinaryTreeDestory(&(*root)->right);
	free(*root);
	*root = NULL;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值