二叉树——链式结构的代码实现(包含前中后遍历的实现)

目录

二叉树的创建

构建一颗二叉树

二叉树的销毁

创建一个新结点

计算二叉树的结点个数

计算二叉树的叶子结点个数

计算二叉树第k层节点的个数

 二叉树查找值为x的节点

二叉树前序遍历 

二叉树中序遍历

二叉树的后序遍历

二叉树的层序遍历

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


二叉树的创建

根据二叉树的结构,我们用链表来链接每个结点的左右孩子,并且给每个结点定义一个数值。

如图所示:

代码如下:

typedef char BTDataType;//老样子 便于控制数据类型

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

构建一颗二叉树


// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	BTNode* nodeA = BuyNode('A');
	BTNode* nodeB = BuyNode('B');
	BTNode* nodeC = BuyNode('C');
	BTNode* nodeD = BuyNode('D');
	BTNode* nodeE = BuyNode('E');
	BTNode* nodeF = BuyNode('F');

	nodeA->left = nodeB;
	nodeA->right = nodeC;
	nodeB->left = nodeD;
	nodeC->left = nodeE;
	nodeC->right = nodeF;

	return nodeA;
}

二叉树的销毁

这里利用递归来进行销毁,先销毁除叶子节点的其他节点,然后再释放叶子节点。

代码如下:


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

创建一个新结点

如果要插入一个新结点的时候就可以很好的利用这个函数,方法跟链表中的创建新结点类似。


//创建一个新结点
BTNode* BuyNode(BTDataType x)
{
	BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
	if (newNode == NULL)
	{
		printf("malloc failed");
		exit(-1);
	}
	newNode->data = x;
	newNode->left = newNode->right = x;
	return newNode;
}

计算二叉树的结点个数

这里同样是利用递归来遍历每一个结点。

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
    //+1是因为还有自身的结点
}

计算二叉树的叶子结点个数

方法跟上一个结算结点个数类似,只不过要加一个判断条件,当左右孩子都为空时就找到了。


// 二叉树叶子节点个数
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层节点的个数

这里同样运用递归的方法来求,并且引入一个k的变量,当k=1时说明到这一层了,如果k!=1那么继续遍历下一层,同时让k-1。

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k >= 1);

	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)
	{
		return 1;
	}

	// root不等空,k也不等于1,说明root这颗树的第k节点在子树里面
	// 转换成求左右子树的第k-1等的节点数量
	return BinaryTreeLevelKSize(root->left, k - 1)
		+ BinaryTreeLevelKSize(root->right, k - 1);
}

 二叉树查找值为x的节点

这个就比较简单了,挨个遍历二叉树的所有结点,当找到哪一个结点的data=x的时候就返回该结点。

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* LeftRet = BinaryTreeFind(root->left, x);
    //这里最好赋值一下,要不到时候返回的时候还要进行递归会有巨大的时间损耗
	if (LeftRet->data == x)
		return LeftRet;
	BTNode* RightRet = BinaryTreeFind(root->right, x);
    //这里最好赋值一下,要不到时候返回的时候还要进行递归会有巨大的时间损耗
	if (RightRet->data == x)
		return RightRet;

	return NULL;
}

二叉树前序遍历 

前序遍历的意思其实很容易理解,就是以根左右的顺序遍历,这里我们运用递归的方法进行遍历,

中序遍历与后序遍历同样如此。

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

二叉树中序遍历


// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreePrevOrder(root->left);
	printf("%c ", root->data);
	BinaryTreePrevOreder(root->right);
}

二叉树的后序遍历


// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
	printf("%c ", root->data);
}

二叉树的层序遍历

这里我们要运用我们之前学习的队列,至于层序遍历其实就是一层一层的进行遍历,理解起来也没有很难。我们首先将二叉树的根节点给入队,如果需要出队数据的时候,需要出队的结点会让自身的左右孩子结点给带入到队列当中,所以我们在队列中存储的其实是二叉树的结点,而不是二叉树的值,如图所示:


// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	Queue q;//定义一个队列
	QueueInit(&q);//初始化队列
	QueuePush(&q, root);//将root结点插入
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		//保存结点的值 以便往后遍历
		QueuePop(&q);//出队头数据
		printf("%c ", front->data);//打印队头数据
		//队头出队后 将他的左右孩子入队
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}
	}
	printf("\n");
	QueueDestroy(&q);
}

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

完全二叉树的特点是前k-1层是一颗满二叉树,第k层的结点是连续的,那么我们得知一个特点,在对一棵二叉树进行层序遍历的时候如果出现空节点后,之后就不能在出现非空结点,若再次出现非空结点,那此二叉树就不是完全二叉树。

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
		{
			break;
			//遇到空再出循环 
			//因为只有完全二叉树遇到空之后就不会再遇到数据了
		}
		else
		{
			//如果不为空那就继续遍历
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
	}
	//遇到空以后,检查队列中剩下的结点
	//1、剩下的全是空,则是完全二叉树
	//2、剩下的有非空,则不是完全二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

袁百万

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

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

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

打赏作者

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

抵扣说明:

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

余额充值