【递归调用在二叉树中的应用】前序遍历、中序遍历、后序遍历、求二叉树叶子结点及复制二叉树的C语言实现

二叉树结点的结构体

包含指向左右子树的指针,和一个数据

typedef struct MyTreeNode
{
	struct MyTreeNode* left; //左孩子
	struct MyTreeNode* right; //右孩子
	int data;
}MyTreeNode;

创建一棵二叉树

创建一颗二叉树,其节点关系以及每个结点的数据如图所示

 代码如下

{
    MyTreeNode t[15];

	for (i = 0; i < 15; i++)
	{
		memset(&t[i], 0, sizeof(MyTreeNode)); //没有孩子的应指向NULL
		t[i].data = i + 1;
	}

	//建立关系
	t[0].left = &t[1];
	t[0].right = &t[7];
	t[1].left = &t[2];
	t[2].left = &t[3];
	t[2].right = &t[4];
	t[4].left = &t[5];
	t[5].right = &t[6];
	t[7].right = &t[8];
	t[8].right = &t[14];
	t[8].left = &t[9];
	t[9].left = &t[10];
	t[9].right = &t[11];
	t[11].left = &t[12];
	t[11].right = &t[13];
}

二叉树的前序遍历

前序遍历是指,先访问根结点,然后访问左子树根节点,然后访问右子树根结点(根-左-右)。通过递归调用实现前序遍历算法的C语言代码如下:

void preorder_traversal(MyTreeNode* tree)
{
	if (tree == NULL)
	{
		//叶子结点指向NULL则返回
		return;
	}
	printf("%d ", tree->data);
	preorder_traversal(tree->left);
	preorder_traversal(tree->right);
}

 前序遍历算法的测试结果:

中序遍历

先访问左子树根结点,然后访问根结点,最后访问右子树根结点(左-根-右)。通过递归调用实现中序遍历算法的C语言代码如下:

void inorder_traversal(MyTreeNode* tree)
{
	if (tree == NULL)
	{
		return;
	}
	inorder_traversal(tree->left);
	printf("%d ", tree->data);
	inorder_traversal(tree->right);
}

中序遍历算法的测试结果:

 后序遍历

先访问左子树根结点,然后访问右子树根结点,最后访问根结点(左-右-根)。通过递归调用实现后序遍历算法的C语言代码如下:

void postorder_traversal(MyTreeNode* tree)
{
	if (tree == NULL)
	{
		return;
	}
	postorder_traversal(tree->left);
	postorder_traversal(tree->right);
	printf("%d ", tree->data);
}

后序遍历算法的测试结果:

三种遍历的关系 

通过对比三种递归遍历算法的代码可以看到,三种遍历的区别就在于printf函数的位置不同,其他语句的顺序都是相同的,实际上,在遍历树的时候,不管是前序遍历、中序遍历、还是后序遍历,每个结点都会被访问三次,如下图所示,三种遍历的区别就在于获取节点数据的时机不同,前序遍历是在第一次访问就获取结点数据,中序遍历是在第二次访问的时候获取结点数据,后序遍历是在第三次访问的时候获取结点数据。

 求二叉树的叶子结点数

代码如下

void get_leaf_num(MyTreeNode* tree, int* count) //指针做函数参数,间接修改实参的值
{
	if ((tree->left == NULL) && (tree->right == NULL))
	{
		(*count)++;
	}
	if (tree->left != NULL)
	{
		get_leaf_num(tree->left, count);
	}
	if (tree->right != NULL)
	{
		get_leaf_num(tree->right, count);
	}
}

求二叉树叶子结点算法测试:

 复制一棵树

通过递归实现复制树,代码如下

MyTreeNode* copy_tree(MyTreeNode* tree)
{
	MyTreeNode* root = NULL;// *left = NULL, * right = NULL;
	root = (MyTreeNode*)malloc(sizeof(MyTreeNode));
	memset(root, 0, sizeof(MyTreeNode));
	root->data = tree->data;
	if (tree->left != NULL)
	{
		//如果有左子树则复制左子树
		root->left = copy_tree(tree->left);
	}
	else
	{
		//没有左子树则置为NULL
		root->left = NULL;
	}
	if (tree->right != NULL)
	{
		root->right = copy_tree(tree->right);
	}
	else
	{
		root->right = NULL;
	}
	return root;
}

复制树的时候,要通过malloc动态为复制好的树的结点分配内存,最后返回树的根结点地址。算法测试结果如下:

posted @ 2022-04-04 10:00  Mindtechnist  阅读(22)  评论(0编辑  收藏  举报  来源