您的位置:首页 > 编程语言 > C语言/C++

c语言实现顺序二叉树的非递归的三种遍历算法

2015-09-03 17:51 609 查看
二叉树的概念遍地都是,就不详说了。不管是顺序的还是链式的二叉树,实现的方法基本上都是递归的例子,我就自己看着遍历的方法,写出了这一个程序,程序中每个遍历实现思想都有详细描述,代码略显繁琐,欢迎读者批评指正。使用的例子看附图,也算是自己的一个学习笔记。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

#define Max_Size 100
#define null '#'//表示为空

//可以当做一个数据类型
typedef char BinaryTree[Max_Size];

//初始化二叉树中每个节点为空
void InitTree(BinaryTree tree)
{
int i;
for(i=0;i<Max_Size-1;i++)
{
tree[i] = null;
}
tree[i] = '\0';
}

void CreateTree(BinaryTree tree,char *strtree)
{
int len = strlen(strtree);

if(strtree[0] == null)
{
printf("树根节点不能为空");
return ;
}
int i;
for(i=0;i<len;i++)
{
tree[i] = strtree[i];

//树节点从0开始,若从1开始,则判断条件改为:tree[(i+1)/2]
if((tree[(i+1)/2 - 1] == null) &&(tree[i] != null))
{
printf("构造二叉树错误,子节点没有父节点.\n节点为%d  %c.\n",i+1,tree[i]);
exit(1);
return;
}
}
}

//使用完全二叉树求深度的公式[log₂N]+1   [x]取不大于x的整数
int Length(char *strtree)
{
printf("二叉树字符串:%s\n完全二叉树的节点数::%d\n",strtree,strlen(strtree));
//c语言提供的函数log10
float a = log10((double)strlen(strtree)),b = log10(2.0);
//计算深度函数
int len = a/b + 1;
printf("二叉树深度为:%d\n",len);

return len;
}

int Is_Empty(BinaryTree tree)
{
if(tree[0] == '#' || tree[0] == '\0')
{
printf("二叉树为空!\n");
return 1;
}

return 0;
}

//有效节点个数
int Count(BinaryTree tree)
{
int count=0;
int len = strlen(tree);
int i=0;
while(i < len)
{
if(tree[i] != '#')
{
count++;
}
i++;
}

return count;
}

//先序遍历实现思想:(根据输出的有效节点个数来作为循环的终止条件)
//一:从根节点出发,先打印根节点,
//二:寻找下一个左节点,
//三:若节点不为空,打印该节点并重复步骤二
//四:若节点为空,判断该节点的兄弟右节点
//五:	若不为空,从该节点开始,重复步骤二
//六:	若为空,回退至上一个节点,重复步骤四
//注:(回退时注意从左节点开始回退,避免两个不同子树的右孩子与左孩子有联系)
void PreOrderTraverse(BinaryTree tree)
{
char Strtree[Max_Size];
strcpy(Strtree,tree);

if((Is_Empty(Strtree) == 1))
{
return;
}

int len = Count(Strtree);
int k=0,i=0;//i表示节点在完全二叉树中的位置

//根据输出的有效节点个数来作为循环的终止条件
while(k < len)
{
while(Strtree[i] != '#')
{
//打印有效节点
printf("%c ",Strtree[i]);
Strtree[i] = '#';//标志节点已被打印为空
k++;
//继续寻找左节点
i = (i+1)*2 - 1;
if(Strtree[i] == '#')
{
break;
}
}

//遍历右节点
if(Strtree[i+1] != '#')
{
i = i + 1;
}
else
{
//回退过程
i = (i+1)/2 - 1;

if(i%2 == 0 )
{
i = i - 1;
}
}

}
}

//中序遍历实现思想:(根据输出的有效节点个数来作为循环的终止条件)
//一:对于任意一个节点,先找到它的最左节点,最左节点的下一个左节点一定是空的
//二:回退至上一个节点,判断该节点是否为空(左子树打印过程中会置空,回退时避免打印无效节点):
//三:	若不为空,打印该节点,继续判断该节点的右孩子,若不为空,重复步骤一;
//四:	若为空,重复步骤二。
void MidOrderTraverse(BinaryTree tree)
{
char Strtree[Max_Size];
strcpy(Strtree,tree);

if((Is_Empty(Strtree) == 1))
{
return;
}

int len = Count(Strtree);
int i=0,k=0;//i表示节点在完全二叉树中的位置

while(k<len)
{
//新一个右节点就寻找该子树的最左节点
while((Strtree[i] != '#'))
{
i = 2*(i+1)-1;
}

//回退至父节点
i = (i+1)/2 - 1;
if(Strtree[i] != '#')
{
printf("%c ",Strtree[i]);
Strtree[i] = '#';//标志节点已被打印为空
k++;
}

if(Strtree[(i+1)*2] != '#')
{
i= (i+1)*2;
}
}
}

//后序遍历实现思想:
//一:对于任意一个节点,先找到它的最左节点,最左节点的下一个左节点一定是空的,判断该兄弟(右)节点:
//二:若为空,回退至父节点,打印并输出该节点,判断该节点的兄弟(右)节点
//三:	若不为空,重复步骤一
//四:	若为空,重复步骤二
//注:判断右节点是否为空之前,先要判断该节点是否为右节点,如果是就要跳过该判断。
//数组的方式存储完全二叉树,除开根节点,右节点所在位置都是偶数,故用:i%2判断
void PostOrderTraverse(BinaryTree tree)
{
char Strtree[Max_Size];
strcpy(Strtree,tree);

if((Is_Empty(Strtree) == 1))
{
return;
}

int len = Count(Strtree);
int i=0,k=0;//i表示节点在完全二叉树中的位置

while(k<len)
{
//新一个右节点就寻找该子树的最左节点
while((Strtree[i] != '#'))
{
i = 2*(i+1)-1;
}

//如果最左节点的兄弟(右)节点不为空,继续下一轮循环
if(Strtree[i+1] != '#' && (i%2 !=0) )
{
i = i + 1;
continue;
}

//回退至父节点
i = (i+1)/2 - 1;
if(Strtree[i] != '#')
{
//printf("i = %d\n",i);
printf("%c ",Strtree[i]);
Strtree[i] = '#';//标志节点已被打印为空
k++;
}

//判断兄弟(右)节点(在完全二叉树中,右节点一定为偶数(除开根节点))
if(Strtree[i+1] != '#')
{
if(i%2 != 0)
{
i= i+1;
}
}
}

}

int main()
{
BinaryTree tree;

char BinaryTree[Max_Size] = "-+/a*ef##b-##########cd";//第一个图
//char BinaryTree[Max_Size] = "fdgbe#iac####hj";//第二个图
//char BinaryTree[Max_Size] = "AB#CD####EF#########G";

InitTree(tree);

CreateTree(tree,BinaryTree);

Length(BinaryTree);

printf("有效节点个数:%d\n",Count(tree));

printf("先序遍历如下:\n");
PreOrderTraverse(tree);

printf("\n中序遍历如下:\n");
MidOrderTraverse(tree);

printf("\n后序遍历如下:\n");
PostOrderTraverse(tree);

return 0;
}


运行结果示例:





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: