二叉树的创建与遍历

67 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

1、二叉树的创建

首先简单介绍一下什么是二叉树,像树一样有很多分支,很明显它是非线性结构,我们在创建一个树的时候可以用下图的方式依次赋值。 image.png 定一个含有两个指针的结构体,分别为左右子树!!!

定义是顺序栈的结构体

#define _CRT_SECURE_NO_WARNINGS 1;
#include <stdio.h>
#include <stdlib.h>
#define max 30
//#define NULL 0
#define MAXSIZE 100
typedef struct bnode
{
	char  data;	/*数据域 */
	struct Bnode  *lchild, *rchild;	//指向左右子女  
}*BTree, Bnode;
typedef BTree DataType;

typedef struct//定义顺序栈的结构体,注意DataType是BTree类型
{
	DataType data[MAXSIZE];
	int top;
}SeqStack, *PSeqStack;

2、创建一个完整的栈!!!

//初始化空栈
PSeqStack Init_SeStack()
{
	PSeqStack S;
	S = (PSeqStack)malloc(sizeof(SeqStack));
	if (S)
		S->top = -1;
	return S;
}
//判断空栈
int Empty_SeqStack(PSeqStack S)
{
	if (S->top == -1)
		return 1;
	else
		return 0;
}
//入栈
int Push_SeqStack(PSeqStack S, DataType x)
{
	if (S->top == MAXSIZE - 1)
		return 0;//栈已满,不能入栈
	else
	{
		S->top++;
		S->data[S->top] = x;
		return 1;
	}
}
//出栈
int Pop_SeqStack(PSeqStack S, DataType *x)
{
	if (Empty_SeqStack(S))
		return 0;//空栈,不能能出栈
	else {
		*x = (S->data[S->top]);
		S->top--;
		return 1;
	}
}
//取栈顶元素
int GetTop_SeqStack(PSeqStack S, DataType *x)
{
	if (Empty_SeqStack(S))
		return 0;//空栈,不能出栈
	else {
		*x = S->data[S->top];
		return 1;
	}
}
//销毁栈
void Destroy_SeqStack(PSeqStack *S)
{
	if (*S)
		free(*S);
	*S = NULL;
	return;
}
//打印栈
int Print_SeqStack(PSeqStack S)
{
	if (Empty_SeqStack(S))
		return 0;//空栈,不能打印
	else {
		//printf("打印全栈\n");
		for (int i = S->top; i >= 0; i--) {
			printf("%c", S->data[i]);
		}
		return 1;
	}
}

// 有栈才能搞事情!!栈是用来服务二叉树的,所以要先有二叉树,再来对应栈 //创建二叉链表储存的二叉树的节点!!!!

3、创建二叉树!!!

因为二叉树的每一个节点都未必要有数据,但是我们再赋值的时候依然是按照sha那个图的顺序,那么我们就使用#来表这节点内容为NULL!!!

BTree CreateBinTree()
{
	BTree t;
	char ch;
	ch = getchar();//输入字符!!!
	if (ch == '#') t = NULL;//如果#,就代表我们不想给这个节点赋初值,就直接将结点指向NULL!!!
	else //否则:
	{
		t = (Bnode*)malloc(sizeof(Bnode));//开辟堆区空间
		t->data = ch;//传值
		t->lchild = CreateBinTree(ch++);//递归创建下面的自述子树
		t->rchild = CreateBinTree(ch++);//递归创建下面的自述子树
	}
	return t;
}

函数声明,函数实现放在main函数之后!!!

void preorder(BTree t);
void preorder(BTree t); //声明先根遍历函数
void inorder(BTree t);  //声明中根遍历函数
void postorder(BTree t);//声明后根遍历函数
int leafs(BTree b);      //声明求叶子数函数
int treedeep(BTree p);   //声明求树的深度函数
BTree swap(BTree p);  //声明交换二叉树的所有结点的左右子树的函数
void PreOrder(BTree t);
void PreOrder2(BTree t);
void InOrDer(BTree t);//非递归中根遍历
void PostOrder(BTree t);//非递归后跟遍历

4、测试代码!!!

创建建一个二叉树!!为其复制,并使用六种方法遍历它!!!

