开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
1、二叉树的创建
首先简单介绍一下什么是二叉树,像树一样有很多分支,很明显它是非线性结构,我们在创建一个树的时候可以用下图的方式依次赋值。
定一个含有两个指针的结构体,分别为左右子树!!!
定义是顺序栈的结构体
#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、运行截图
图解:
交换左右子树后:
正好满足先根遍历!!!