前言
说是树,其实大部分都是二叉树,更多的还是二叉排序树(也叫做二叉查找树 BinarySearchTree),树的数据结构一般都要自己实现。下面给出部分自己的写法(CPP),仅供参考。注意nullptr要在C++11的标准以上,有可能xdoj编译错误,改成NULL就行。再一次验证了xdoj的复古风格。
xdoj例题的代码都是CPP,都不是裸体代码或者屎山,放心食用。
二叉树的定义以及操作集
大神可以跳过,这里只有常见的一些函数,前序中序后序层次遍历等。
定义:
/*-----------------二叉链表实现----------------*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#define TElemType int
typedef struct BiTNode{
TElemType data;
struct BiTNode* lchild,*rchild;
}BiTNode,*BiTree;
//这里是下面Visit函数的一个例子
int PrintElement(TElemType e){
printf("%c",e);
return 1;
}
//遍历部分 int(*Visit)表示 指向函数的指针,传递一个函数
//递归版本前序遍历,自己写的,比较垃圾,LDR,LRD同理
void PreOrder(BiTree T){
if(T==nullptr){
return;
}else{
cout<<T->data;//Visit();
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//递归版本中序遍历,自己写的
void InOrder(BiTree T){
if(T==nullptr){
return;
}else{
InOrder(T->lchild);
cout<<T->data;//Visit();
InOrder(T->rchild);
}
}
//递归版本后序遍历,自己写的
void PostOrder(BiTree T){
if(T==nullptr){
return;
}else{
PostOrder(T->lchild);
PostOrder(T->rchild);
cout<<T->data;
}
}
//非递归层次遍历
int LevelTraverseNonR(BiTree T,int(*Visit)(TElemType e)){
//队列实现 queue 总体是先入队,p=Q的头并访问,p左子树入队,p右子树入队,再循环
BiTree p;
queue<BiTree>Q;
Q.push(T);
while(!Q.empty()){
p=Q.front();
if(!Visit(p->data)){
return 0;//ERROR
}
Q.pop();
if(p->lchild!=nullptr){
Q.push(p->lchild);
}
if(p->rchild!=nullptr){
Q.push(p->rchild);
}
}
return 1;//OK
}
//先序次序创建二叉树
BiTree CreateBiTree(){
char ch;
BiTree T;
scanf("%c",&ch);
if(ch==' '){//用空格表示空树
T=NULL;
}else{
if(!(T=(BiTree)malloc(sizeof(BiTNode)))){
exit(0);
}
T->data=ch;//生成根结点
T->lchild=CreateBiTree();
T->rchild=CreateBiTree();
}
return T;
}
例题:
XDOJ0273 统计二叉树中的叶子结点数
输入形式类似完全二叉树,所以可以利用数组存储。而且下标有一定规律。
//xdoj0273.cpp
#include<cstdio>
using namespace std;
char input[100];
int main(){
char ch;
int count=0,len=1;
while(scanf("%c",&ch) && ch!='#'){
input[len++]=ch;
}
for(int i=1;i<len;++i){
if(input[i]=='@'){
continue;
}else{
if(i*2>=len){
printf("%c ",input[i]);
count++;
}else{
if(input[i*2]=='@' && input[i*2+1]=='@'){
printf("%c ",input[i]);
count++;
}
}
}
}
printf("\n%d",count);
return 0;
}
XDOJ0314 完全二叉树的子树
完全二叉树,可以利用数组来做。这个子树有多少结点可以数学推导。而且子树的结点数与层数有关系。
大概有三种情况。
(1)n结点和m结点在同一子树
(2)n在下方
(3)n在右边
具体推导可以参考下面的图片。
//xdoj0314.cpp
#include<cstdio>
#include<cmath>
using namespace std;
void CountNodes(int m,int n){
int delta=(int)log2(n)-(int)log2(m);
int k=1<<delta;
//俩个层数之差是k
if(n>k*m+k-1){
//说明n结点不在这个子树但是在同一层
printf("%d\n",2*k-1);
}else if(n<m*k){
printf("%d\n",k-1);
}else{
//n和m都在同一个树
printf("%d\n",k+n%k);
}
return;
}
int main(){
int n,m;
while(scanf("%d%d",&m,&n) && n+m!=0){
CountNodes(m,n);
}
return 0;
}
XDOJ0315 二叉树扩展先序遍历转中序遍历
//xdoj0315.cpp
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
using namespace std;
typedef struct BTNode{
char data;
struct BTNode* lchild;
struct BTNode* rchild;
}BTNode,*BiTree;
BiTree PreOrderCreateBT(){
char ch;
BiTree T;
scanf("%c",&ch);
if(ch=='#'){//用空格表示空树
T=NULL;
}else{
if(!(T=(BiTree)malloc(sizeof(BTNode)))){
exit(0);
}
T->data=ch;//生成根结点
T->lchild=PreOrderCreateBT();
T->rchild=PreOrderCreateBT();
}
return T;
}
void InOrder(BiTree T){
//LDR
if(T==NULL){
return;
}else{
InOrder(T->lchild);
cout<<T->data<<' ';
InOrder(T->rchild);
}
}
int main(){
BiTree T;
T=PreOrderCreateBT();
InOrder(T);
return 0;
}
XDOJ0316 完全二叉树的公共父结点
完全二叉树,编号很特殊,左右子树其实是俩倍根结点和俩倍根结点+1。
//xdoj0316.cpp
#include<cstdio>
using namespace std;
//观察易得左右子树除2就是根结点的值
int main(){
int n,m;//沙比题目也不说清楚00是什么,纯属挠谈
while(scanf("%d%d",&n,&m) && n+m!=0){
while(n!=m){
n>m?n/=2:m/=2;
}
printf("%d\n",n);
}
return 0;
}
XDOJ0317 输出完全二叉树的某一层
//xdoj0317.cpp
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
int Node[100];//完全二叉树一定是先有左孩子的,要么满要么从左到右连续
void InitNode(){
for(int i=0;i<100;++i){
Node[i]=0;//0表示空
}
}
int Pow(int x){//计算2的x次方
return 1<<x;//左移x次,相当于2的x次方
}
//输出某一层的结点 如果有的话,一定是[2^(d-1)-1,2^d -1)这个范围 注意右边不取
void PrintLevel(int n,int d){
//记得判定是否大于了树的深度
if(d > (int)log2(n)+1){
printf("EMPTY");
return;
}
int start=Pow(d-1)-1;
int end=Pow(d)-1;
for(int i=start;i<end;++i){
if(i==start && Node[i]==0){
//开头就是空,说明这一层都是空
printf("EMPTY");
return;
}
if(Node[i]!=0){
printf("%d ",Node[i]);
}else{
return;
}
}
return;
}
int main(){
int n,d;
while(scanf("%d",&n) && n!=0){
InitNode();
for(int i=0;i<n;++i){
scanf("%d",&Node[i]);
}
scanf("%d",&d);//depth
PrintLevel(n,d);
printf("\n");
}
return 0;
}
二叉排序树/二叉查找树/BinarySearchTree
定义:
一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
数据结构和操作集:
还是用的CPP
#define TElemType int
typedef struct BiTNode{
TElemType data;
struct BiTNode* lchild,*rchild;
}BiTNode,*BiTree;
//BinarySearchTree,结点结构体定义与二叉树相同
//定义:左子树所有结点小于根,右子树所有结点大于根,子树仍符合上述定义(递归)
//MakeEmpty,初始化
BiTree MakeEmpty(BiTree T){
if(T!=nullptr){
MakeEmpty(T->lchild);
MakeEmpty(T->rchild);
free(T);
}
return nullptr;
}
//Find查找 递归的方法
BiTree Find(TElemType x,BiTree T){
if(T==nullptr){
return nullptr;
}
if(x < T->data){
return Find(x,T->lchild);
}else if(x > T->data){
return Find(x,T->rchild);
}else{
return T;
}
}
//FindMin查找最小值 递归版本
BiTree FindMin(BiTree T){
if(T==nullptr){//先写终止条件
return nullptr;
}else if(T->lchild==nullptr){
return T;
}else{
return FindMin(T->lchild);
}
}
//FindMax查找最大值 非递归版本
BiTree FindMax(BiTree T){
if(T!=nullptr){
while(T->rchild!=nullptr){
T=T->rchild;
}
}
return T;
}
//在二叉查找树中插入x结点
BiTree Insert(TElemType x,BiTree T){
if(T=nullptr){
//创建一个树
T=(BiTree)malloc(sizeof(BiTNode));
if(T==nullptr){
printf("Out of Space");//溢出
}else{
T->data=x;
T->lchild=nullptr;
T->rchild=nullptr;
}
}else{
if(x < T->data){
T->lchild=Insert(x,T->lchild);//这里已经实现插入了
}else if(x > T->data){
T->rchild=Insert(x,T->rchild);//这里已经实现插入了
}
}
return T;//这一行非常重要
}
//Delete删除操作 递归 lazy deletion
BiTree Delete(TElemType x,BiTree T){
BiTree TmpCell;
if(T==nullptr){
printf("ERROR: Element not found");
}else if(x < T->data){
T->lchild=Delete(x, T->lchild);
}else if(x > T->data){
T->rchild=Delete(x, T->rchild);
}else if(T->lchild && T->rchild){//找到要删除的元素了,不过是有俩个子树的情况
//找右子树中的最小值
TmpCell=FindMin(T->rchild);
T->data=TmpCell->data;
T->rchild=Delete(T->data,T->rchild);//此时T->data已经赋值成右子树的最小值了,接下来需要在右子树删除这个结点(因为多余了)
}else{
//0个子树,或者1个子树
TmpCell = T;
if(T->lchild==nullptr){//这里同时也处理了0个子树的情况
T=T->rchild;
}else if(T->rchild==nullptr){
T=T->lchild;
}
free(TmpCell);
}
return T;
}
例题:
XDOJ0259 二叉排序树运算
//xdoj0259.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
BiTree CreateBSTree(BiTree T,int x){
if(T==NULL){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}else{
if(x < T->data){
T->lchild=CreateBSTree(T->lchild,x);
}else if(x > T->data){
T->rchild=CreateBSTree(T->rchild,x);
}
}
return T;
}
void PreOrder(BiTree T){
if(T==NULL)return;
cout<<T->data<<" ";
PreOrder(T->lchild);
PreOrder(T->rchild);
return;
}
void PostOrder(BiTree T){
if(T==NULL)return;
PostOrder(T->lchild);
PostOrder(T->rchild);
cout<<T->data<<" ";
return;
}
int main(){
BiTree T=NULL;
int n,input[100];
cin>>n;
for(int i=0;i<n;++i){
cin>>input[i];
}
for(int i=0;i<n;++i){
T=CreateBSTree(T,input[i]);
}
PreOrder(T);
cout<<endl;
PostOrder(T);
return 0;
}
XDOJ0271 中序遍历二叉排序树(同XDOJ0274)
//xdoj0271.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
BiTree CreateBSTree(BiTree T,int x){
if(T==NULL){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}else{
if(x>T->data){
T->rchild=CreateBSTree(T->rchild,x);
}else if(x< T->data){
T->lchild=CreateBSTree(T->lchild,x);
}
}
return T;
}
void InOrder(BiTree T){
//LDR中序遍历
if(T==NULL){
return;
}else{
InOrder(T->lchild);
cout<<T->data<<' ';
InOrder(T->rchild);
}
}
int main(){
BiTree T=NULL;
int n,t;
cin>>n;
for(int i=0;i<n;++i){
cin>>t;
T=CreateBSTree(T,t);
}
InOrder(T);
return 0;
}
XDOJ0329 相同二叉排序树
xdoj非要加个最后一行是0,最后一个测试样例是多次输入n然后多次判断,纯属啥比
//xdoj0329.cpp
#include<cstdio>
#include<cstdlib>
using namespace std;
int pos=0;//计数器
typedef struct BiTNode{
char data;//因题而异
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
BiTree CreateBSTree(BiTree T,char x){
if(T==NULL){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}else{
if(x>T->data){
T->rchild=CreateBSTree(T->rchild,x);
}else if(x< T->data){
T->lchild=CreateBSTree(T->lchild,x);
}
}
return T;
}
//将T前序遍历的结果存储到数组a
void PreOrder(BiTree T,char a[]){
if(T==NULL){
return;
}else{
a[pos++]=T->data;
PreOrder(T->lchild,a);
PreOrder(T->rchild,a);
}
return;
}
//将T中序遍历的结果存储到数组a
void InOrder(BiTree T,char a[]){
if(T==NULL){
return;
}else{
InOrder(T->lchild,a);
a[pos++]=T->data;
InOrder(T->rchild,a);
}
return;
}
void CompareTree(char pre1[],char pre2[],char in1[],char in2[],int length){
for(int i=0;i<length;++i){
if(pre1[i]!=pre2[i]){
printf("NO\n");
return;
}
}
for(int i=0;i<length;++i){
if(in1[i]!=in2[i]){
printf("NO\n");
return;
}
}
printf("YES\n");
return;
}
void Fun(int n){
BiTree T1=NULL;
int i,length;
char str1[11];//输入的字符串
char pre1[10],pre2[10],in1[10],in2[10];//最终对比的前序和中序结果
scanf("%s",str1);
for(i=0;str1[i]!='\0';++i){
T1=CreateBSTree(T1,str1[i]);
}
PreOrder(T1,pre1);
pos=0;
InOrder(T1,in1);
pos=0;
//此时i为str1的长度
length=i;
for(int j=0;j<n;++j){
char str2[11];//避免循环过后仍然存在值
BiTree T2=NULL;//避免循环过后仍然存在树
scanf("%s",str2);
for(i=0;i<length;++i){
T2=CreateBSTree(T2,str2[i]);
}
PreOrder(T2,pre2);
pos=0;
InOrder(T2,in2);
pos=0;
CompareTree(pre1,pre2,in1,in2,length);
}
}
int main(){
int n;
//xdoj非要加个最后一行是0,最后一个测试样例是多次输入n判断,纯属啥比
while(scanf("%d",&n) && n!=0){
Fun(n);
}
return 0;
}
XDOJ0330 二叉排序树之父结点
//xdoj0330.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
BiTree CreateBSTree(BiTree T,int x){
if(T==NULL){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}else{
if(x>T->data){
T->rchild=CreateBSTree(T->rchild,x);
}else if(x< T->data){
T->lchild=CreateBSTree(T->lchild,x);
}
}
return T;
}
void FindFater(BiTree T,int x){
//在二叉排序树T中找到x的父亲
if(T==NULL){
return;
}else{
if(x==T->data){
//是根结点,直接输出-1
cout<<"-1"<<endl;
}else if(x > T->data){
if(x==T->rchild->data){
cout<<T->data<<endl;
}else{
FindFater(T->rchild,x);
}
}else if(x < T->data){
if(x==T->lchild->data){
cout<<T->data<<endl;
}else{
FindFater(T->lchild,x);
}
}
}
return;
}
int main(){
BiTree T=NULL;
int n,t;
cin>>n;
for(int i=0;i<n;++i){
cin>>t;
T=CreateBSTree(T,t);
FindFater(T,t);
}
return 0;
}
XDOJ0331 二叉排序树的遍历
//xdoj0331.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
BiTree CreateBSTree(BiTree T,int x){
if(T==NULL){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}else{
if(x < T->data){
T->lchild=CreateBSTree(T->lchild,x);
}else if(x > T->data){
T->rchild=CreateBSTree(T->rchild,x);
}
}
return T;
}
void PreOrder(BiTree T){
if(T==NULL){
return;
}else{
cout<<T->data<<' ';
PreOrder(T->lchild);
PreOrder(T->rchild);
}
return;
}
void InOrder(BiTree T){
if(T==NULL){
return;
}else{
InOrder(T->lchild);
cout<<T->data<<' ';
InOrder(T->rchild);
}
return;
}
void PostOrder(BiTree T){
if(T==NULL){
return;
}else{
PostOrder(T->lchild);
PostOrder(T->rchild);
cout<<T->data<<' ';
}
return;
}
int main(){
BiTree T=NULL;
int n,t;
cin>>n;
for(int i=0;i<n;++i){
cin>>t;
T=CreateBSTree(T,t);
}
PreOrder(T);
cout<<endl;
InOrder(T);
cout<<endl;
PostOrder(T);
return 0;
}
XDOJ0332 二叉排序树的判定
//xdoj0332.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
int Matrix[1000][3];//直接矩阵存储,不需要非线性结构了
int DFS(int root,int rootval){
//从root开始DFS
int tmp;
if(root==0){
//终止条件,也就是遇到空树
return -1;//设置一个标志,表示该根结点下方无孩子
}else{
tmp=DFS(Matrix[root][1],Matrix[Matrix[root][1]][0]);
if(tmp!=-1 && tmp >= rootval){
//如果左孩子的结点大于等于根,说明不是合法的二叉排序树
cout<<"false";
exit(0);//直接退出
}
tmp=DFS(Matrix[root][2],Matrix[Matrix[root][2]][0]);
if(tmp!=-1 && tmp <= rootval){
//如果右孩子的结点小于等于根,说明不是合法的二叉排序树
cout<<"false";
exit(0);
}
}
if(tmp==-1){
//说明该根的左右子树都是空,返回的应该是根的值
tmp=rootval;
}
return tmp;
}
int main(){
//实际上是DFS深度优先搜索,左子树搜一遍,没有大于根的就回头,再根再右子树
int n,root;
for(int i=0;i<3;++i){
Matrix[0][i]=0;//第0行不存储
}
cin>>n>>root;
for(int i=1;i<=n;++i){
for(int j=0;j<3;++j){
cin>>Matrix[i][j];//行从1数起,避免混淆
}
}
DFS(root,Matrix[root][0]);
cout<<"true";
return 0;
}
俩种遍历结果确定一颗二叉树的方法
前序遍历和中序遍历可以唯一确定一颗二叉树
后序遍历和中序遍历可以唯一确定一颗二叉树
层次遍历和中序遍历可以唯一确定一颗二叉树
一般都是递归的思路来确定树的,先确定根结点,再由中序遍历LDR的特殊性,根结点左边的序列肯定是左子树,根结点右边的序列肯定是右子树。详见下面三种情况的例题。
根据前序遍历和中序遍历确定二叉树
XDOJ0318 二叉树遍历
主要难点在于如何根据前序遍历和中序遍历结果确定一颗二叉树;
其实一样的,在DLR(前序遍历)结果中按顺序来,再从LDR中挑选,LDR中的元素由于特殊性质,该元素左边的子序列一定是该结点的左子树,右边序列一定是该元素的右子树,以此类推,可以用递归实现。
下面给出一种递归的思路确定二叉树:
(1)从头按顺序取DLR数组没取过的一个结点,再从LDR数组里面找到这个点,以这个点为分隔
(2)LDR的左边部分先遍历
(3)LDR的右边部分再遍历
(4)左右遍历部分仍然符合上述规则
//xdoj0318.cpp
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef struct BiTNode{
char data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
char DLR[27],LDR[27];
//插入x到T中,T传引用,避免传值导致返回时T实际上没有改变
void InsertTNode(BiTree& T,char x){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}
int FindRoot(int n,int start,int end){
//在俩个遍历结果中 找到LDR根结点的位置
int flag=0,i,j;
for(i=0;i<n;++i){
for(j=start;j<=end;++j){
if(LDR[j]==DLR[i]){
flag=1;
break;
}
}
if(flag){
break;
}
}
return j;//返回LDR的索引j
}
BiTree CreateBiTree(BiTree T,int n,int start,int end){
//下面是终止条件 start和end都是LDR的索引
if(start>end){
//这种情况,明显不对头,直接返回
return T;//会有这种情况,是下面递归的锅,可以先筛掉
}else if(start==end){
//说明LDR子数组只剩一个,直接插入结点 然后返回就行了
InsertTNode(T,LDR[start]);
return T;
}
//这里是找ROOT结点用于插入到树中 先遍历LEVEL,再从LDR子数组中找
int j=FindRoot(n,start,end);
InsertTNode(T,LDR[j]);
T->lchild=CreateBiTree(T->lchild,n,start,j-1);
T->rchild=CreateBiTree(T->rchild,n,j+1,end);
return T;
}
void PostOrder(BiTree T){
if(T==NULL){
return;
}else{
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%c",T->data);
}
}
int main(){
BiTree T;
char ch;
int i=0;
while(scanf("%c",&ch) && ch!='\n'){
DLR[i++]=ch;
}
gets(LDR);//???没懂为什么这里改成gets过了
T=CreateBiTree(T,i,0,i-1);
PostOrder(T);
return 0;
}
XDOJ0319 将满二叉树转换为求和树
主要难点在于如何根据前序遍历和中序遍历结果确定一颗二叉树;
其实一样的,在DLR(前序遍历)结果中按顺序来,再从LDR中挑选,LDR中的元素由于特殊性质,该元素左边的子序列一定是该结点的左子树,右边序列一定是该元素的右子树,以此类推,可以用递归实现。
下面给出一种递归的思路确定二叉树:
(1)从头按顺序取DLR数组没取过的一个结点,再从LDR数组里面找到这个点,以这个点为分隔
(2)LDR的左边部分先遍历
(3)LDR的右边部分再遍历
(4)左右遍历部分仍然符合上述规则
求和部分也是递归思路
(1)终止条件是左右子树是空(注意是满二叉树,没孩子一定是没有左右孩子的)
(2)否则计算左子树的和
(3)再计算右子树的和
(4)左右子树求和部分仍然符合上述规则
//xdoj0319.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
int DLR[100],LDR[100];
//插入x到T中,T传引用,避免传值导致返回时T实际上没有改变
void InsertTNode(BiTree& T,int x){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}
int FindRoot(int n,int start,int end){
//在俩个遍历结果中 找到LDR根结点的位置
int flag=0,i,j;
for(i=0;i<n;++i){
for(j=start;j<=end;++j){
if(LDR[j]==DLR[i]){
flag=1;
break;
}
}
if(flag){
break;
}
}
return j;//返回LDR的索引j
}
BiTree CreateBiTree(BiTree T,int n,int start,int end){
//下面是终止条件 start和end都是LDR的索引
if(start>end){
//这种情况,明显不对头,直接返回
return T;//会有这种情况,是下面递归的锅,可以先筛掉
}else if(start==end){
//说明LDR子数组只剩一个,直接插入结点 然后返回就行了
InsertTNode(T,LDR[start]);
return T;
}
//这里是找ROOT结点用于插入到树中 先遍历LEVEL,再从LDR子数组中找
int j=FindRoot(n,start,end);
InsertTNode(T,LDR[j]);
T->lchild=CreateBiTree(T->lchild,n,start,j-1);
T->rchild=CreateBiTree(T->rchild,n,j+1,end);
return T;
}
int SumTree(BiTree& T){
//返回值是根结点的值,这样利于递归
if(T->lchild==NULL && T->rchild==NULL){
//满二叉树,不用考虑只有左孩子或者右孩子的情况
int root=T->data;
T->data=0;
return root;
}else{
//相当于把结果存到边上
int l=SumTree(T->lchild);
int r=SumTree(T->rchild);
int root=T->data;
//因为相当于结果存在边上,所以左右结点还要加一次
T->data=l + r + T->lchild->data + T->rchild->data;
return root;
}
}
void PostOrder(BiTree T){
if(T==NULL){
return;
}else{
PostOrder(T->lchild);
cout<<T->data<<" ";
PostOrder(T->rchild);
}
return;
}
int main(){
BiTree T=NULL;
int n;
//input部分
cin>>n;
for(int i=0;i<n;++i){
cin>>DLR[i];
}
for(int i=0;i<n;++i){
cin>>LDR[i];
}
T=CreateBiTree(T,n,0,n-1);
SumTree(T);
PostOrder(T);
return 0;
}
根据后序遍历和中序遍历确定二叉树
根据层次遍历和中序遍历确定二叉树
XDOJ0320 二叉树的不同形态
这题梗概:给你层次遍历和中序遍历,让你确定一棵树,再输出树的叶子结点和前序遍历结果、后序遍历结果。
主要矛盾:如何通过层次遍历和中序遍历确定一颗二叉树?
要先明白,LDR数组里面,随便取一个元素,比如下图的A,左边子数组是DBFE,右边子数组是GCHI,因为是中序遍历,所以左边DBFE是左子树,右边GCHI是右子树。以此类推。
下面给出一种递归的思路:
(1)从头按顺序取LEVEL数组的一个没取过的结点,再从LDR数组里面找到这个点,以这个点为分隔
(2)左边部分先遍历
(3)右边部分再遍历
(4)左右遍历部分仍然符合上述规则
比如下图:
(1)LEVEL中找到A,LDR[0,8]中找到A,左边是[0,3]右边是[4,8]
(2)LEVEL中找到B,LDR[0,3]中找到B,左边是[0,0]右边是[2,3]
(3)LEVEL中找到D,LDR[0,0]中找到D,退栈
(4)LEVEL中找到E,LDR[2,3]中找到E,左边是[2,2]右边为空
(5)LEVEL中找到F,LDR[2,2]中找到F,左边是空,右边是空,退栈
(6)LEVEL中找到G,LDR[4,8]中找到G,左边是空,右边是[6,8]
…依次类推
//xdoj0320.cpp
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode,*BiTree;
int LEVEL[100],LDR[100];
//插入x到T中,T传引用,避免传值导致返回时T实际上没有改变
void InsertTNode(BiTree& T,int x){
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->lchild=NULL;
T->rchild=NULL;
}
int FindRoot(int n,int start,int end){
int flag=0,i,j;
for(i=0;i<n;++i){
for(j=start;j<=end;++j){
if(LDR[j]==LEVEL[i]){
flag=1;
break;
}
}
if(flag){
break;
}
}
return j;
}
BiTree CreateBiTree(BiTree T,int n,int start,int end){
//下面是终止条件 start和end都是LDR的索引
if(start>end){
//这种情况,明显不对头,直接返回
return T;//会有这种情况,是下面递归的锅,可以先筛掉
}else if(start==end){
//说明LDR子数组只剩一个,直接插入结点 然后返回就行了
InsertTNode(T,LDR[start]);
//这里输出的是叶子结点
//因为此时start已经等于end,说明这里直接插入一个结点并且往后不会有结点是他的孩子
cout<<T->data<<" ";
return T;
}
//这里是找ROOT结点用于插入到树中 先遍历LEVEL,再从LDR子数组中找
int j=FindRoot(n,start,end);
InsertTNode(T,LDR[j]);
T->lchild=CreateBiTree(T->lchild,n,start,j-1);
T->rchild=CreateBiTree(T->rchild,n,j+1,end);
return T;
}
void PreOrder(BiTree T){
if(T==NULL){
return;
}else{
cout<<T->data<<" ";
PreOrder(T->lchild);
PreOrder(T->rchild);
}
return;
}
void PostOrder(BiTree T){
if(T==NULL){
return;
}else{
PostOrder(T->lchild);
PostOrder(T->rchild);
cout<<T->data<<" ";
}
return;
}
int main(){
BiTree T=NULL;
int n;
cin>>n;
for(int i=0;i<n;++i){
cin>>LEVEL[i];
}
for(int i=0;i<n;++i){
cin>>LDR[i];
}
T=CreateBiTree(T,n,0,n-1);
cout<<endl;
PreOrder(T);
cout<<endl;
PostOrder(T);
return 0;
}
哈夫曼树
XDOJ0261 哈夫曼树
没用到树,直接数组
//xdoj0261.cpp
#include<iostream>
#include<algorithm>
using namespace std;
int main(){//4 5 2 10 8
int n,sum=0;
int a[30];
cin>>n;
for(int i=0;i<n;++i){
cin>>a[i];
}
sort(a,a+n);
for(int i=1;i<n;++i){
a[i]=a[i-1]+a[i];
sum+=a[i];
sort(a+i-1,a+n);//重新排序
}
cout<<sum;
return 0;
}