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
//棧基本實現
#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
/*
* 都在書上有
* 非遞歸算法可以用棧模擬遞歸(不過課本上不是這麼寫的)
*/
#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;
}