实验目的:

1、掌握二叉树的定义。

2、二叉树的链式存储结构及在链式存储结构中三种遍历(前序,中序,后序)操作的实现及应用。

实验内容:

编写程序,实现以下功能:

(1)建立一棵二叉树(以链表存储),对该二叉树进行遍历并输出该二叉树的前序,中序,后序遍历序列。要求前序、中序遍历用非递归方法,后序遍历用递归方法完成。

(2)实现二叉树左右子树的交换。

(3)统计二叉树中叶子结点个数。(要求用非递归算法完成)

基本要求:

1、写出完成实验内容的实验方法和源代码。

2、写出实验数据及运行结果。

3、写出在实验过程中所遇到的问题及解决办法。

实验方法:

1.二叉树采用链式存储结构,以链表实现,每个节点里面有一个字符型数据和两个左右子树节点的指针,创建二叉树时先输入父节点的值,然后输入左子节点然后右子节点,空节点以0表示。

2.前序和中序遍历还有统计二叉树中叶子节点个数采用非递归算法完成,使用栈来实现。

3.后续遍历则采用递归,递归实质上也是使用栈实现的。

4.左右树的交换利用一个辅助指针,将根节点的左右子树节点交换。

5.我在本次实验基础上还增加了一个输出二叉树的功能,这样会更加直观,帮助理解三种遍历的区别。打印二叉树需要以二叉树的遍历为基础,我们要打印出每一个节点就需要对每一个节点进行遍历,在遍历二叉树时递归的先序更为简单,而控制台打印时只能一行一行的打印,所以我们可以先根据二叉树的高度和宽度创建一个动态的数组,再通过前序遍历的方法将每个节点的数据存入数组中,同时向数组中填入连线和空格要打印出来的图形先存储到一个数组中最终通过输出数组打印二叉树。

代码图:

 代码部分:

