【递归调用在二叉树中的应用】前序遍历、中序遍历、后序遍历、求二叉树叶子结点及复制二叉树的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动态为复制好的树的结点分配内存,最后返回树的根结点地址。算法测试结果如下: