二叉树链式结构的实现

本文详细介绍了如何实现二叉树的链式结构,包括前序、中序、后序和层序遍历算法,以及计算叶子节点、第k层节点个数和判断二叉树是否为完全二叉树的方法。
摘要由CSDN通过智能技术生成

前面我们对二叉树的顺序结构(堆:一种二叉树)进行了一个实现,这里,我们将对二叉树的链式结构进行一个实现。

1. 二叉树的基本功能

实现一颗二叉树,我们首先要知道二叉树的基本功能是什么,这里我列举了一些简单的功能:

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 cv  
BTNode* BinaryTreeCreate(BTDataType* a,  int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode** root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

2. 二叉树的基本实现

2.1. 二叉树的前序遍历

前序遍历也叫 dfs (深度优先遍历)这里我们先通过图示了解一下前序遍历:

这个遍历得到的结果就是 1->2->3->4->5->6 ,他先从 1 开始然后递归左子树到 2 然后递归左子树到 3 然后递归左子树到 NULL,由于左子树为NULL,所以左子树遍历完毕,然后以 3 为根节点遍历右子树,右子树也为空随即返回。这样以3为根节点的二叉树就遍历完毕。然后回到以 2 为根节点的树进行遍历,2 树的右子树也为NULL,随即返回。这样,以 1 为根节点的二叉树的左子树就遍历完毕。然后就开始遍历 1 树的右子树4 ,同样的先遍历 4 树的左子树 5 然后遍历4树的右子树 6 .这样一颗二叉树的前序遍历就完成了。二叉树的前序遍历总结几个字就是:  根->左->右  

这里附上参考代码,这里为了表示遍历到了NULL的节点,我将空节点打印为了“N” :

void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
        return;
	}
	else
	{
		printf("%c ", root->_data);
		BinaryTreePrevOrder(root->_left);
		BinaryTreePrevOrder(root->_right);
	}
}

2.2. 二叉树的中序遍历

知道了二叉树的前序遍历,二叉树的中序遍历也是比较简单的,这里附上图示:

中序遍历总结几个字就是: 左->根->右 

这里附上参考代码:

void BinaryTreeInOrder(BTNode* root)
{
	if (root)
	{
		BinaryTreeInOrder(root->_left);
		printf("%c ", root->_data);
		BinaryTreeInOrder(root->_right);
	}
	else
	printf("N ");
}

2.3 二叉树的后序遍历

后序遍历总结几个字就是: 左->右->根   。  通过前面两个遍历,这里看图应该能理解:

参考代码如下:

void BinaryTreePostOrder(BTNode* root)
{
	if (root)
	{
		BinaryTreePostOrder(root->_left);
		BinaryTreePostOrder(root->_right);
		printf("%c ",root->_data);
	}
	else
		printf("N ");
}

2.4 二叉树的层序遍历

前面我们了解到的二叉树都是递归式的遍历,这里我们将要了解二叉树的一种非递归遍历---层序遍历,层序遍历也叫 bfs (广度优先遍历)。广度优先遍历很简单理解,就是一层一层遍历,大概的遍历过程如下:

要实现层序遍历有多种方法,我们这里提供一种相对简单的方法。首先我们需要借助队列进行遍历,这里我们附上参考代码进行说明:

void BinaryTreeLevelOrder(BTNode* root)
{
	Queue Q;    //构建一个队列
	QueueInit(&Q);//初始化队列
	QueuePush(&Q, root);// 将头节点入队列
	int i = QueueSize(&Q);//i存储队列中数据个数
	while(QueueEmpty(&Q))//队列为空说明遍历完毕
	{
		while (i--)//i中存储了每一层的数据个数,按照i的值进行分层
		{
			BTNode* Front = QueueFront(&Q);
			QueuePop(&Q);//得到队列首元素并出队列
			if (Front->_left)//如果队列左子树不为空就继续入队列
				QueuePush(&Q, Front->_left);
			if (Front->_right)//右不为空就进队列
				QueuePush(&Q, Front->_right);
			printf("%c ", Front->_data);
		}
		i = QueueSize(&Q);//i每更新一次,就表明即将出队列的这一层有几个数据
	} 
	QueueDestroy(&Q);//遍历完毕,销毁队列
}

2.5 通过前序遍历生成二叉树

了解了二叉树的相关的遍历之后,我们就可以实现根据数组生成二叉树了,这里依然对代码进行讲解:

BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
	if (a[*pi] == '#')//如果为'#'就置空
	{
		(*pi)++;
		return NULL;
	}
	BTNode* tmp = (BTNode*)malloc(sizeof(BTNode));
	if (tmp == NULL)//其他字符就创造一个节点存储字符
	{
		perror("malloc fail");
		exit(-1);
	}
	tmp->_data = a[*pi];
	(*pi)++;
	tmp->_left = BinaryTreeCreate(a,pi );//根节点创造完毕就创造左子树
	tmp->_right = BinaryTreeCreate(a, pi);//左子树完了就创造右子树
	return tmp;
}

2.6 二叉树叶子节点的个数

叶子节点个数是比较好求得的,只要该节点的左右子节点都为空既是叶子节点,这个比较简单,代码如下:

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);
}