#include<stdio.h>
#include<stdlib.h> 
#include<string.h>
#define MaxSize 20
//链二叉树类型
typedef struct Node
{
	char data;		
	struct Node* lchild;//左孩子节点
	struct Node* rchild;//右孩子节点
}*BinaryTree;
int width = 0, height = 0;
//创建二叉树
BinaryTree CreatTree()
{
	BinaryTree tree;
	//scanf_s("%d",&data); //整型数据的输入
	//字符型数据的输入
	int temp = getchar();  //吸收回车
	int data = getchar();
	if (data==48)          //空节点以0表示
	{
		return NULL;       //数据域为-1代表此节点不存数据,左右子节点指针置为NULL,不继续指向子节点
	}
	else
	{
		tree = (BinaryTree)malloc(sizeof(Node));
		if (tree != NULL)
		{
			tree->data = data;
			printf("请输入%c树的左叶子节点的值!\n",data);
			tree->lchild = CreatTree();
			printf("请输入%c树的右叶子节点的值!\n",data);
			tree->rchild = CreatTree();
			return tree;
		}
	}
}
//求树的高度
int TreeHeight(BinaryTree tree)
{
	int lchildh, rchildh;
	if (tree == NULL)
	{
		return 0;
	}
	else
	{
		lchildh = TreeHeight(tree->lchild);
		rchildh = TreeHeight(tree->rchild);
		return (lchildh > rchildh ? lchildh+1 : rchildh+1);
	}
}
//非递归前序遍历
void FrontPrint(BinaryTree tree)
{
	    BinaryTree Stack[MaxSize], node = NULL;	//创建栈,创建节点
		int top = -1;		  //栈顶指针  
		if (tree != NULL)     //如果树不为空
		{
			Stack[0] = tree;  //根节点入栈
			top++;
			while (top!=-1)   //如果栈不为空
			{
				node = Stack[top];
				printf("%c\t",node->data);//出栈
				top--;
				if (node->rchild != NULL)
				{
					Stack[++top] = node->rchild;//右孩子不为空先进栈
				}
				if (node->lchild != NULL)
				{
					Stack[++top] = node->lchild;//左孩子不为空先进栈
				}
			}
	}
}
//非递归中序遍历
void MiddlePrint(BinaryTree tree)
{ 
	BinaryTree stack[MaxSize], node = NULL;//创建栈
	int top = -1;	                       //栈顶指针
	while (top!=-1 || tree!=NULL)          //栈或树非空
	{
		while (tree!=NULL)
		{
			stack[++top] = tree;
			tree = tree->lchild;
		}
		if (top!=-1)
		{
			node = stack[top--];
			printf("%c\t", node->data);
		    tree = node->rchild;
		}
	}
}
//后序遍历
void LastPrint(BinaryTree tree)
{
	if (tree == NULL)
	{
		return;//遍历到的当前节点如果为空则返回
	}
	LastPrint(tree->lchild);
	LastPrint(tree->rchild);
	printf("%c\t", tree->data);
	
}
//左右树的交换
void ChangeTree(BinaryTree tree)
{
	if (tree == NULL)
	{
		printf("树为空,左右树交换失败!\n");
	}
	else 
	{
		BinaryTree temp; //辅助交换的指针
		temp = tree->rchild;
		tree->rchild = tree->lchild;
		tree->lchild = temp;
		printf("\n左右子树交换成功!\n\n");
	}
}
//统计叶子节点个数
int CalTreeLeaf(BinaryTree tree)
{
	int top = -1; // 栈为空
	int count = 0;
	BinaryTree s[MaxSize]; //创建栈

	while (tree != NULL || top != -1) // 当前节点不为空或栈不为空
	{
		while (tree != NULL) // 当前节点不为空
		{
			if (tree->lchild == NULL && tree->rchild == NULL) // 若当前根节点的左右子树都为空,则是叶子节点
				count++;
			s[++top] = tree; // 先 ++top,然后将当前的根节点入栈

			tree = tree->lchild; // 然后访问当前根节点的左子树

		}
		if (top != -1) // 栈不为空
		{
			tree = s[top--]; 
			tree = tree->rchild; 
		}
	}

	return count;
}//打印二叉树
//打印二叉树
void Print(BinaryTree tree, char* a, int i, int j)//a是数组 i,j是当前节点在数组中的位置
{
	int ti, tj;
	if (tree!=NULL) //如果该位置有节点
	{
		*(a + (i * width) + j) = tree->data; //向数组该点填入字符
		if (tree->lchild!=NULL) //有左右孩子给对应的连接线,左右孩子的值在下一层递归赋值
		{
			for (ti = i + 1, tj = j - 1; tj > j - (height - i + 1) / 2; tj--)//将该点与其左孩子之间的连线全部填上'/'
			{
				*(a + ((ti)*width) + tj) = '/';
				ti++;
			}
		}
		if (tree->rchild!=NULL)
		{
			for (ti = i + 1, tj = j + 1; tj < j + (height - i + 1) / 2; tj++)
			{
				*(a + ((ti)*width) + tj) = '\\';
				ti++;
			}
		}
		if (tree->lchild == NULL && tree->rchild == NULL)
			return;
		Print(tree->lchild, a, ti, j - (height - i + 1) / 2);//经过循环,ti恰好指到其孩子所在的层
		Print(tree->rchild, a, ti, j + (height - i + 1) / 2);
	}
}
void printTree(BinaryTree tree)
{
	int i, j;
	int n = TreeHeight(tree); //计算高度
	width = (2 << n) - 3;  // 2^(n+1)-3   一个数据左移1位就相当于乘以2的1次方
	height = (2 << (n - 1)) - 1; // 2^n-1
	char* a = (char*)malloc(sizeof(char) * (width * height));//创建数组
	memset(a, 0, sizeof(char) * (width * height));//数组初始化
	Print(tree, a, 0, (width - 1) / 2);	//调用Print函数,填充打印数组
	for (i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
		{
			if (*(a + (i * width) + j) == '/')
			{
				printf("/");
			}
			else if (*(a + (i * width) + j) == '\\')
			{
				printf("\\");
			}
			else if (*(a + (i * width) + j) == 0)
			{
				printf(" ");
			}
			else
			{
				printf("%c", *(a + (i * width) + j));
			}
		}
		printf("\n");
	}
}
int main()
{
	BinaryTree tree=NULL;
	int choice = 0,h=0,num=0;
	while (choice != 8)
	{
		printf("*******************************\n");
		printf("***      1.创建二叉树       ***\n");
		printf("***      2.前序遍历         ***\n");
		printf("***      3.中序遍历         ***\n");
		printf("***      4.后续遍历         ***\n");
		printf("***      5.求树的高度       ***\n");
		printf("***      6.左右子树交换     ***\n");
		printf("***      7.统计叶子结点个数 ***\n");
		printf("***      8.退出             ***\n");
		printf("*******************************\n");
		scanf_s("%d", &choice);
		switch (choice)
		{
		case 1:
			printf("\n请输入树的节点的值!(节点类型为字符型,空节点用0表示)\n");
			tree = CreatTree();//创建二叉树
			system("cls");
			printf("\n创建成功!\n");
			printTree(tree);//打印二叉树
			break;
		case 2:
			system("cls");
			printTree(tree);
			printf("\n前序遍历结果为:\n");
			FrontPrint(tree);//非递归前序遍历
			printf("\n\n");
			break;
		case 3:
			system("cls");
			printTree(tree);
			printf("\n中序遍历结果为:\n");//非递归中序遍历
			MiddlePrint(tree);
			printf("\n\n");
			break;
		case 4:
			system("cls");
			printTree(tree);
			printf("\n后续遍历结果为:\n");
			LastPrint(tree);  //递归后序遍历
			printf("\n\n");
			break;
		case 5:
			system("cls");
			printTree(tree);
			h = TreeHeight(tree);
			printf("\n树的高度为:%d\n\n", h);
			break;
		case 6:
			system("cls"); 
			printTree(tree);
			ChangeTree(tree);
			printTree(tree);
			break;
		case 7:
			system("cls");
			printTree(tree);
			num = CalTreeLeaf(tree);
			printf("\n叶子结点个数为:%d\n",num);
			break;
		case 8:
			break;
		default:
			system("cls");
			printf("\n没有此选项,请重新选择!\n\n");
			break;
		}
	}
}

实验数据

创建二叉树 

 

 

 

前序遍历

 

中序遍历

 

后续遍历

 

求树的高度

 

左右子树交换

统计叶子节点个数

 

 

实验总结略 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