结点的构建
class BiTreeNode {
public:
char data;//存放数据,结点的数据域
BiTreeNode* LeftChild;//左子树指针,结点指针域
BiTreeNode* RightChild;//右子树指针,结点指针域
BiTreeNode() { LeftChild = NULL; RightChild = NULL; }
~BiTreeNode(){}
};
树的构建
//树构造
class BiTree {
private:
BiTreeNode* Root;//根节点指针
string strTree;//字符串
int pos;
BiTreeNode* CreateBiTree();//构造二叉树(先序遍历法)
void PreOrder(BiTreeNode* t);//先序遍历
void InOrder(BiTreeNode* t);//中序遍历
void PostOrder(BiTreeNode* t);//后序遍历
public:
void CreateTree(string TreeArray);//构造二叉树接口
void PreOrder();//先序遍历接口
void InOrder();//中序遍历接口
void PostOrder();//后序遍历接口
};
利用先序遍历法构造二叉树
//利用先序遍历法构造二叉树
void BiTree::CreateTree(string TreeArray) {//共有函数,对外接口
pos = 0;
strTree.assign(TreeArray);//字符串复制
Root = CreateBiTree();
}
BiTreeNode* BiTree::CreateBiTree() {//递归建树,私有函数,类内实现
BiTreeNode* T;
char ch;
ch = strTree[pos++];//取字符串pos的位置元素,先赋值后加加
if (ch == '0') {
T = NULL;
}
else {
T = new BiTreeNode();//构造新结点
T->data = ch;//数据域赋值
T->LeftChild = CreateBiTree();//指针域成为新的结点继续构造二叉树
//左结点先构建完再构建右结点,为先序遍历法
T->RightChild = CreateBiTree();//指针域成为新的结点继续构造二叉树
}
return T;
}
先序遍历法
//先序遍历
void BiTree::PreOrder() {
PreOrder(Root);
}
void BiTree::PreOrder(BiTreeNode* t) {
if (t) {
cout << t->data;
PreOrder(t->LeftChild);
PreOrder(t->RightChild);
}
}
中序遍历法
//中序遍历
void BiTree::InOrder() {
InOrder(Root);
}
void BiTree::InOrder(BiTreeNode* t) {
if (t) {
InOrder(t->LeftChild);
cout << t->data;
InOrder(t->RightChild);
}
}
后序遍历法
//后序遍历
void BiTree::PostOrder() {
PostOrder(Root);
}
void BiTree::PostOrder(BiTreeNode* t) {
if (t) {
PostOrder(t->LeftChild);
cout << t->data;
PostOrder(t->RightChild);
}
}
层次遍历法
从上到下,从左到右进行遍历输出
利用队列先进先出的性质:先把根节点放入队列中,把队首元素出队列,再把队首元素的左孩子和右孩子(如果存在的话)也放入队列中,依次进行遍历,直到队空。
//层次遍历,利用队列先进先出的性质
#include <queue>
void BiTree::LevelOrder() {
LevelOrder(Root);
}
void BiTree::LevelOrder(BiTreeNode* t) {
//用队列实现
queue<BiTreeNode*> tq;//创建队列tq,队列的每个元素都是结点指针
BiTreeNode* p = t;//p是指向当前变量的指针
if (p) {
tq.push(p);//若p不为空,则p进入队列
}
while (!tq.empty()) {
//队列不为空时,循环
p = tq.front();//p指向tq队列的头元素
tq.pop();//弹出
cout << p->data;
if (p->LeftChild) {
tq.push(p->LeftChild);//传入其左孩子
}
if (p->RightChild) {
tq.push(p->RightChild);//传入其右孩子
}
}
cout << endl;
}
后序非递归遍历
//后序非递归遍历,用到栈先进后出的性质
#include <stack>
void BiTree::void LastOrder() {
LastOrder(Root);
}
}void BiTree::LastOrder(BiTreeNode* t) {
int tag = 0;
stack<BiTreeNode*> S1;//S1栈,用于存放结点
stack<int> S2;//S2栈,用于存放tag值
BiTreeNode* p = t;//结点p指向当前结点
do {
while (p) {
S1.push(p);
tag = 0;
S2.push(tag);
p = p->LeftChild;
if (S1.empty()) {
break;
}
}
while (!p) {
if (S2.top() == 0) {
//访问完左子树
S2.top() = 1;//把tag值改为1
p = S1.top()->RightChild;//接下来访问右结点
}
else if (S2.top() == 1) {
//访问完右子树,弹出结点并输出结点
p = S1.top();
S1.pop();
S2.pop();
cout << p->data;
p = NULL;
}
if (S2.empty()) {
break;
}
}
} while (!S1.empty());
cout << endl;
}
二叉树的数组存储
用数组的形式表示树,并根据数组进行遍历输出
用到二叉树的性质5:左子树=根节点*2,右子树=根节点*2+1
因为用到的是数组,数组下标是从0开始的,因此左子树=根节点*2+1,右子树=根节点*2+2
题目描述:
二叉树可以采用数组的方法进行存储,把数组中的数据依次自上而下,自左至右存储到二叉树结点中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点就在数组中用0来表示。
如下图所示:
从上图可以看出,右边的是一颗普通的二叉树,当它与左边的完全二叉树对比,发现它比完全二叉树少了第5号结点,所以在数组中用0表示,同样它还少了完全二叉树中的第10、11号结点,所以在数组中也用0表示。结点存储的数据均为非负整数。
输入:
第一行输入一个整数t,表示有t个二叉树
第二行起,每行输入一个数组,先输入数组长度,再输入数组内数据,每个数据之间用空格隔开,输入的数据都是非负整数
连续输入t行
输出:
每行输出一个示例的先序遍历结果,每个结点之间用空格隔开
输入样例:
3
3 1 2 3
5 1 2 3 0 4
13 1 2 3 4 0 5 6 7 8 0 0 9 10
输出样例:1 2 3
1 2 4 3
1 2 4 7 8 3 5 9 10 6
#include <iostream>
using namespace std;
class Tree {
private:
int len;
int* root;//存储数组
public:
void set(int a[],int n) {
len = n;
root = new int[n];
for (int i = 0; i < n; i++) {
root[i] = a[i];
}
}
void PreOrder(int i) {
if (i < len && root[i] != 0) {
cout << root[i] << " ";//根节点
PreOrder(i * 2 + 1);//左孩子
PreOrder(i * 2 + 2);//右孩子
}
}
};
int main()
{
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int* a = new int[n];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
Tree tree;
tree.set(a, n);
tree.PreOrder(0);
cout << endl;
}
}
二叉树的父子结点
寻炸二叉树的叶子结点及叶子节点的父亲结点。
叶子结点的寻并不困难,但是寻找完的叶子节点后如何返回寻找父亲节点就是一个难题
在这里,我运用了一个队列来对父亲节点进行存储,队列有先进先出的性质,符合题意
题目描述:
给定一颗二叉树的逻辑结构如下图,(先序遍历的结果,空树用字符‘0’表示,例如AB0C00D00),建立该二叉树的二叉链式存储结构。
编写程序输出该树的所有叶子结点和它们的父亲结点
输入:
第一行输入一个整数t,表示有t个二叉树
第二行起,按照题目表示的输入方法,输入每个二叉树的先序遍历,连续输入t行
输出:
第一行按先序遍历,输出第1个示例的叶子节点
第二行输出第1个示例中与叶子相对应的父亲节点
以此类推输出其它示例的结果
输入样例:
3
AB0C00D00
AB00C00
ABCD0000EF000输出样例:
C D
B A
B C
A A
D F
C E
#include <iostream>
#include <string>
#include <queue>
using namespace std;
class BiTreeNode {
public:
char data;
BiTreeNode* LeftChild;
BiTreeNode* RightChild;
BiTreeNode(){LeftChild = NULL,RightChild = NULL;}
};
queue <BiTreeNode*> qu;//用队列来对父亲结点进行保存
BiTreeNode* Q;
class BiTree {
private:
int pos;
int len;
BiTreeNode* Root;
string strTree;
BiTreeNode* CreateTree() {
BiTreeNode* T;
char ch;
ch = strTree[pos++];
if (ch == '0') {
T = NULL;
}
else {
T = new BiTreeNode();
T->data = ch;
T->LeftChild = CreateTree();
T->RightChild = CreateTree();
}
return T;
}
void findleave(BiTreeNode* t) {
if (t->LeftChild) {
Q = t;//寻找父亲结点
findleave(t->LeftChild);
}
if (t->RightChild) {
Q = t;//寻找父亲节点
findleave(t->RightChild);
}
if (!t->LeftChild && !t->RightChild) {
qu.push(Q);//父亲节点进入队列
cout << t->data << " ";
}
}
public:
void CreateTree(string str) {
int pos = 0;
strTree.assign(str);
Root = CreateTree();
}
void findleave() {
findleave(Root);
cout << endl;
while (!qu.empty()) {
cout << qu.front()->data << " ";
qu.pop();
}
cout << endl;
}
};
int main()
{
int t;
cin >> t;
while (t--) {
string str;
cin >> str;
BiTree tree;
tree.CreateTree(str);
tree.findleave();
}
}
二叉树的最大路径
题目描述:
给定一颗二叉树的逻辑结构(先序遍历的结果,空树用字符‘0’表示,例如AB0C00D00),建立该二叉树的二叉链式存储结构
二叉树的每个结点都有一个权值,从根结点到每个叶子结点将形成一条路径,每条路径的权值等于路径上所有结点的权值和。编程求出二叉树的最大路径权值。如下图所示,共有4个叶子即有4条路径,
路径1权值=5 + 4 + 11 + 7 = 27 路径2权值=5 + 4 + 11 + 2 = 22
路径3权值=5 + 8 + 13 = 26 路径4权值=5 + 8 + 4 + 1 = 18
可计算出最大路径权值是27。
该树输入的先序遍历结果为ABCD00E000FG00H0I00,各结点权值为:
A-5,B-4,C-11,D-7,E-2,F-8,G-13,H-4,I-1
输入:
第一行输入一个整数t,表示有t个测试数据
第二行输入一棵二叉树的先序遍历,每个结点用字母表示
第三行先输入n表示二叉树的结点数量,然后输入每个结点的权值,权值顺序与前面结点输入顺序对应,以此类推输入下一棵二叉树。
输出:
每行输出每棵二叉树的最大路径权值,如果最大路径权值有重复,只输出1个
输入样例:
2
AB0C00D00
4 5 3 2 6
ABCD00E000FG00H0I00
9 5 4 11 7 2 8 13 4 1输出样例:
11
27
#include <iostream>
#include <string>
#include <stack>
using namespace std;
stack <int> st;//用栈对叶子节点进行存储,便于后续比较权值大小
class BiTreeNode {
public:
char data;
int weight;
BiTreeNode* LeftChild;
BiTreeNode* RightChild;
BiTreeNode() { LeftChild = NULL, RightChild = NULL; }
};
class BiTree {
private:
int pos1;
int pos2;
string strTree;
int* wei;
BiTreeNode* Root;
BiTreeNode* CreateTree() {
BiTreeNode* T;
char ch;
ch = strTree[pos1++];
if (ch == '0') {
T = NULL;
}
else {
T = new BiTreeNode();
T->data = ch;
T->weight = wei[pos2++];
T->LeftChild = CreateTree();
T->RightChild = CreateTree();
}
return T;
}
void findmax(BiTreeNode* t) {
if (t->LeftChild && t->RightChild) {
t->LeftChild->weight += t->weight;
t->RightChild->weight += t->weight;
}
else if (t->LeftChild) {
t->LeftChild->weight += t->weight;
}
else if (t->RightChild) {
t->RightChild->weight += t->weight;
}
if (t->LeftChild) {
findmax(t->LeftChild);
}
if (t->RightChild) {
findmax(t->RightChild);
}
}
void displaymax(BiTreeNode* t) {
if (t->LeftChild) {
displaymax(t->LeftChild);
}
if (t->RightChild) {
displaymax(t->RightChild);
}
if (!t->LeftChild && !t->RightChild) {
st.push(t->weight);
}
}
public:
void CreateTree(string str,int n,int a[]) {
wei = new int[n];
for (int i = 0; i < n; i++) {
wei[i] = a[i];
}
pos1 = 0;
pos2 = 0;
strTree.assign(str);
Root = CreateTree();
}
void findmax() {
findmax(Root);
}
void displaymax() {
displaymax(Root);
int max = 0;
while (!st.empty()) {
if (st.top() > max) {
max = st.top();
}
st.pop();
}
cout << max << endl;
}
};
int main()
{
int t;
cin >> t;
while (t--) {
string str;
cin >> str;
int n;
cin >> n;
int* a = new int[n];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
BiTree tree;
tree.CreateTree(str, n, a);
tree.findmax();
tree.displaymax();
}
return 0;
}