二叉树的基本操作(C语言)

目前正在学习数据结构,这是二叉树这一章的基本操作的内容,包括创建二叉树,树的前序,中序,后序遍历的递归和非递归算法。借鉴了大佬们的代码,然后分享出来,希望能帮到别人。

注意:

一、 

这是用递归先序的方法创建二叉树,如果有不懂的可去B站搜索“懒猫老师”,她讲的很好,一听就能懂。

二、

非递归遍历二叉树,也是利用了栈,建立一个顺序栈,用数组实现,定义的“int box_top“不是指针,只是将它当做数组的下标,以便使用的方便。把栈顶指针“(box_top)”指向-1,是为了和数组下标保持一致。如果有看不懂那个代码的可以自己先在草稿本上手动模拟以便执行过程,这样再来理解代码就很容易了。

三、递归创建二叉树的代码

//按(递归)先序次序输入二叉树中节点的值(一个字符),创建二叉链表表示的二叉树T
BiTNode*  CreatBiTree(BiTNode *T)
{
	char ch;
	scanf("%c",&ch);
	if(ch=='#') T=NULL;//如果接收的字符为“#”,就返回一个空值
	else
	{
		T=(BiTNode *)malloc(sizeof(BiTNode));//动态申请一个节点空间
		T->data=ch;							//将ch的值赋给T->data域
		T->lchild=CreatBiTree(T->lchild);	//递归调用到左子树的某个节点的左孩子节点为空(输入为#)时,返回空,并将这个空值赋给该节点的左孩子域。
		T->rchild=CreatBiTree(T->rchild);	//递归调用到右子树的某个节点的右孩子节点为空(输入为#)时,返回空,并将这个空值赋给该节点的右孩子域。
	}
	return T;	
}

 四、完整代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#define MaxSize 100
#define OK 1
#define ERROR 0
typedef char ElemType;
typedef int Status;
typedef struct BiTNode{
	ElemType data;//节点中的数据元素
	struct BiTNode *lchild;
	struct BiTNode *rchild;
}BiTNode,*BiTree;
//初始化建立二叉树
void  inittree(BiTNode* T)
{
	T->data ="";
	T->rchild = NULL;
	T->lchild = NULL;
}
//按(递归)先序次序输入二叉树中节点的值(一个字符),创建二叉链表表示的二叉树T
BiTNode*  CreatBiTree(BiTNode *T)
{
	char ch;
	scanf("%c",&ch);
	if(ch=='#') T=NULL;//如果接收的字符为“#”,就返回一个空值
	else
	{
		T=(BiTNode *)malloc(sizeof(BiTNode));//动态申请一个节点空间
		T->data=ch;							//将ch的值赋给T->data域
		T->lchild=CreatBiTree(T->lchild);	//递归调用到左子树的某个节点的左孩子节点为空(输入为#)时,返回空,并将这个空值赋给该节点的左孩子域。
		T->rchild=CreatBiTree(T->rchild);	//递归调用到右子树的某个节点的右孩子节点为空(输入为#)时,返回空,并将这个空值赋给该节点的右孩子域。
	}
	return T;	
}
//用二级指针创建二叉树
void Createtree(BiTNode* *node)
{
	char p_data;
	scanf("%c",&p_data);
	if(p_data=='#')
		(*node)=NULL;
	else
	{
		*node=(BiTNode*)malloc(sizeof(BiTNode));
		(*node)->data=p_data;
		Createtree(&((*node)->lchild));
		Createtree(&((*node)->rchild));
	}
}
//二叉树判空
int tempty(BiTNode *T)
{
	if(T->data=="")
	{
		printf("二叉树为空\n");
		return 0;
	}
	else
	{
		printf("二叉树不为空\n");
		return 0;
	}
}

	
//对二叉树进行先序遍历(递归),输出各个节点的值
void proder(BiTNode *T)
{
	if(T!=NULL)//判断二叉树是否为空
	{
		printf("%c  ",T->data);
		proder(T->lchild);
		proder(T->rchild);			
	}
}

//中序遍历二叉树(递归),输出各个节点的值
void morder(BiTNode *T)
{
	if(T!=NULL)
	{
		morder(T->lchild);
		printf("%c  ",T->data);
		morder(T->rchild);
		
	}
}
//后序遍历二叉树(递归),输出各个节点值
void torder(BiTNode *T)
{
	if(T!=NULL)
	{
		morder(T->lchild);
		morder(T->rchild);
		printf("%c \n ",T->data);
		
	}
}

