(1)实验目的
通过该实验,使学生理解二叉树的链式存储,掌握二叉树的几种遍历算法,并通过该实验使学生理解递归的含义,掌握C语言编写递归函数的方法和注意事项。
(2)实验内容
实现教材中算法6.4描述的二叉树创建算法,在此基础上实现二叉树的先序、后序递归遍历算法、两种非递归中序遍历、层序遍历、求二叉树的深度。注意:在非递归算法中用到栈和队列时,不要调用系统的栈和队列,需要自己实现栈和队列的操作。
(3)参考界面
(4)验收/测试用例
- 创建
输入 :ABC$$DE$G$$F$$$ ($表示空格)
该输入对应的树如图所示
- 先序 屏幕输出 A B C D E G F
- 后序 屏幕输出 C G E F D B A
- 中序 屏幕输出 C B E G D F A
(两种中序非递归还需看源代码)
- 层序 屏幕输出 A B C D E F G
- 深度 屏幕显示 深度为5
- 另外自己画出一棵树,再测试一遍
#include<iostream>
using namespace std;
#define STACK_INIT_SIZE 100 //存储空间分配初始量
#define STACKINCREMENT 10
typedef int status;
typedef int TElement;//二叉树
typedef int QElemType;//队列
typedef int SElemType;//栈
//二叉树的结构体
typedef struct BiTNode {//定义一个结构体用来存储二叉链表
TElement data;//数据域
struct BiTNode* lchild, * rchild;//左右孩子指针域
}BiTNode, * BiTree;//BiTree表示这个指针,里面包含数据域,指针域
BiTree T;
//栈的结构体
typedef struct {
BiTree* base;
int top;
int stacksize;
}SqStack;
SqStack S;
//队列的结构体
typedef struct QNode {
BiTree data;
struct QNode* next;
}QNode, * QueuePtr;
typedef struct {
QueuePtr front;
QueuePtr rear;
}LinkQueue;
LinkQueue Q;
BiTree CreateBiTree(BiTree& T);//1
status FirstBiTree(BiTree& T);//2
status CenterBiTreeOne(BiTree& T);//3
status CenterBiTreeTwo(BiTree& T);//4
status LastBiTree(BiTree& T);//5
status LevelBiTree(BiTree& T);//6
status Depth(BiTree& T);//7
int main() {
cout << "~~~~~~用户选择界面~~~~~~" << endl;
cout << "1、创建二叉树" << endl;
cout << "2、先序遍历二叉树" << endl;
cout << "3、中序遍历二叉树1" << endl;
cout << "4、中序遍历二叉树2" << endl;
cout << "5、后序遍历二叉树" << endl;
cout << "6、层序遍历二叉树" << endl;
cout << "7、求二叉树的深度" << endl;
cout << "输入一个负数退出" << endl;
int x;
while (1) {
cout << "-------------------------" << endl;
cout << "请输入您的选择:" ;
cin >> x;
if (x < 0) {
cout << "程序已经退出" << endl;
break;
}
else {
switch (x) {
case 1:
cout << "请将您想要创建的二叉树按先序输入,每个结点都必须有孩子,没有的就输入$" << endl;
CreateBiTree(T);
cout << "输入完毕,二叉树创建成功" << endl;
break;
case 2:
if (T == NULL) {
cout << "请先创建二叉树" << endl;
}
else {
cout << "前序遍历二叉树的结果是:" << endl;
FirstBiTree(T);
cout << " " << endl;
}
break;
case 3:
if (T == NULL) {
cout << "请先创建二叉树" << endl;
}
else {
cout << "方法一中序遍历二叉树的结果是:" << endl;
CenterBiTreeOne(T);
cout << " " << endl;
}
break;
case 4:
if (T == NULL) {
cout << "请先创建二叉树" << endl;
}
else {
cout << "方法二中序遍历二叉树的结果是:" << endl;
CenterBiTreeTwo(T);
cout << " " << endl;
}
break;
case 5:
if (T == NULL) {
cout << "请先创建二叉树" << endl;
}
else {
cout << "后序遍历二叉树的结果是:" << endl;
LastBiTree(T);
cout << " " << endl;
}
break;
case 6:
if (T == NULL) {
cout << "请先创建二叉树" << endl;
}
else {
cout << "层序遍历二叉树的结果是:" << endl;
LevelBiTree(T);
cout << " " << endl;
}
break;
case 7:
if (T == NULL) {
cout << "请先创建二叉树" << endl;
}
else {
cout << "二叉树的深度是:" << endl;
int depth = Depth(T);
cout << depth << endl;
}
break;
}
}
}
system("pause");
return 0;
}
//1、创建二叉树
BiTree CreateBiTree(BiTree& T) {
char ch;
cin >> ch;
if (ch == '$')T = NULL;
else {
if (!(T = (BiTNode*)malloc(sizeof(BiTNode))))exit(OVERFLOW);
T->data = ch;
CreateBiTree(T->lchild);//由于不知什么时候结束,用递归比较好。输入一定的空格后发现T不存在就结束了,所以不需要额外设置标志
CreateBiTree(T->rchild);
}
return T;
}
//2、先序遍历二叉树
status FirstBiTree(BiTree& T) {
if (T) {
cout << (char)T->data << " ";//这里必须强制转换类型,转换成char类型,否则输出的数据与插入的不一样
FirstBiTree(T->lchild);
FirstBiTree(T->rchild);
}
else {
return 0;
}
}
//34-1栈的初始化和入栈出栈
status InitStack(SqStack& S) {
S.top = 0;
S.stacksize = 0;
S.base = (BiTree*)malloc(sizeof(BiTree));
return true;
}
status Push(SqStack& S, BiTree t) {
S.stacksize++;//进去一个就多加一个空间,用来存储这个指针
S.base = (BiTree*)realloc(S.base, sizeof(BiTree) * (S.stacksize));//这是多加的空间
S.base[S.top++] = t;//这里的top就相当于一个索引,这里是第0个,进去后再进就是第一个,二top一直在最后一个元素的后面
return true;
}
BiTree Pop(SqStack& S, BiTree t) {
if (S.stacksize <= 0) {
return NULL;
}
t = S.base[--S.top];//top指向最后一个元素的下一个,所以先减一
S.stacksize--;//出栈的时候把空间减一
return t;//因为这里的返回值类型是BiTree类型,所以函数类型也必须改成BiTree
}
BiTree GetTop(SqStack& S, BiTree t) {
t = S.base[S.top - 1];
return t;
}
//3、中序遍历二叉树1
status CenterBiTreeOne(BiTree& T) {
InitStack(S);
BiTree B = T;
while (B || S.stacksize != 0) {
if (B) {
Push(S, B);
B = B->lchild;
}
else {
B = Pop(S, B);
cout << (char)B->data << " ";
B = B->rchild;
}
}
return 1;
}
//4、中序遍历二叉树2
status CenterBiTreeTwo(BiTree& T) {
InitStack(S);
BiTree B = T;
Push(S, B);//根指针进
while (S.stacksize != 0) {
B = GetTop(S, B);//取出栈顶元素用于判断
while (B) {
Push(S, B->lchild);//向左走到尽头
B = GetTop(S, B);//这里到最后一步的时候,栈顶元素为空了,就退出了
}
Pop(S, B);//空指针退栈,这里的空就是上面的最左边元素的左边为空
B = Pop(S, B);//取出栈顶元素,并把它释放掉
if (B != NULL) {
cout << (char)B->data << " ";
Push(S, B->rchild);//这里第一次循环时,我举得例子中这个元素的右孩子为空,
//所以空指针入栈,下一次循环时,因为栈顶元素为空,所以不会再向左一直取,一旦这个元素的右孩子不为空
//那么下一次循环会一直向左,直到找到最左边的指针为止,然后再进行以上操作,也就是把这个节点的右子树取完。
}
}
return 0;
}
//5、后序遍历二叉树
status LastBiTree(BiTree& T) {
if (T) {
LastBiTree(T->lchild);
LastBiTree(T->rchild);
cout << (char)T->data << " ";
}
else {
return 0;
}
}
//6-1层序遍历里的入队出队操作
status InitQueue(LinkQueue& Q) {
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));//给这两个指针分配空间,队头队尾相等说明队列为空
if (!Q.front)exit(OVERFLOW);
Q.front->next = NULL;//初始化后队头指针的下一个元素是空
return 1;
}
status EnQueue(LinkQueue& Q, BiTree t) {
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if (p == NULL) {
return 0;
}
else {
p->data = t;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return 1;
}
}
BiTree DeQueue(LinkQueue& Q) {
QueuePtr p;
p = Q.front->next;
BiTree t;
if (p == NULL) {
return 0;
}
else {
t = p->data;
Q.front->next = p->next;
if (Q.rear == p)Q.front = Q.rear;
free(p);
return t;
}
}
//6、层序遍历二叉树
status LevelBiTree(BiTree& T) {
LinkQueue Q;
InitQueue(Q);
BiTree C = T;
if (C) {
EnQueue(Q, C); //把根节点入队
while (Q.front != Q.rear) {
C = DeQueue(Q);//这里出队一个下一个循环就入队这个的孩子,这个的位置不重要,因为每次只能出队一个元素
cout << (char)C->data << " ";//输出队头元素,输出后就把他们的孩子进来
if (C->lchild != NULL) {
EnQueue(Q, C->lchild);
}
if (C->rchild != NULL) {
EnQueue(Q, C->rchild);
}
}
}
return 0;
}
//7、求二叉树的深度
int max(int a, int b) {
return a > b ? a : b;
}
status Depth(BiTree& T) {
if (T == NULL) {
return 0;
}
else {
int h1 = Depth(T->lchild);
int h2 = Depth(T->rchild);//不管这个子树存在不存在都可以遍历,返回的都是0,取最大永远取不到它
return max(h1, h2) + 1;
}
}