void test01()
{
	
	BTree root = CreateBinTree();
	printf("\n");
	//先根遍历
	printf("\n先根遍历结果:");
	preorder(root);
	printf("\n");
	//中根遍历
	printf("\n中根遍历结果:");
	inorder(root);
	printf("\n");
	//后根遍历
	printf("\n后根遍历结果:");
	postorder(root);
	printf("\n");

	printf("\n非递归先根遍历结果:");
	PreOrder(root);//非递归先根遍历
	printf("\n");

	printf("\n非递归中根遍历结果:");
	InOrDer(root);
	printf("\n");

	printf("\n非递归后根遍历结果:");
	PostOrder(root);
	printf("\n");

	printf("\n叶子数为:%d\n", leafs(root));
	printf("\n树的深度为:%d\n", treedeep(root));
	printf("\n交换左右子树后先序遍历序列为:");
	preorder(swap(root));
	printf("\n\n");
}
//ABC##D##EF##G##

main函数::

int main()
{
	test01();
	return 0;
}

六个遍历函数的实现与三个函数!!

1、先根递归

//先根遍历
void preorder(BTree t)
{
	if (t != NULL)
	{
		printf(" %c ", t->data);
		if (t->lchild)
		{
			printf("->");
			preorder(t->lchild);
		}
		if (t->rchild)
		{
			printf("->");
			preorder(t->rchild);
		}
	}
}

2、中根递归

//中根
void inorder(BTree t)
{
	if (t != NULL)
	{
		inorder(t->lchild);
		printf(" %c ", t->data);
		inorder(t->rchild);
	}
}

3、后根递归

//后根
void postorder(BTree t)
{
	if (t != NULL)
	{
		postorder(t->lchild);
		postorder(t->rchild);
		printf(" %c ", t->data);
	}
}

4、求叶子数

int leafs(BTree b)//求叶子数 
{
	int num1, num2;
	if (b == NULL)  return (0);
	else if (b->lchild == NULL && b->rchild == NULL) return (1);
	else
	{
		num1 = leafs(b->lchild);
		num2 = leafs(b->rchild);
		return(num1 + num2);
	}
}

5、求树的深度

int treedeep(BTree p)//求树的深度
{
	int ldeep, rdeep, deep;
	if (p == NULL) deep = 0;
	else
	{
		ldeep = treedeep(p->lchild);
		rdeep = treedeep(p->rchild);
		deep = (ldeep > rdeep ? ldeep : rdeep) + 1;
	}
	return deep;
}

6、交换左右子树

//注意,他这个使用递归实现的,即会交换所有的左右子树!! //通过还原树状图可验证!!!

BTree swap(BTree p)//交换二叉树的所有结点的左右子树
{
	BTree stack[max];
	int k = 0;
	stack[k] = NULL;
	if (p != NULL)
	{
		stack[++k] = p->lchild;
		p->lchild = p->rchild;
		p->rchild = stack[k];
		p->lchild = swap(p->lchild);
		p->rchild = swap(p->rchild);
	}
	return p;
}

7、先根非递归

//非递归遍历 先根
void PreOrder(BTree t)
{
	PSeqStack S;
	BTree p = t;
	S = Init_SeStack();
	while (p||!Empty_SeqStack(S))
	{
		if (p)
		{
			printf("%c", p->data);
			Push_SeqStack(S, p);
			p = p->lchild;
		}
		else
		{
			Pop_SeqStack(S, &p);//回到上一个
			//printf("%c", p->data);
			p = p->rchild;
		}
	}
}
//AB#D##CE##F##

8、中跟非递归

//非递归遍历 后根
void InOrDer(BTree t)
{
	PSeqStack S;
	BTree p = t;
	S = Init_SeStack();
	while (p||!Empty_SeqStack(S))
	{
		if (p)
		{
			Push_SeqStack(S, p);
			p = p->lchild;
		}
		else
		{
			Pop_SeqStack(S, &p);
			printf("%c", p->data);
			p = p->rchild;
		}
	}
}

9、后跟非递归


//非递归算法的 后果跟遍历 
void PostOrder(BTree t)
{
	PSeqStack S1;
	PSeqStack S2;
	BTree p;
	p = t;
	S1 = Init_SeStack();
	S2 = Init_SeStack();
	while (p||!Empty_SeqStack(S2))
	{
		if (p)
		{
			Push_SeqStack(S1, p);
			Push_SeqStack(S2, p);
			p = p->rchild;
		}
		else
		{
			Pop_SeqStack(S2, &p);
			p = p->lchild;
		}
	}
	while (!Empty_SeqStack(S1))
	{
		Pop_SeqStack(S1, &p);
		printf("%c", p->data);
	}
}

5、运行截图

image.png 图解:

image.png

交换左右子树后:

image.png 正好满足先根遍历!!!