二叉树的创建和简单操作;前序中序后续,层序遍历。

Posted 银背欧尼酱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的创建和简单操作;前序中序后续,层序遍历。相关的知识,希望对你有一定的参考价值。


前言

本篇文章将带大家了解二叉树一些功能实现和二叉树的四种遍历方式:前、中、后、层。
接下俩让我们一起来看一下吧~


1.定义二叉树结点

首先我们来定义二叉树的结点,这里使用孩子表示法。孩子表示法是指该结点除了存储本结点的数值之外,还具备指向自己左右孩子的指针。(还有另一种父母孩子表示法,是在孩子表示法的基础上增加了可以指向父母结点的指针)

代码:

typedef struct BTNode
{
	BDataType data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

2.创建树

树的创建和前序遍历的思想一样。先创建根节点,再创建左子树,最后创建右子树。
代码实现:

/ index按照值的方式传递的---在递归过程中对index修改之后,不会将修改之后的结果带到上一层中
BTNode* _CrteateBinTree(BDataType array[], int size, int* index, BDataType invalid)
{
	BTNode* root = NULL;
	if (*index < size && invalid != array[*index])
	{
		// 创建根节点
		root = BuyBinTreeNode(array[*index]);

		// 创建根节点的左子树
		++(*index);
		root->left = _CrteateBinTree(array, size, index, invalid);

		// 创建根节点的右子树
		++(*index);
		root->right = _CrteateBinTree(array, size, index, invalid);
	}

	return root;
}

BTNode* CrteateBinTree(BDataType array[], int size, BDataType invalid)
{
	int index = 0;
	return _CrteateBinTree(array, size, &index, invalid);
}

BuyBinTreeNode是获取结点函数,下面介绍创建结点函数

3.获取结点

BTNode* BuyBinTreeNode(BDataType data)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == node)
	{
		assert(0);
		return NULL;
	}

	node->data = data;
	node->left = node->right = NULL;
	return node;
}

4.计算二叉树结点和叶子结点个数

int BinaryTreeSize(BTNode* root)
{
	if (NULL == root)
		return 0;

	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (NULL == root)
		return 0;

	if (NULL == root->left && NULL == root->right)
	{
		return 1;
	}

	return BinaryTreeLeafSize(root->left) + 
		   BinaryTreeLeafSize(root->right);
}

5.计算树的高度

int BinaryTreeHeight(BTNode* root)
{
	if (0 == root)
		return 0;

	int leftHeight = BinaryTreeHeight(root->left);
	int rightHeight = BinaryTreeHeight(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

6. 计算第K层结点的个数

思路:求第K层结点元素个数,等于到root的左右子树中求K-1层结点个数合。用递归法。

代码:

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (NULL == root || k <= 0)
		return 0;

	//第1层中只有根节点
	if (1 == k)
		return 1;

	// k > 1
	return BinaryTreeLevelKSize(root->left, k - 1) +
		   BinaryTreeLevelKSize(root->right, k - 1);
}

7. 查找二叉树值为X的结点

BTNode* BinaryTreeFind(BTNode* root, BDataType x)
{
	BTNode* ret = NULL;
	if (NULL == root)
		return NULL;

	if (x == root->data)
		return root;
	
	if (ret = BinaryTreeFind(root->left, x))
		return ret;

	return BinaryTreeFind(root->right, x);
}

8.前序,中序,后序遍历

由于前序,中序,后序遍历,思路相似,都是利用递归的思想实现,所以这里一并给出。

void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d ", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

// 中序遍历:左子树--->根节点--->右子树
void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d ", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d ", root->data);
	}
}

9.层序遍历

层序遍历和前中后序遍历不同。由于前中后序遍历,都可以直接用“二叉树的头结点能够指向自己左右孩子”的功能来实现。而层序遍历要求先遍历根结点,然后遍历另一个同等级结点,而不是根结点的左右孩子。所以直接用二叉树的结点无法满足功能。

设计思路:

这里决定使用队列来实现层序遍历的功能。具体操作步骤:

  1. 先把二叉树根节点加入队列

image-20210601061932411

  1. 打印队列中的前端第一个结点

  2. 分别将根节点的左右孩子按先左后右的顺序放入队列

image-20210601062116160

  1. 去掉队列前端第一个结点

image-20210601064311151

  1. 循环上述步骤,直到二叉树为空

队列的定义:

typedef struct QNode
{
	struct QNode* next;
	DataType data;
}QNode;

typedef struct Queue
{
	QNode* front;
	QNode* back;
}Queue;

代码实现:

void LevelOrder(BTNode* root)
{
	Queue q;
	if (NULL == root)
		return;

	QueueInit(&q);//队列初始化
	QueuePush(&q, root);//插入根节点

	while (!QueueEmpty(&q))//判断是否为空
	{
		BTNode* cur = QueueFront(&q);

		printf("%d ", cur->data);

		if (cur->left)
			QueuePush(&q, cur->left);

		if (cur->right)
			QueuePush(&q, cur->right);

		QueuePop(&q);//删除堆前侧元素
	}

	QueueDestroy(&q);//销毁堆
}

关于队列的具体函数实现如果一并给出,则代码太过臃肿和混乱,反而降低了可读性。想具体了解的可以移步到另一篇博客:《队列用带头单链表实现》

10.总体代码实现

BinaryTree.c

#include "BinaryTree.h"
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
BTNode* BuyBinTreeNode(BDataType data)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (NULL == node)
	{
		assert(0);
		return NULL;
	}

	node->data = data;
	node->left = node->right = NULL;
	return node;
}

void PreOrder(BTNode* root)
{
	if (root)
	{
		printf("%d ", root->data);
		PreOrder(root->left);
		PreOrder(root->right);
	}
}

// 中序遍历:左子树--->根节点--->右子树
void InOrder(BTNode* root)
{
	if (root)
	{
		InOrder(root->left);
		printf("%d ", root->data);
		InOrder(root->right);
	}
}

void PostOrder(BTNode* root)
{
	if (root)
	{
		PostOrder(root->left);
		PostOrder(root->right);
		printf("%d ", root->data);
	}
}

// 层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	if (NULL == root)
		return;

	QueueInit(&q);
	QueuePush(&q, root);

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

		printf("%d ", cur->data);

		if (cur->left)
			QueuePush(&q, cur->left);

		if (cur->right)
			QueuePush(&q, cur->right);

		QueuePop(&q);
	}

	QueueDestroy(&q);
}

int BinaryTreeSize(BTNode* root)
{
	if (NULL == root)
		return 0;

	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (NULL == root)
		return 0;

	if (NULL == root->left && NULL == root->right)
	{
		return 1;
	}

	return BinaryTreeLeafSize(root->left) + 
		   BinaryTreeLeafSize(root->right);
}

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (NULL == root || k <= 0)
		return 0;

	//第1层中只有根节点
	if (1 == k)
		return 1;

	// k > 1
	return BinaryTreeLevelKSize(root->left, k - 1) +
		   BinaryTreeLevelKSize(root->right, k - 1);
}

int BinaryTreeHeight(BTNode* root)
{
	if (0 == root)
		return 0;

	int leftHeight = BinaryTreeHeight(root->left);
	int rightHeight = BinaryTreeHeight(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BDataType x)
{
	BTNode* ret = NULL;
	if (NULL == root)
		return NULL;

	if (x == root->data)
		return root;
	
	if (ret = BinaryTreeFind(root->left, x))
		return ret;

	return BinaryTreeFind(root->right, x);
}

void DestroyBinTree(BTNode** root)
{
	assert(root);
	if (NULL == *root)
		return;

	// 按照后序遍历规则来进行销毁
	DestroyBinTree(&(*root)->left);
	DestroyBinTree(&(*root)->right);
	free(*root);
	*root = NULL;
}

// index按照值的方式传递的---在递归过程中对index修改之后,不会将修改之后的结果带到上一层中
BTNode* _CrteateBinTree(BDataType array[], int size, int* index, BDataType invalid)
{
	BTNode* root = NULL;
	if (*index < size && invalid != array[*index])
	{
		// 创建根节点
		root = BuyBinTreeNode(array[*index]);

		// 创建根节点的左子树
		++(*index);
		root->left = _CrteateBinTree(array, size, index, invalid);

		// 创建根节点的右子树
		++(*index);
		root->right = _CrteateBinTree(array, size, index, invalid);
	}

	return root;
}

BTNode* CrteateBinTree(BDataType array[], int size, BDataType invalid)
{
	int index = 0;
	return _CrteateBinTree(array, size, &index, invalid);
}

BinaryTree.h

typedef int BDataType;


// 孩子表示法

typedef struct BTNode
{
	BDataType data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

typedef struct QNode
{
	struct QNode* next;
	DataType data;
}QNode;

typedef struct Queue
{
	QNode* front;
	QNode* back;
}Queue;


BTNode* _CrteateBinTree(BDataType array[], int size, int* index, BDataType invalid);
BTNode* CrteateBinTree(BDataType array[], int size, BDataType invalid);

void PreOrder(BTNode* root);
void InOrder(BTNode* root);
void PostOrder(BTNode* root);

// 层序遍历
void LevelOrder(BTNode* root);

// 求二叉树中节点的个数
int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

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

// 求二叉树的高度
int BinaryTreeHeight(BTNode* root);

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BDataType x);

void DestroyBinTree(BTNode** root);

void QueueInit(Queue* q);

总结

以上就是本篇博客的内容,希望大家有所收获。

以上是关于二叉树的创建和简单操作;前序中序后续,层序遍历。的主要内容,如果未能解决你的问题,请参考以下文章

二叉树的非递归遍历(先序中序后序和层序遍历)

输入后序和中序,构造二叉树,并输出该二叉树的层序前序中序后序遍历结构;输入后序和中序,构造二叉树,并输出该二叉树的层序前序中序后序遍历结构

手撕二叉树的4种遍历:前序中序后序层序

手撕二叉树的4种遍历:前序中序后序层序

二叉树的前序中序后序层序遍历,递归和迭代两大类解题思路,每类细分不同解法完整版附PDF文档

二叉树的四种遍历方式以及中序后序前序中序前序后序层序创建二叉树专为力扣刷题而打造