数据结构总目录
非递归创建创建二叉树
1. 结构解析
对于大部分递归算法,想要转化成非递归的方式,常常需要借助一个栈来完成,对于二叉树的创建也是如此;
在创建二叉树的结点时,将插入的左孩子结点压入栈中,使得在完成左孩子的插入后,再通过出栈来回溯到先前的结点,即可完成右孩子的插入,从而完成二叉树的创建。
假设我们需要创建如下一棵二叉树
(1)依次插入左孩子结点A、B、C,每次插入完成后都设置flag = 0, 代表下一次插入默认是左孩子,同时按顺序将结点压入栈顶S,如图:
(2)当我们需要在结点B的右孩子上插入D,此时栈的作用就体现出来了,通过出栈两次,回溯到结点B,同时每次出栈后都设置flag = 1,那么下次插入时根据flag就可知道插入的是右孩子结点。
(3)根据flag=1可知,插入右孩子结点D并入栈,而后重新设置flag=0,代表下次插入的是结点D的左孩子结点
总结来讲,就是通过 入栈flag = 0 来插入左孩子结点,通过 出栈flag=1 来插入右孩子结点,同时多次出栈可依次回溯结点。
2. 源代码:
#include <stdio.h>
#include <stdlib.h>
// 树结点
typedef char DataType;
typedef struct BiTNode
{
DataType data;
struct BiTNode *lchild, *rchild;
}LinkBiTree;
//栈结点
typedef struct SNode
{
LinkBiTree *data;
struct SNode *next;
}LinkStack;
// 入栈
void Push(LinkStack **S, LinkBiTree *T)
{
// 创建一个新的结点
LinkStack *s;
s = (LinkStack *)malloc(sizeof(LinkStack));
s->data = T;
// 采用头插法,修改头指针的指向
s->next = (*S);
(*S) = s;
}
// 出栈
LinkBiTree *Pop(LinkStack **S)
{
LinkStack *p = (*S);
if (p != NULL)
{
(*S) = (*S)->next;
return p->data;
}
else
{
return NULL;
}
}
// 非递归创建二叉树
void CreateBiTree(LinkBiTree **T)
{
// 初始化二叉树和栈
(*T) = NULL;
LinkStack *S = NULL;
int op, flag = 0;
LinkBiTree *p = NULL, *q = NULL;
while(1)
{
printf("选择入栈(0)或者出栈(1),输入其他退出:");
scanf("%d", &op);
if (op == 0)
{
DataType x;
printf("请输入插入的结点数据:");
fflush(stdin);
scanf("%c", &x);
// 创建新的二叉树结点
LinkBiTree *node = (LinkBiTree *) malloc(sizeof(LinkBiTree));
node->data = x;
node->lchild = node->rchild = NULL;
if ((*T) == NULL)
{
// 如果二叉树根节点为空,则设置根节点
(*T) = node;
p = (*T);
printf("当前根结点为空,设置根节点root = %c\n", node->data);
}
else
{
// flag = 0 代表插入的是左孩子,flag = 1 代表插入的是右孩子
if (flag == 0)
{
p->lchild = node;
printf("已向左孩子插入新结点 = %c, ", node->data);
}
else
{
p->rchild = node;
printf("已向右孩子插入新结点 = %c, ", node->data);
}
// p指向新的结点
p = node;
// 默认下次插入的是左孩子
flag = 0;
}
// 将新结点存在栈中,用于回溯结点
Push(&S, p);
}
else if(op == 1)
{
// 出栈,回溯到上一个入栈结点
q = Pop(&S);
p = q;
// 设置下次插入的是右孩子
flag = 1;
printf("出栈结点 = %c, ", p->data);
}
else
{
break;
}
// *********************提示信息**************************
if (p)
{
printf("当前指针位置 -> %c, ", p->data);
flag ? printf("下次插入结点为右孩子\n\n") : printf("下次插入结点为左孩子\n\n");
}
// *********************提示信息**************************
}
}
// 先序遍历二叉树
void PreOrderTraverse(LinkBiTree *T)
{
if (T)
{
printf("%c ", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
// 中序遍历二叉树
void InOrderTraverse(LinkBiTree *T)
{
if (T)
{
InOrderTraverse(T->lchild);
printf("%c ", T->data);
InOrderTraverse(T->rchild);
}
}
// 后序遍历二叉树
void PostOrderTraverse(LinkBiTree *T)
{
if (T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c ", T->data);
}
}
int main()
{
LinkBiTree *T;
CreateBiTree(&T);
printf("\n先序遍历:");
PreOrderTraverse(T);
printf("\n");
printf("中序遍历:");
InOrderTraverse(T);
printf("\n");
printf("后序遍历:");
PostOrderTraverse(T);
printf("\n");
system("pause");
return 0;
}
3. 测试结果