数据结构 - 二叉树的实现


前言

二叉树的结构特征在这节介绍了,这里就直接实现一个二叉树
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、二叉树结构体的创建

这里用二叉链。

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* leftChild;		//左孩子
	struct BinaryTreeNode* rightChild;		//右孩子
	BTDataType data;						//数据
}BTNode;

二、手动构建二叉树

1.开辟二叉树节点

BTNode* CreateTreeNode(BTDataType x)
{
	BTNode* NewNode = (BTNode*)malloc(sizeof(BTNode));
	if (NewNode == NULL)
	{
		perror("CreateTreeNode malloc fail");
		return NULL;
	}

	NewNode->data = x;
	NewNode->leftChild = NULL;
	NewNode->rightChild = NULL;
	
	return NewNode;
}

2.创建节点并链接

代码如下(示例):

	BTNode* A = CreateTreeNode('A');
	BTNode* B = CreateTreeNode('B');
	BTNode* C = CreateTreeNode('C');
	BTNode* D = CreateTreeNode('D');
	BTNode* E = CreateTreeNode('E');
	BTNode* F = CreateTreeNode('F');

	A->leftChild = B;
	A->rightChild = C;
	B->leftChild = D;
	B->rightChild = E;
	C->leftChild = F;

三、二叉树的一些接口实现

前序遍历

前序遍历:访问根节点的操作发生在遍历其左右子树之前。(根->左->右)

void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	printf("%c ", root->data);
	PrevOrder(root->leftChild);
	PrevOrder(root->rightChild);
}

中序遍历

中序遍历:访问根节点的操作发生在遍历其左右子树之中。(左->根->右)

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	InOrder(root->leftChild);
	printf("%c ", root->data);
	InOrder(root->rightChild);
}

后序遍历

中序遍历:访问根节点的操作发生在遍历其左右子树之后。(左->右->根)

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	PostOrder(root->leftChild);
	PostOrder(root->rightChild);
	printf("%c ", root->data);

}

层序遍历

层序遍历:自上而下、自左到右逐层访问树的节点的过程就是层序遍历。
这里要用到队列,但是c语言库本身中又没有,所以我们把以前写过的直接拿过来用
思路:第一个节点尾插到队列,然后保存下来,在头删,打印保存下来的值,接着把左右孩子尾插进去,再把左孩子节点删除,尾插左孩子节点的下两个,以此类推,直到队列为空就终止循环

void TreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root != NULL)
	{
		QueuePushBack(&q, root);
	}

	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePopFront(&q);

		printf("%c ", front->data);
		if (front->leftChild)
		{
			QueuePushBack(&q, front->leftChild);
		}

		if (front->rightChild)
		{
			QueuePushBack(&q, front->rightChild);
		}
	}

	QueueDestroy(&q);
}

二叉树的销毁

这里传的是一级指针,不能对root置空,等学到c++就可以用引用,可以完美解决,这里我们是在函数外手动置空。

void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->leftChild);
	TreeDestory(root->rightChild);
	free(root);
}

二叉树的节点个数

int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->leftChild) + TreeSize(root->rightChild) + 1;
}

二叉树的叶子节点个数

叶子节点:左右孩子都为空

int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->leftChild == NULL && root->rightChild == NULL)
		return 1;

	return TreeLeafSize(root->leftChild) + TreeLeafSize(root->rightChild);
}

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

思路:求第k层的节点个数,可以拆解成求左右子树的k-1层的节点个数,用这个条件递归,直到k等于1时,返回1

int TreeKLevelSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;

	return TreeKLevelSize(root->leftChild, k - 1) + TreeKLevelSize(root->rightChild, k - 1);
}

二叉树的查找值为x的节点

BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;

	BTNode* left = TreeFind(root->leftChild, x);
	if (left)
		return left;

	BTNode* right = TreeFind(root->rightChild, x);
	if (right)
		return right;

	return NULL;
		
}

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

思路:
完全二叉树:最后一层的节点是按顺序排序的,其他层都是满的
把每个不为空的节点的左右孩子都传进队列,然后再把队列中不为空的节点删除掉,遇到空就跳出循环
再对剩下的队列做循环,把空的节点都删除,遇到不为空的节点,就说明不是按顺序排序返回false,反之返回true

bool TreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if (root != NULL)
	{
		QueuePushBack(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePopFront(&q);

		if (front==NULL)
			break;

		QueuePushBack(&q, front->leftChild);
		QueuePushBack(&q, front->rightChild);

	}

	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePopFront(&q);
		if (front)
			return false;
	}
	QueueDestroy(&q);
	return true;
}

总结

读者还是要自己动手画递归过程,理解深刻。
完整代码在这

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值