//非递归先序遍历
//在递归中其实也是用到了栈的,所以可以用栈来代替递归的功能
void p_porder(BiTNode *T)
{
	if(T==NULL)//判断树是否为空
		return ;
	BiTNode* box[10];//申明一个可以存放BiTNode类型的地址的顺序栈,用来存放当前打印节点的位置
	int box_top=-1;//为使栈顶指针和数组下标保持一致,让栈顶指针指向-1
	BiTNode* move = T;//递归过程中移动的指针
	while (box_top!= -1||move)
	{
		while(move)
		{
			printf("%c ",move->data);//访问move所指向的节点
			box[++box_top]=move;//把该结点入栈
			move=move->lchild;//移动到访问过的结点的左子树
		}
		if(box_top!=-1)//判断是否访问完左子树
		{
			move=box[box_top];//获取栈顶指针
			box_top--;//回溯
			move=move->rchild;//移动到右子树
		}
	}
	printf("\n");
}
//中序非递归遍历
//指针先移动到左子树的最后一个结点并打印,然后再访问根节点,再访问右子树。
void m_morder(BiTNode *T)
{
	BiTNode* box[10];//创建栈
	int box_top=-1;//定义栈顶指针
	BiTNode* move=T;//定义移动指针
	while(box_top!=-1||move)
	{
		//访问左子树
		while(move)
		{
			box[++box_top]=move;
			move=move->lchild;
		}
		if(box_top!=-1)
		{
			move=box[box_top--];//取栈顶指针
			printf("%c  ",move->data);
			move=move->rchild;//移动到右子树,若右子树非空,则继续循环
		}
	}
	printf("\n");
}

//后序非递归遍历
//先访问左子树一直深入直到无法访问,打印节点然后回溯,再访问右子树
//访问完右子树再回溯,因为回溯,会导致打印两次根节点,所以需要定义一个标记,将打印过的节点标记
void t_torder(BiTNode* T)
{
	if(T==NULL)
		return;
	BiTNode* box[10];
	int  box_top=-1;
	BiTNode* move=T;
	BiTNode* visit=NULL;//访问标记
	while (move)
	{
		box[++box_top]=move;
		move=move->lchild;
	}
	while(box_top !=-1)
	{
		move=box[box_top--];
		if(move->rchild==NULL||move->rchild==visit)
		{
			printf("%c  ",move->data);
			visit=move;//访问完就标记,然后回溯到上一层
		}
		else
		{
			box[++box_top]=move;
			move=move->rchild;
			while(move)
			{
				box[++box_top]=move;
				move=move->lchild;
			}
		}
	}
	printf("\n");
}

//求二叉树的叶子结点数
int leaves(BiTNode* T)
{
	if(T==NULL)
		return 0;
	else if(T->lchild==NULL && T->rchild==NULL)//若左孩子或者右孩子不为空,则返回1;
		return 1;
	else
		return leaves(T->lchild)+leaves(T->rchild);//递归调用
}
//求树的深度的递归算法
int deep(BiTNode* T)
{
	int lnum,rnum;
	if(T==NULL)
		return 0;
	else
	{
		lnum =deep(T->lchild);
		rnum =deep(T->rchild);
		return(lnum>rnum?lnum:rnum)+1;
	}
}
int main()
{
	BiTNode *T=(BiTNode *)malloc(sizeof(BiTNode));
	inittree(T);
	Createtree(&T);
	//T=CreatBiTree(T);
	tempty(T);
	printf("先序遍历结果:......................\n");
	proder(T);
	printf("\n");
	printf("中序遍历结果:......................\n");
	morder(T);
	printf("\n");
	printf("后序遍历结果:......................\n");
	torder(T);
	printf("非递归先序遍历结果:......................\n");
	p_porder(T);
	printf("非递归中序遍历结果:......................\n");
	m_morder(T);
	printf("非递归后序遍历结果:......................\n");
	t_torder(T);
	printf("叶子结点个数为:%d",leaves(T));
	free(T);
	
}

五、执行结果

这里按照先序遍历的顺序输入字符,注意这里是一次性输入。#代表这个结点为空。我的输入是ABC##DE#G##F###,如果想测试其他数据的也可以再换其他的。

猜你喜欢

转载自blog.csdn.net/qq_53764714/article/details/127394989
今日推荐