文件说明
文件名 | 二叉树.cpp | Mytree.h | MyStack.h | MyQueue.h |
---|---|---|---|---|
包含内容 | 测试代码及遍历算法实现 | 二叉树节点结构及遍历算法声明 | 自建栈类 | 自建队列类 |
1.编写建立二叉树的动态(或者静态)二叉链表存储结构(左右链表示)的程序,并以适当的形式显示和保存二叉树;
二叉树遍历所用到的MyStack栈类:
const int maxlength = 1000;
class MyStack {
public:
MyStack();
void MakeNull();//将栈置空
void Push(BTREE a);//进栈
BTREE Pop();//出栈
bool Empty();//判断栈是否为空
BTREE Top();
public:
BTREE stk[maxlength];//用于存放横坐标、纵坐标
int top;//用于记录栈顶
};
二叉树遍历所用到的MyQueue栈类:
const int Max = 1000;
class Queue {//尾进头出
public:
Queue();//无参构造初始化队列
bool Empty();
void EnQueue( BTREE x);
BTREE DeQueue( );
public:
int front;
int rear;
BTREE d[Max];
};
二叉树的遍历算法声明:
typedef struct node* BTREE;
struct node {
BTREE lchild;
BTREE rchild;
char data;
};
void CreatBT(BTREE& T);//按先序序列建立二叉树的左右链存储结构
void PrintBT(BTREE T);//打印二叉树
void Re_PreOrder(BTREE T);//递归实现先序遍历
void Re_InOrder(BTREE T);//递归实现中序遍历
void Re_PostOrder(BTREE T);//递归实现后序遍历
void PreOrder(BTREE T);//先序遍历
void InOrder(BTREE T);//中序遍历
void PostOrder(BTREE T);//后序遍历
void LevelOrder(BTREE T);//层次遍历
void Visit(BTREE T);//访问节点
bool CheckTree(BTREE T);//判断是否为完全二叉树
int TreeWide(BTREE T);//递归计算二叉树宽度
动态二叉链表结构二叉树的保存和展示:
void CreatBTre(BTREE& T) {//按先序序列建立二叉树的左右链存储结构,#代表节点为空
char ch;
cin >> ch;
if (ch == '#')T = NULL;
else {
T = new node;
T->data = ch;
CreatBTre(T->lchild);
CreatBTre(T->rchild);
}
}
void PrintBT(BTREE T) {//用两种遍历方式唯一地确定一棵树
cout << "这是你所构造的唯一二叉树" << endl;
cout << "其先序序列为";
PreOrder(T);
cout << endl << "其中序序列为";
InOrder(T);
cout << endl;
}
**2.采用二叉树的上述二叉链表存储结构,编写程序实现二叉树的先序、中序和 后序遍历的递归和非递归算法以及层序遍历算法,并以适当的形式显示和保存二叉树及其相应的遍历序列; **
void Re_PreOrder(BTREE T) {//递归先序遍历函数
if (T != NULL) {
Visit(T);//根
Re_PreOrder(T->lchild);//左
Re_PreOrder(T->rchild);//右
}
}
void Re_InOrder(BTREE T) {//递归中序遍历函数
if (T != NULL) {
Re_InOrder(T->lchild);//左
Visit(T);//根
Re_InOrder(T->rchild);//右
}
}
void Re_PostOrder(BTREE T) {//递归后序遍历函数
if (T != NULL) {
Re_PostOrder(T->lchild);//左
Re_PostOrder(T->rchild);//右
Visit(T);//根
}
}
void PreOrder(BTREE T) {//先序遍历
BTREE p = T;
MyStack S;//建栈
while (p || !S.Empty()) {//节点非空或栈不为空
if (p) {//访问节点不为空
Visit(p);//访问根
S.Push(p);//进栈
p = p->lchild;//访问左
}
else {//到底了,碰到空节点
p = S.Pop();//取出栈顶不为空的节点
p = p->rchild;//访问右
}
}
}
void InOrder(BTREE T) {//中序遍历
BTREE p = T;
MyStack S;//建栈
while (p || !S.Empty()) {//节点非空或栈不为空
if (p) {//访问节点不为空
S.Push(p);//进栈
p = p->lchild;//访问左
}
else {//到底了,碰到空节点
p = S.Pop();//取出栈顶不为空的节点
Visit(p);//可以理解为他的左孩子已经访问完了,再访问他自己
p = p->rchild;//访问右
}
}
}
void PostOrder(BTREE T) {//后序遍历
MyStack S;//建栈
BTREE p = T;
BTREE tag = NULL;//用来保存刚访问过的节点,作用是判断是否刚从右边返回
while (p || !S.Empty()) {//节点非空或栈不为空
if (p) {//访问节点不为空
S.Push(p);//进栈
p = p->lchild;//访问左
}
else {//到底了,碰到空节点
p = S.Top();//访问栈顶元素
if (p->rchild && p->rchild != tag)//右边有孩子且不等于标记
p = p->rchild;//访问右
else {//到达后序遍历待访问的第一个节点
p = S.Pop();取出栈顶不为空的节点
Visit(p);//访问自己
tag = p;//标记成自己
p = NULL;
}
}
}
}
void LevelOrder(BTREE T) {//层序遍历
Queue Q;//建立队列
BTREE p;
Q.EnQueue(T);//进队
while (!Q.Empty()) {//队列不为空时
p=Q.DeQueue();//取出队首
Visit(p);//访问队首,由于队列是先进先出,访问顺序就跟入队顺序一样,相当于一层层访问
if (p->lchild)//左不为空
Q.EnQueue(p->lchild);//左进队
if (p->rchild)//右不为空
Q.EnQueue(p->rchild);//右进队
}
}
**3.设计并实现判断任意一棵二叉树是否为完全二叉树的算法。 **
bool CheckTree(BTREE T) {//判断完全二叉树
Queue Q;//建立队列
if (T == NULL)//空树
return true;
Q.EnQueue(T);//进队
BTREE p;
while (!Q.Empty()) {//队列不为空时
p = Q.DeQueue();//取出队首
if (p->lchild && p->rchild) {//左右都有孩子,分别进队,也是一层一层进队的
Q.EnQueue(p->lchild);
Q.EnQueue(p->rchild);
}
else if (p->rchild && !p->lchild)//有右孩子没左孩子,不是完全二叉树,返回
return false;
else {//这一步理应达到完全二叉树的叶子节点或着上一层最右端节点
if (p->lchild && !p->rchild)//有左孩子没右孩子,是上一层最右端节点
Q.EnQueue(p->lchild);//进队
while (!Q.Empty()) {//队列不为空时
p = Q.DeQueue();//取出队首,在这之后应该全为叶子节点了
if (p->lchild || p->rchild)
return false;
}
}
}
return true;
}
4.设计并实现计算任意一棵二叉树的宽度的(递归或非递归)算法。二叉树的 宽度是指其各层结点数的最大值。
int c[100];//这个是用来保存每一层的节点数的,从0层开始。全局变量默认值为0
int M = 0;//用来保存最大节点数
void layer_count(BTREE T, int k)//自顶向下递归找出最大宽度
{
if (T == NULL) return;
c[k]++;
if (M < c[k])
M = c[k];
layer_count(T->lchild, k + 1);
layer_count(T->rchild, k + 1);
}
int TreeWide(BTREE T) {
layer_count(T, 0);
return M;
}
5.测试代码及实验结果
测试代码:
int main() {
BTREE T;
cout << "请用先序序列创建你的二叉树,#代表节点为空" << endl;
CreatBTre(T);
cout << "构造成功" << endl;
PrintBT(T);
cout << "以递归方式先序遍历二叉树" << endl;
Re_PreOrder(T);
cout << endl;
cout << "先序遍历二叉树" << endl;
PreOrder(T);
cout << endl;
cout << "以递归方式中序遍历二叉树" << endl;
Re_InOrder(T);
cout << endl;
cout << "中序遍历二叉树" << endl;
InOrder(T);
cout << endl;
cout << "以递归方式后序遍历二叉树" << endl;
Re_PostOrder(T);
cout << endl;
cout << "后序遍历二叉树" << endl;
PostOrder(T);
cout << endl;
cout << "层序遍历二叉树" << endl;
LevelOrder(T);
cout << endl;
cout << endl;
if (CheckTree(T))
cout << "该树是完全二叉树" << endl;
else
cout << "该树不是完全二叉树" << endl;
cout << "该树的宽度为:" << TreeWide(T) << endl;
return 0;
}
实验结果:
树1:ABDH##I##EJ##K##CF#M##G##
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AWKkcLq3-1677332114698)(2022120067-刘虹志-作业3.assets/1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UJw6wOfR-1677332114698)(2022120067-刘虹志-作业3.assets/3.png)]
树2:ABDH##I##EJ##K##CFL###G##
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iB80i88U-1677332114699)(2022120067-刘虹志-作业3.assets/2.png)]
cout << “该树不是完全二叉树” << endl;
cout << “该树的宽度为:” << TreeWide(T) << endl;
return 0;
}
实验结果:
树1:ABDH##I##EJ##K##CF#M##G##
[外链图片转存中...(img-AWKkcLq3-1677332114698)]
[外链图片转存中...(img-UJw6wOfR-1677332114698)]
树2:ABDH##I##EJ##K##CFL###G##
[外链图片转存中...(img-iB80i88U-1677332114699)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ReUEk7mE-1677332114699)(2022120067-刘虹志-作业3.assets/4.png)]