文章目录
前言:
思维导图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vOghesek-1645797380622)(%E9%81%8D%E5%8E%86.assets/202202252155405.png)]
建议
递归的3要素
二叉树的遍历
前序遍历
递归
思路
完整代码
//前序遍历是根在左右孩子前,先访问二叉树根结点。
void PreOrder(BTNode* root)
{
if(root==NULL)
{
printf("NULL ");
return ;
}
printf("%c ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
非递归
思路
代码
void PreOrderNoR(BTNode* root)// 二叉树前序遍历---非递归法
{
assert(root);
stack st;
StackInit(&st);
//我们需要根结点来进入右子树,因此要存根结点
//同时一旦左子树访问完后,再进入右子树时需要根结点,后面就不需要了。因此pop
SDateType p = root;
while (1)
{
if (p != NULL)
{
printf("%c->", p->data);
StackPush(&st, p);
p = p->left;
}
else
{
printf("NULL->");
break;
}
}
while (!StackEmpty(&st)||p)//空树或者栈空结束
{
/
//p为空说明,根和左子树遍历完毕。
if (!StackEmpty(&st))
{
p = StackTop(&st);
StackPop(&st);
p = p->right;
while (1)
{
if (p != NULL)
{
printf("%c->", p->data);
StackPush(&st, p);
p = p->left;
}
else
{
printf("NULL->");
break;
}
}
}
}
printf("\n");
StackDestroy(&st);
}
中序遍历
递归
思路
代码
void InOrder(BTNode* root)// 二叉树中序遍历
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->left);
printf("%c ", root->data);
InOrder(root->right);
}
非递归
思路
代码
void InOrderNoR(BTNode* root)// 二叉树中序遍历---递归法
{
assert(root);
stack st;
StackInit(&st);
//我们需要根结点来进入右子树,因此要存根
SDateType p = root;
//遍历到左子树最低端.
while (1)
{
if (p != NULL)
{
StackPush(&st, p);
p = p->left;
}
else
{
printf("NULL->");
break;
}
}
while (!StackEmpty(&st) || p)//空树或者栈空结束
{
if (!StackEmpty(&st))
{
SDateType tmp= StackTop(&st);
printf("%c->", tmp->data);
StackPop(&st);
p = tmp->right;
//根结点已经遍历玩比,后续的遍历就不需要它了。
//无论右子树是否为空,即使回来也不需要根结点。
//遍历到左子树最低端.
while (1)
{
if (p != NULL)
{
StackPush(&st, p);
p = p->left;
}
else
{
printf("NULL->");
break;
}
}
}
}
printf("\n");
StackDestroy(&st);
}
后序遍历
递归
思路
代码
void PostOrder(BTNode* root)// 二叉树后序遍历
{
if (root == NULL)
{
printf("NULL ");
return;
}
PostOrder(root->left);
PostOrder(root->right);
printf("%c ", root->data);
}
非递归
思路
代码
void PostOrderNoR(BTNode* root)// 二叉树后序遍历---非递归法
{
//思路:1.只有当左右子树访问完后,才能访问根结点。
// 因此要有一个pVisist指针来记录已访问的左或右子树。当pVisit=p->right||p->right==NULL时,访问根结点。
// 2.我们访问存在的右子树时,仍把它看作一棵二叉树,因此仍需要压栈与出栈,
// 3.这里我打印NULL来帮助更好理解,
assert(root);
assert(root);
stack st;
StackInit(&st);
SDateType p = root;
SDateType pVisit = NULL;//标记左右子树的
//简化版--只是将Top赋值给p了,但是要注意当右子树不为空,一定要直接进行左子树入栈。因为p的值并不是空。
while (1)//先将左子树压栈,当左子树为空后,开始访问右子树。
{
if (p == NULL)
{
printf("NULL->");
break;
}
else
{
StackPush(&st, p);
p = p->left;
}
}
while (!StackEmpty(&st) || p)//空树或者栈空结束
{
if (!StackEmpty(&st))
{
p = StackTop(&st);
//只有当右子树为空或者右子树已访问才访问根结点,才能删除根结点.
if (p->right == NULL || p->right == pVisit)
{
if (p->right == NULL)
{
printf("NULL->");
}
StackPop(&st);
printf("%c->", p->data);
pVisit = p;
//这一部代表该子树已访问,但是不确实是左子树还是右子树,因此需要 p->right == pVisit
}
else
{
p = p->right;//下次循环将是右子树的遍历。
while (1)
{
if (p == NULL)
{
printf("NULL->");
break;
}
else
{
StackPush(&st, p);
p = p->left;
}
}
}
}
}
printf("\n");
StackDestroy(&st);
}
层序遍历
代码
void LevelOrder(BTNode* root)// 层序遍历
{
if (root == NULL)
{
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* tmp = QueueTop(&q);
printf("%c ", tmp->data);
QueuePop(&q);
if (tmp->left != NULL)
{
QueuePush(&q, tmp->left);
}
if (tmp->right != NULL)
{
QueuePush(&q, tmp->right);
}
}
QueueDestroy(&q);
}