ACM 树

一、二叉树

  1. 节点的表示
    通常使用结构体表示。
struct Node{
	Node * lchild;  //左子节点
	Node * rchild;  //右子节点
	int c;  //编号
}Tree[1005];
  1. 二叉树的三种遍历方式
    前序、中序、后序的遍历方式如下所示。
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);  //将结点中的字符放入正在保存的字符串中
}
  1. 根据前序/后序和中序得到树的后序/前序(待整理)
    题目链接: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值