一、二叉树
- 节点的表示
通常使用结构体表示。
struct Node{
Node * lchild; //左子节点
Node * rchild; //右子节点
int c; //编号
}Tree[1005];
- 二叉树的三种遍历方式
前序、中序、后序的遍历方式如下所示。
void preOrder(Node *T) { //后序遍历
if(T->lchild != NULL) postOrder(T->lchild);
if(T->rchild != NULL) postOrder(T->rchild);
printf("%d ",T -> c); //将结点中的字符放入正在保存的字符串中
}
void inOrder(Node *T) { //中序遍历
if(T->lchild != NULL) postOrder(T->lchild);
printf("%d ",T -> c);
if(T->rchild != NULL) postOrder(T->rchild);
}
void postOrder(Node *T) { //后序遍历
if(T->lchild != NULL) postOrder(T->lchild);
if(T->rchild != NULL) postOrder(T->rchild);
printf("%d ",T -> c); //将结点中的字符放入正在保存的字符串中
}
- 根据前序/后序和中序得到树的后序/前序(待整理)
题目链接:HDU 1710 Binary Tree Traversals
题目是给出了前序遍历和中序遍历,求后序遍历。思路就是首先根据中序遍历序列找到根节点,在前序遍历中划分出左子树和右子树并进行递归,最后将根节点放入vector中存储。
AC代码如下,详见注释:
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
//题目是给出了前序遍历和中序遍历,求后序遍历
//HDU Accepted 1710 109MS 1804K 748 B C++
const int maxn = 1005;
int pre[maxn], mi[maxn];
int pid; //记录前序遍历中根节点的位置
vector<int> v;
void pos(int l, int r) {
int i = l;
while(mi[i] != pre[pid])
i++; //找到中序中的根节点位置
if(i > l) {
pid++; //前序遍历中根节点的位置
pos(l, i-1);
}
if(i < r) {
pid++; //前序遍历中根节点的位置
pos(i+1, r);
}
// printf("%d---", mi[i]);
v.push_back(mi[i]);
}
int main() {
int n;
while(cin >> n) {
pid = 0;
for(int i=0; i<n; i++)
cin>>pre[i];
for(int i=0; i<n; i++)
cin>>mi[i];
pos(0, n-1);
for(int i=0; i<n; i++)
printf("%d%c", v[i], i==n-1?'\n':' ');
v.clear();
}
return 0;
}
二、二叉排序树
二叉排序树是一种特殊的二叉树。
树
上
的
任
意
一
个
结
点
,
其
数
值
必
大
于
等
于
其
左
子
树
上
任
意
结
点
数
值
,
\color{#FF0000}{树上的任意一个结点,其数值必大于等于其左子树上任意结点数值,}
树上的任意一个结点,其数值必大于等于其左子树上任意结点数值,
必
小
于
等
于
其
右
子
树
上
任
意
结
点
的
数
值
。
\color{#FF0000}{必小于等于其右子树上任意结点的数值。}
必小于等于其右子树上任意结点的数值。
给出数字序列建一棵二叉排序树,若数字相同但数字出现的顺序不同,则各个数字插入的顺序不同,所得到的二叉排序树的形态也很可能不同。但是所有的二叉排序树都有一个共同的特点:若对二叉排序树进行中序遍历,那么其遍历结果必然是一个递增序列。即通过建立二叉排序树就能对原无序序列进行排序,并实现动态维护。
我们可以通过一道 题目(HDU 3791),对二叉排序树的建立、二叉树的遍历等知识点进行实践。
#include <iostream>
#include <string.h>
using namespace std;
//HDU Accepted 3791 15MS 1404K 1783 B G++
//题意:判断两序列是否为同一二叉搜索树序列
//我们对输入的数字序列构建二叉排序树,并对它们进行后序和中序的遍历,
//依次比较两次遍历结果是否相同,若相同则说明两棵二叉排序树相同,否则不同。
string s, tmp;
int loc = 0;
int size1, size2;
int *size; //当前正在保存字符串中字符个数
char ans1[25];
char ans2[25];
char *ans; //当前正在保存字符串
struct Node{
Node * lchild;
Node * rchild;
int c;
}Tree[1005];
Node* create() {
Tree[loc].lchild = Tree[loc].rchild = NULL;
return &Tree[loc++];
}
void postOrder(Node *T) { //后序遍历
if(T->lchild != NULL) postOrder(T->lchild);
if(T->rchild != NULL) postOrder(T->rchild);
ans[(*size)++] = T->c + '0'; //将结点中的字符放入正在保存的字符串中
}
void inOrder(Node *T) { //中序遍历
if(T->lchild != NULL) postOrder(T->lchild);
ans[(*size)++] = T->c + '0';
if(T->rchild != NULL) postOrder(T->rchild);
}
Node *Insert(Node *T, int x) { //插入二叉树
if(T == NULL) {
T = create();
T->c = x;
return T;
}
else if(x < T->c) { //小于根节点 ,插入到右子树
T->lchild = Insert(T->lchild, x);
}
else if(x > T->c) { //大于,插入到右子树
T->rchild = Insert(T->rchild, x);
}
return T;
}
int main() {
int n;
while(cin>>n && n) {
loc = 0;
cin>>s;
Node *T = NULL;
for(int i=0; i<s.length(); i++) T = Insert(T, s[i] - '0');
size1 = 0; //保存在第一个字符串中的字符初始化为0
ans = ans1; //将正在保存字符串设定为第一个字符串
size = &size1; //将正在保存字符串中的字符个数指针指向size1
postOrder(T);
inOrder(T);
ans1[size1] = 0; //向第一个字符串的最后一个字符后添加空字符,方便使用字符串函数
while(n--) {
cin>>tmp;
Node *T2 = NULL;
for(int i=0; tmp[i] != 0; i++) {
T2 = Insert(T2, tmp[i] - '0');
}
size2 = 0;
ans = ans2;
size = &size2; //正在保存字符串中字符数量指针指向size2
postOrder(T2);
inOrder(T2);
ans2[size2] = 0;
// cout<<"ans1: "<<ans1<<endl;
// cout<<"ans2: "<<ans2<<endl;
if(strcmp(ans1, ans2) == 0)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
return 0;
}