2021.10.19数据结构实验课作业——树的操作和应用
1、二叉树的基本操作(必做题)
(1) 使用二叉链表构建二叉树;
(2) 实现二叉树的前序、中序和后序遍历,包括递归算法和非递归算法;
(3) 统计二叉树的深度;
(4) 在二叉树中查找值为X的节点,若存在输出Yes,不存在输出No。
点击查看代码BiTree.h
#pragma once
#include <iostream>
using namespace std;
template <typename T>
struct BiNode {
T data;
BiNode<T> *lchild, *rchild;
BiNode<T>(T x, BiNode<T> *l, BiNode<T> *r) {
data = x;
lchild = l, rchild = r;
}
};
template <typename T>
class BiTree {
public:
BiTree() { root = Creat(); }
~BiTree() { Release(root); }
void PreOrder() {
PreOrder(root);
cout << endl;
}
void InOrder() {
InOrder(root);
cout << endl;
}
void PostOrder() {
PostOrder(root);
cout << endl;
}
int GetDeep() { return GetDeep(root); }
BiNode<T>* GetRoot() { return root; }
private:
BiNode<T> *Creat() {
BiNode <T> *bt;
char ch;
cin >> ch;
if (ch == '#')
bt = NULL;
else {
BiNode<T>* l = Creat();
BiNode<T>* r = Creat();
bt = new BiNode<T>(ch, l, r);
}
return bt;
}
void Release(BiNode<T> *bt) {
if (bt == NULL) return;
Release(bt->lchild);
Release(bt->rchild);
delete bt;
}
void PreOrder(BiNode<T> *bt) {
if (bt == NULL) return;
cout << bt->data << ' ';
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
void InOrder(BiNode<T> *bt) {
if (bt == NULL) return;
InOrder(bt->lchild);
cout << bt->data << ' ';
InOrder(bt->rchild);
}
void PostOrder(BiNode<T> *bt) {
if (bt == NULL) return;
PostOrder(bt->lchild);
PostOrder(bt->rchild);
cout << bt->data << ' ';
}
int GetDeep(BiNode<T> *bt) {
if (bt == NULL)
return 0;
int l = GetDeep(bt->lchild),
r = GetDeep(bt->rchild);
return max(l, r) + 1;
}
BiNode<T> *root;
};
Stack.h
点击查看代码Stack.h
//栈基本实现
#pragma once
const int Maxn = 1001;
template <typename T>
class Stack {
private:
int top;
T sta[Maxn];
public:
Stack() {
top = 0;
}
Stack(int n, T a[]) {
top = n;
for (int i = 0; i < n; ++i)
sta[i] = a[i];
}
void Push(T x) {
if (top == Maxn) throw "Fulled!";
sta[top++] = x;
}
T Pop() {
if (Empty()) throw "Empty!";
return sta[--top];
}
T GetTop() {
if (Empty()) throw "Empty!";
return sta[top-1];
}
bool Empty() {
return top == 0;
}
};
main.cpp
点击查看代码main.cpp
/*
* 都在书上有
* 非递归算法可以用栈模拟递归(不过课本上不是这么写的)
*/
#include <iostream>
#include "BiTree.h"
#include "Stack.h"
using namespace std;
template<typename T>
struct Element
{
BiNode<T>* ptr;
int flag;//flag=1表示左子树已经入栈,=2表示右子树已经入栈
Element() {
ptr = NULL, flag = 0;
}
Element(BiNode<T>* p, int x) {
ptr = p, flag = x;
}
};
template <typename T>
class MyTree : public BiTree<T> {
public:
bool ExistX(T x) { return ExistX(BiTree<T>::GetRoot(), x); }//按值查找
void PreOrderNeg() {
Stack<BiNode<T>* > sta;
BiNode<T>* bt = BiTree<T>::GetRoot();
sta.Push(bt);
while (!sta.Empty()) {
bt = sta.Pop();
cout << bt->data << ' ';
if (bt->rchild != NULL)
sta.Push(bt->rchild);
if (bt->lchild != NULL)
sta.Push(bt->lchild);
}
cout << endl;
return;
}
void InOrderNeg() {
Stack<BiNode<T>* > sta;
BiNode<T>* bt = BiTree<T>::GetRoot();
while (bt != NULL || !sta.Empty()) {
while (bt != NULL) {
sta.Push(bt);
bt = bt->lchild;
}
if (!sta.Empty()) {
bt = sta.Pop();
cout << bt->data << ' ';
bt = bt->rchild;
}
}
cout << endl;
return;
}
void PostOrderNeg() {
Stack<Element<T> > sta;
BiNode<T>* bt = BiTree<T>::GetRoot();
while (bt != NULL || !sta.Empty()) {
while (bt != NULL) {
sta.Push(Element<T>(bt, 1));
bt = bt->lchild;
}
while (!sta.Empty() && sta.GetTop().flag == 2) {
bt = sta.Pop().ptr;
cout << bt->data << ' ';
}
if (!sta.Empty()) {
Element<T> x = sta.Pop();
x.flag = 2;
sta.Push(x);
bt = (x.ptr)->rchild;
}
else bt = NULL;
}
cout << endl;
return;
}
private:
bool ExistX(BiNode<T>* bt, T x) {
if (bt == NULL) return false;
if (x == bt->data)
return true;
return ExistX(bt->lchild, x) || ExistX(bt->rchild, x);
}
};
int main() {
cout << "Please creat the tree_a;" << endl;
MyTree<char> tree_A;
cout << "PreOrder:" << endl;
tree_A.PreOrderNeg();
tree_A.PreOrder();
cout << "InOrder:" << endl;
tree_A.InOrderNeg();
tree_A.InOrder();
cout << "PostOrder:" << endl;
tree_A.PostOrderNeg();
tree_A.PostOrder();
cout << "The depth is: " << tree_A.GetDeep() << endl;
char x;
cout << "Search: ";
cin >> x;
cout << (tree_A.ExistX(x) ? "Yes" : "NO");
return 0;
}
/*
A B D E # # # F # #
C G # # #
*/
2、树的应用:同构树的判断(选做题)
(1) 问题描述:给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。
(2) 输入
输入数据包含多组,每组数据给出2棵二叉树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出”-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。
示例:
8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -
(3) 输出
如果两棵树是同构的,输出“Yes”,否则输出“No”。
示例:
Yes
思路:
/*
- 不需要记录整棵树的结构
- 只需要记录某个节点的左右子树即可
- 比较两棵树是否同构时,在两棵树中找到对应的(data相同)的节点
- 然后比较左右子树
*/
结构体:
struct BiNode {
char data;//节点数据
int l, r;//左右子树编号
}tree_A[N], tree_B[N];
用tree_A和tree_B两个数组记录两棵树
For(tree_A[i])
For(tree_B[j])
if(tree_A[i].data == tree_B[j])
判断左右子树是否相同(对应相同或左右互换相同)
点击查看代码main.cpp
/*
* 不需要记录整棵树的结构
* 只需要记录某个节点的左右子树即可
* 比较两棵树是否同构时,在两棵树中找到对应的(data相同)的节点
* 然后比较左右子树
*/
#include <iostream>
using namespace std;
const int N = 11;
bool flag;
struct BiNode {
char data;
int l, r;
//构造函数
BiNode(char x, int lchild, int rchild) {
data = x;
l = lchild;
r = rchild;
}
BiNode() { data = l = r = 0; }
};
BiNode tree_A[N], tree_B[N];
//判断左右子树互换是否相同
bool judge(BiNode a, BiNode b) {
if(tree_A[a.l].data == tree_B[b.l].data && tree_A[a.r].data == tree_B[b.r].data)
return true;//左右对应
if(tree_A[a.r].data == tree_B[b.l].data && tree_A[a.l].data == tree_B[b.r].data)
return true;//左右互换
return false;
}
int main()
{
int n, m; char ch, a, b;
cin >> n;
tree_A[0].data = tree_B[0].data = '-';
for(int i=1; i<=n; ++i) {
cin >> ch >> a >> b;
if(a == '-') a=0;
else a-='0'-1;
if(b == '-') b=0;
else b-='0'-1;
tree_A[i] = BiNode(ch, a, b);
}
cin >> m;
for(int i=1; i<=m; ++i) {
cin >> ch >> a >> b;
if(a == '-') a=0;
else a-='0'-1;
if(b == '-') b=0;
else b-='0'-1;
tree_B[i] = BiNode(ch, a, b);
}
/*
for(int i=1; i<=n; ++i)
cout << tree_A[i].data << ' ' << tree_A[i].l << ' ' << tree_A[i].r << endl;
cout << endl;
for(int i=1; i<=m; ++i)
cout << tree_B[i].data << ' ' << tree_B[i].l << ' ' << tree_B[i].r << endl;
*/
if(n != m) {//节点数不同必定不同构
cout << "No";
return 0;
}
bool flag = true;//true表示同构
for(int i=1; i<=n && flag; ++i) {
for(int j=1; j<=n; ++j) {
if(tree_A[i].data == tree_B[j].data)//找data相同的节点
if(!judge(tree_A[i], tree_B[j])) {
flag = false;
break;
}
}
}
cout << (flag?"Yes":"No");
return 0;
}