2.7 二叉树第 K 层节点个数

这里我们用递归的思想,他要第K层的节点个数,我们就把第让函数递归K次,等K为1的时候,函数就递归到了第K层,此时就判断他们是否为NULL,为NULL返回0,否则返回 1;这样左右相加最终就得到了第K层有多少节点。参考代码如下:

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
	return 1;
	return BinaryTreeLevelKSize(root->_left,k-1) + BinaryTreeLevelKSize(root->_right,k-1);
}

2.8 查找值为X的节点

这个是比较简单的,我们以前序遍历为例,这里用到了三目运算符,参考代码如下:

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	return BinaryTreeFind(root->_left, x) == NULL ? BinaryTreeFind(root->_right, x) : BinaryTreeFind(root->_left, x);
}

2.9 判断二叉树是否为完全二叉树

在实现这个代码的时候,我们不能以二叉树层数与个数的关系来判断,这样是有问题的。在这里一个正确的方式就是借助队列,我们用层序遍历的方式进行判断,这里我们还是对代码进行说明理解,参考代码如下:

int BinaryTreeComplete(BTNode* root)
{
	Queue qu;
	BTNode * cur;
	int tag = 0;
	QueueInit(&qu);
	QueuePush(&qu, root);
	while (!QueueIsEmpty(&qu))
	{
		cur = QueueTop(&qu);
		putchar(cur->_data);
		if (cur->_right && !cur->_left)
		{
			return 0;//左空右不空一定不是完全二叉树,返回 0
		}
		if (tag && (cur->_right || cur->_left))
		{
			return 0;//tag不为1说明前面出现了空节点,此时还有非空节点则一定不是完全二叉树
		}
		if (cur->_left)
		{
			QueuePush(&qu, cur->_left);//子节点不为空就入队列
		}
		if (cur->_right)
		{
			QueuePush(&qu, cur->_right);
		}
		else
		{
			tag = 1;//有的根出现了空节点把tag赋值为1
		}
		QueuePop(&qu);
	}
	QueueDestory(&qu);
	return 1;//是完全二叉树返回 1
}

3. 汇总:

这是二叉树几个功能的全部代码,函数声明代码在前面,基本功能的地方:

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 cv  
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
	if (a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* tmp = (BTNode*)malloc(sizeof(BTNode));
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	tmp->_data = a[*pi];
	(*pi)++;
	tmp->_left = BinaryTreeCreate(a,pi );
	tmp->_right = BinaryTreeCreate(a, pi);
	return tmp;
}
// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root)
	{
		BinaryTreeDestory(&(*root)->_left);
		BinaryTreeDestory(&(*root)->_right);
		free(*root);
		*root = NULL;
	}
	else
		return;
}
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (!root)
		return 0;
	return 1 + BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right);
}
// 二叉树叶子节点个数
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);
}
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
	return 1;
	return BinaryTreeLevelKSize(root->_left,k-1) + BinaryTreeLevelKSize(root->_right,k-1);
}
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	return BinaryTreeFind(root->_left, x) == NULL ? BinaryTreeFind(root->_right, x) : BinaryTreeFind(root->_left, x);
}
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
	}
	else
	{
		printf("%c ", root->_data);
		BinaryTreePrevOrder(root->_left);
		BinaryTreePrevOrder(root->_right);
	}
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root)
	{
		BinaryTreeInOrder(root->_left);
		printf("%c ", root->_data);
		BinaryTreeInOrder(root->_right);
	}
	else
	printf("N ");
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root)
	{
		BinaryTreePostOrder(root->_left);
		BinaryTreePostOrder(root->_right);
		printf("%c ",root->_data);
	}
	else
		printf("N ");
}
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue Q;
	QueueInit(&Q);
	QueuePush(&Q, root);
	int i = QueueSize(&Q);
	while(QueueEmpty(&Q))
	{
		while (i--)
		{
			BTNode* Front = QueueFront(&Q);
			QueuePop(&Q);
			if (Front->_left)
				QueuePush(&Q, Front->_left);
			if (Front->_right)
				QueuePush(&Q, Front->_right);
			printf("%c ", Front->_data);
		}
		i = QueueSize(&Q);
	} 
	QueueDestroy(&Q);
}
int BinaryTreeHight(BTNode* root)
{
	if (root == NULL)
		return 0;
	else
	{
		int i = BinaryTreeHight(root->_left );
		int j = BinaryTreeHight(root->_right);
		return i > j ? i+1 : j+1;
	}
}
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	Queue qu;
	BTNode * cur;
	int tag = 0;
	QueueInit(&qu);
	QueuePush(&qu, root);
	while (!QueueIsEmpty(&qu))
	{
		cur = QueueTop(&qu);
		putchar(cur->_data);
		if (cur->_right && !cur->_left)
		{
			return 0;
		}
		if (tag && (cur->_right || cur->_left))
		{
			return 0;
		}
		if (cur->_left)
		{
			QueuePush(&qu, cur->_left);
		}
		if (cur->_right)
		{
			QueuePush(&qu, cur->_right);
		}
		else
		{
			tag = 1;
		}
		QueuePop(&qu);
	}
	QueueDestory(&qu);
	return 1;
}

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何陈陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值