文章目录
一.递归二叉树
1.二叉树遍历
用N代表空
1 前序遍历
先访问根节点,然后递归地访问左子树和右子树。
1->2->3->N->N->N->4->5->N->N->6->N->N
void PreOrder(bintree* root)
{
if (root== NULL)
{
printf("N->");
return;
}
printf("%d->", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
结果如下:
2中序遍历
先递归地访问左子树,然后访问根节点,最后递归地访问右子树。
N->3->N->2->N->1->N->5->N->4->N->6->N
void InOrder(bintree* root)
{
if (root == NULL)
{
printf("N->");
return;
}
InOrder(root->left);
printf("%d->", root->data);
InOrder(root->right);
}
结果如下:
3后序遍历
先递归地访问左子树和右子树,最后访问根节点。
N->N->3->N->2->N->N->5->N->N->6->4->1
void TailOrder(bintree* root)
{
if (root == NULL)
{
printf("N->");
return;
}
TailOrder(root->left);
TailOrder(root->right);
printf("%d->", root->data);
}
4层序遍历
具体的层序遍历步骤如下:
1。将根节点放入队列中。
2.当队列不为空时,循环执行以下步骤: a. 从队列中取出一个节点,并将其值输出。 b. 将该节点的左子节点和右子节点(如果存在)依次放入队列中。
3.当队列为空时,表示层序遍历结束
在这里插入代码片
层序遍历可以用于树的广度优先搜索,它能够按照层级顺序逐层遍历节点,适用于求解树的最短路径等问题。
如图这棵树,将根节点放入队列之中,当需要遍历之时,取出1号,随之将其左右孩子节点放入队列即2号和4号,当取出2号时,将3号放入,取出4号时将5号6号放入…
那么如何一层一层取出数据或打印数据呢?
我们借助队列个数统计,创建一个levesize记录每一层个数循环操作
void BinaryTreeLevelOrder(bintree* root)
{
queue q;
QueueInit(&q);
if (root)
QueuePush(&q, root);
int levesize = 1;//记录每层个数
while (!QueueEmpty(&q))
{
//一层一层
while (levesize--)
{
bintree* front = QueueFront(&q);
QueuePop(&q);//出队列
printf("%d ", front->data);
//递归操作
if (front->left)
QueuePush(&q, front->left);
if (front->right)
QueuePush(&q, front->right);
}
printf("\n");
levesize = QueueSize(&q);//每层出完后,重新统计
}
QueueDestroy(&q);
}
在c语言中没有队列库函数,所以借助曾经代码,对此不熟悉的可以参考往期文章:链接: 队列和栈
2.递归制造一棵二叉树
给定一个字符数组,将其表现为想要的树
ABD##E#H##CF##G##
采用前序遍历方式,制造结点
bintree* CreatBTree(char* a,int*pi)
{
if (a[*pi] == '#')
{
(*pi)++;
return NULL;
}
bintree* root = (bintree*)malloc(sizeof(bintree));
root->data = a[(*pi)++];
root->left= CreatBTree(a, pi);
root->right= CreatBTree(a, pi);
return root;
}
结束条件为'#',开始返回,根节点的左孩子接受左子树返回的节点,右孩子接受右子树返回的节点
我们展示一下将要实现的功能:
int main()
{
//bintree*treeroot=Creattree();
int i = 0;
char a[100] = "ABD##E#H##CF##G##";
bintree* treeroot = CreatBTree(a, &i);
PreOrder(treeroot);
printf("\n");
InOrder(treeroot);
printf("\n");
TailOrder(treeroot);
printf("\n");
printf("%d", TreeSize(treeroot));
printf("\n");
printf("%d", TreeLeafSize(treeroot));
printf("\n");
printf("%d", TreeHeight(treeroot));
printf("\n");
printf("%d", TreeKleve(treeroot,3));
return 0;
}
这些功能在第二部分实现
二.部分功能实现
1.统计二叉树节点数
有两种常见思路:
1.创建一个全局变量size,然后遍历二叉树,size++。
2.递归思路,左右子树节点之和加1。
第一种比较简单,我们实现第二种思路。
结束条件为,root为空
如果二叉树为空,则节点数为0。
否则,节点数为根节点数加上左子树节点数和右子树节点数。
递归地计算左子树节点数和右子树节点数。
int TreeSize(bintree* root)
{
return root == NULL ?
0 : TreeSize( root->left) +//左
TreeSize(root->right) +//右
1;//根
}
2.统计子叶个数
类似于第二点,只不过由于判断子叶条件变了所以递归条件变了。
分治子问题:
1.是空,返回条件,返回0
2.不是空,是叶子,返回1
int TreeLeafSize(bintree* root)
{
if (root == NULL)
//是空,返回条件,返回0
return 0;
if (root->left == NULL && root->right == NULL)
//不是空,是叶子,返回1
return 1;
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
//左子树叶子与右子树叶子之和
}
如图所示,先递归红色左子树,在递归棕色右子树,此为分治子问题,一共两种情况不同返回递归结果
答案正确。
3.统计树高
同样的问题:左右递归,选择左右子树高的记录。
int TreeHeight(bintree* root)
{
if (root == NULL)
return 0;
int leftheight = TreeHeight(root->left);
int rightheight = TreeHeight(root->right);
return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}
我们可以人为给树增加两层
node5->left = node7;
node7->left = node8;
4.统计任意一层的节点数
这题仍然是一个分治子问题,由于在同一层的节点存在NULL和非空,所以递归条件:
1.root==NULL时,不计数量返回0
2.k=1时,root!=NULL时,计数量为1
int TreeKleve(bintree* root,int k)
{
assert(k > 0);
if (root == NULL)
return 0;
if (k == 1)
return 1;
return TreeKleve(root->left, k - 1) + TreeKleve(root->right, k - 1);
}
以该图解释,计数第三层,则为左子树和右子树第二层相加,则为左子树的左右子树第一层相加和右子树的左右子树第一层相加
根k=3
<=>左子树k=2+右子树k=2
<=>左子树的 左右子树k=1 + 右子树的 左右子树k=1
结果为3
三.判断完全二叉树
判断一棵树是否是完全二叉树通常需要使用层序遍历的方法。以下是判断一棵树是否为完全二叉树的步骤:
对树进行层序遍历,从根节点开始。
1.如果在层序遍历中遇到了空节点(即null节点),则该空节点后面的所有节点必须都是空节点,否则树不是完全二叉树。
2.如果在层序遍历中遇到了一个节点,但是它的左子节点是空节点,而右子节点不是空节点,则树不是完全二叉树。
3.如果在层序遍历中遇到了一个节点,但是它没有左子节点,但是有右子节点,则树不是完全二叉树。
4.如果在层序遍历中没有出现上述情况,且遍历到最后一个节点后,树仍然是完全二叉树。
bool BinaryTreeComplete(bintree* root)
{
queue q;
QueueInit(&q);
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
bintree* front = QueueFront(&q);
QueuePop(&q);
if (front == NULL)
break;
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
while (!QueueEmpty(&q))
{
bintree* front = QueueFront(&q);
QueuePop(&q);
if (front)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
在第一遇到NULL时看队列内是否还有数据,如果没有则为完全二叉树
显然该树不是完全二叉树