二叉树前中后序遍历以及节点计算


多叉树的表示方法是左孩子右兄弟。二叉树每个节点的度至多为2,所以用左孩子,右孩子。

二叉树

有二叉链和三叉链。

分类

二叉链的数据结构

struct BTNode
{
	int data;
	struct BTNode* leftchild;
	struct BTNode* rightchild;
};

三叉链的数据结构

struct BTNode
{
	int data;
	struct BTNode* leftchild;
	struct BTNode* parent;
	struct BTNode* rightchild;
};

任何一颗二叉树由三部分组成:根节点,左子树,右子树。

要用到分治算法:将大问题分成类似的子问题,子问题再分,直到子问题不可再分割。对于二叉树,就是分到空树不可再分了。

四种遍历方法

深度优先遍历:前中后序

为了不遗漏(也不能重复)处理二叉树的每一个节点,总得按照某种顺序,前辈们发明了处理二叉树节点的顺序:按层遍历、前序遍历、中序遍历、后续遍历。二叉树的前序、中序、后序遍历的作用都是不遗漏且不重复地处理二叉树的每一个结点。

              		                 A
                        B                         C
                D                E            NULL  NULL
         F     		    G     NULL NULL
     NULL NULL    H          I
    		  NULL NULL  NULL NULL

前序(先根遍历):根左右。先访问根,再访问左子树,再访问右子树。

顺序是A B D F NULL NULL G H NULL NULL I NULL NULL E NULL NULL C NULL NULL

中序:左根右。NULL F NULL D NULL H NULL G NULL I NULL B NULL E NULL A NULL C NULL

后序:左右根。NULL NULL F NULL NULL H NULL NULL I G D NULL NULL E B NULL NULL C A

为什么要用前中后序原因:前序(先根后子)用于搜索目标状态(先比较再扩展,你发现当前结点就是要搜索的目标就不需要继续扩展了)。或者子依赖父的对象创建(树是一组元数据,你基于这些元数据创建对象,子对象依赖于父对象所以父对象需要先创建),比如说根据元数据创建网页元素插入到浏览器DOM树。

中序(左根右)用于遍历排序二叉树。

后序(先子后根)用于父依赖子(子是父的组成要素)的对象创建。或者自低向上收集信息,比如不剪枝的博弈树收集极大极小值的过程。

深度优先遍历是前中后序,前序是先访问再往下走,中序是左路退回来的时候再访问,后序是左右两路都退回来再访问。

//前序 根左右
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->data);
	//左子树
	PrevOrder(root->leftchild);
	//右子树
	PrevOrder(root->rightchild);
}

//中序 左根右
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	//左子树
	InOrder(root->leftchild);
	printf("%d ", root->data);
	//右子树
	InOrder(root->rightchild);
}

//后序 左右根
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	//左子树
	PostOrder(root->leftchild);
	//右子树
	PostOrder(root->rightchild);
	printf("%d ", root->data);
}

广度优先遍历:层序遍历

用的是队列,先进先出的原则。核心思路是上一层带下一层

计算

节点个数

//方法1 外部传节点个数的地址,函数中直接改
void TreeSize1(BTNode* root, int* size)
{
	if (root == NULL)
	{
		return 0;
	}
	//该节点不为空就+1
	(*size)++;
	//继续遍历左子树
	TreeSize1(root->leftchild, size);
	//右子树
	TreeSize1(root->rightchild, size);
}
//方法2 
int TreeSize2(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	//根不为空就可以继续往下遍历
	return  1 + TreeSize2(root->leftchild) + TreeSize2(root->rightchild);
}

叶子节点个数

int TreeLeafSize(BTNode* root)
{
	//当前节点为空,就无法访问它的左右子树
	if (root == NULL)
	{
		return 0;
	}
	if (root->leftchild == NULL && root->rightchild == 0)
	{
		return 1;
	}
	return TreeLeafSize(root->leftchild) + TreeLeafSize(root->rightchild);
}

树的高度

//要用后序思想来做
int TreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftHeight = TreeHeight(root->leftchild);
	int rightHeight = TreeHeight(root->rightchild);
	//有了左子树的高度和右子树的高度,等于1 + max(左子树高度,右子树高度)
	return leftHeight > rightHeight ?
		1 + leftHeight : 1 + rightHeight;
}

第k层的节点个数

root的第k层,转换成求root左右子树的第k-1层

int TreeKLevel(BTNode* root, int K)
{
	assert(K > 0);
	if (root == NULL)
	{
		return 0;
	}
	//到第K层,遇到1个非空节点,就+1
	if (K == 1)
	{
		return 1;
	}
	return TreeKLevel(root->leftchild, K - 1) + TreeKLevel(root->rightchild, K - 1);
}

返回值为x的节点

这种方法还可以去修改指定值

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	//如果该节点为空,那就没必要执行后面的语句,直接返回
	if (root == NULL)
	{
		return NULL;
	}
	//如果找到了,返回该节点
	if (root->data == x)
	{
		return root;
	}
	//没找到就接着找
	//先在左子树找
	BTNode* left = BinaryTreeFind(root->leftchild, x);
	if (left != NULL)
	{
		return left;
	}
	//左子树没找到,就去右子树找
	BTNode* right = BinaryTreeFind(root->rightchild, x);
	if (right != NULL)
	{
		return right;
	}
	//左子树和右子树都找不到,要返回NULL
	return NULL;
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值