<数据结构>由SearchTree的遍历序列确定树
XDOJ315. 拓展先序遍历-->二叉树
问题与解答
问题描述
编一个程序,读入用户输入的一串扩展先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的扩展先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入格式
输入包括1行字符串,长度不超过100。
输出格式
输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。每个输出结果占一行。
样例输入
abc##de#g##f###
样例输出
c b e g d f a
样例说明
根据给定的扩展先序遍历序列,建立对应的二叉树,然后对所得的二叉树进行中序遍历输出结果即可。
/*先序遍历转中序遍历*/
/*数组树只能表示完全二叉树*/
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char _val;
struct TreeNode* pleft;
struct TreeNode* pright;
}TreeNode;
TreeNode* CreateTree(char* arr,int *pi)
{
/*4. 递归终止条件*/
if (arr[*pi] == '#')
{
return NULL;
}
else
{
/*1. 递归操作:处理单个节点*/
TreeNode * root = (TreeNode *)malloc (sizeof(TreeNode));
root->_val = arr[*pi] ;
++(*pi);
/*2. 递归式:缩小问题规模*/
root->pleft = CreateTree(arr,pi);
++(*pi);
root->pright = CreateTree(arr,pi);
/*无需 ++(*pi); */
/*3. 返回值*/
return root;
}
}
void InorderTraversal(TreeNode * root)
{
if (root == NULL)
{
return ;
}
InorderTraversal(root->pleft);
printf("%c ",root->_val);
InorderTraversal(root->pright);
}
int main()
{
char arr[100];
scanf("%s",arr);
int i = 0;
TreeNode * root = CreateTree(arr,&i);
InorderTraversal(root);
return 0;
}
题后反思:数组树的不足
- 只有在表示完全二叉树的时候更方便:用数组表示非完全二叉树是所需要的附加操作不足可能比实现二叉链表树更加繁琐。
- 空间有限:数组不能开太大。
- 不方便用遍历操作,基本操作集合还没构建模板,要现场实现。
XDOJ318.先序+中序-->二叉树
问题与解答
问题描述
给定一棵二叉树的先序遍历和中序遍历序列,求其后序遍历序列。
输入格式
输入数据有两行,为两个字符串,其长度n均小于等于26。第一行为先序遍历序列,第二行为中序遍历序列。
二叉树中的结点名称以大写字母表示:A,B,C....最多26个结点。
输出格式
在一行上输出后序遍历序列。
样例输入
ABC
BAC
样例输出
BCA
步骤
1. 先序确定根结点
2. 在中序序列中找到根节点,从而确定左右子树
3. 递归解决
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MaxNum 30
struct TNode;
typedef struct TNode* Position;
typedef Position BT;
struct TNode
{
char Element;
BT LT;
BT RT;
};
BT BuildTree(char *pre, char *in, int n);
void PostOrderTraverse(BT T);
int main()
{
char pre[MaxNum], in[MaxNum];
int n;
BT T;
gets(pre);
gets(in);
n = strlen(pre);
T = BuildTree(pre,in,n);
PostOrderTraverse(T);
return 0;
}
/*输入:先序序列pre、中序序列in、待构建的树节点数n*/
BT BuildTree(char *pre, char *in, int n)
{
Position Parent;
char *p;
int k;
/*4. 终止条件:终止递归,弹栈*/
if(n==1)
{
Parent = (Position)malloc(sizeof(struct TNode));
Parent->Element = *pre;
Parent->LT = NULL;
Parent->RT = NULL;
return Parent;
}
/*1. 递归操作:处理单个节点*/
/*先序确定父节点,中序中找到该节点确定左右子树*/
for(p=in;p<in+n;p++)
if(*p==*pre) break;
k = p-in; //父节点对应下标
Parent = (Position)malloc(sizeof(struct TNode));
Parent->Element = *pre;
Parent->LT = NULL;
Parent->RT = NULL;
/*2. 递归式:对左右子树重复操作,缩小问题范围*/
if(k) //存在左子树
Parent->LT = BuildTree(pre+1, in, k); //左子树节点数为k
if(n-k-1) //存在右子树
Parent->RT = BuildTree(pre+k+1, p+1, n-k-1); //右子树节点数为(n-1)-k
/*3. 返回值*/
return Parent;
}
void PostOrderTraverse(BT T)
{
if(T)
{
PostOrderTraverse(T->LT);
PostOrderTraverse(T->RT);
printf("%c", T->Element);
}
}
题后反思:左右子树赋零
(忽略了子树赋零)
构建树结点:赋值完后需要把左右子树赋零
XDOJ320.层序+中序-->二叉树
问题与解答
问题描述
给定二叉树T(树深度H<=10,深度从1开始,结点个数N<1024,结点编号1~N)的层次遍历序列和中序遍历序列,输出T从左向右叶子结点以及二叉树先序和后序遍历序列。
输入格式
输入共三行:第一行是整数n,表示二叉树中的结点数目;第二行有n个整数,表示该二叉树的层次遍历序列;第三行也是n个整数,表示该二叉树的中序遍历序列。整数间以空格隔开。
输出格式
输出三行,分别是:从左向右的叶子结点,先序遍历序列,后序遍历序列。结点编号用空格隔开。
样例输入
7
3 5 4 2 6 7 1
2 5 3 6 4 7 1
样例输出
2 6 1
3 5 2 4 6 7 1
2 5 6 1 7 4 3
层序确定根节点,中序确定左右子树位置,遍历解决
/*层序+中序 确定树*/
/*输出:叶子结点*/
/*输出:先序、后序*/
#include<stdio.h>
#include<stdlib.h>
struct TNode;
typedef struct TNode* Position;
typedef Position BT;
struct TNode
{
int Element;
BT LT;
BT RT;
};
BT BuildTree(int *level, int *in, int levelL, int levelR, int inL, int inR);
void PreOrderTraverse(BT T);
void PostOrderTraverse(BT T);
void LeafNode(BT T); //打印叶子结点
int main()
{
int i,n;
BT T;
scanf("%d",&n);
int level[n], in[n];
for(i=0; i<n; i++)
scanf("%d", &level[i]);
for(i=0; i<n; i++)
scanf("%d", &in[i]);
T = BuildTree(level, in, 0, n-1, 0, n-1);
LeafNode(T);
printf("\n");
PreOrderTraverse(T);
printf("\n");
PostOrderTraverse(T);
printf("\n");
// InOrderTraverse(T);
// printf("\n");
return 0;
}
//当前二叉树的 层序区间[levelL,levelR], 中序区间[inL,inR]
BT BuildTree(int *level, int *in, int levelL, int levelR, int inL, int inR)
{
/*4. 终止条件: 子树无结点*/
if(inL > inR)
{
return NULL;
}
int i,j,flag=0;
Position Parent;
/*1. 递归操作:处理单个节点,即父节点Parent*/
Parent = (Position)malloc(sizeof(TNode));
Parent->LT = NULL;
Parent->RT = NULL; //不要忘记哦~~
//找到当前层序序列中 第一个 出现在当前中序序列的元素 赋值
for(i = levelL; i <= levelR; i++){
for(j = inL; j <= inR; j++){
if(level[i] == in[j]){
flag = 1;
break;
}
}
if(flag == 1) break;
}
Parent->Element = level[i];
/*2. 递归式:确定左右子树,缩小问题范围*/
/*[levelL, levelR]区间不断后移*/
Parent->LT = BuildTree(level, in, levelL+1, levelR, inL, j-1); //层序序列指针+1,左子树区间[inL, j-1]
Parent->RT = BuildTree(level, in, levelL+2, levelR, j+1, inR); //层序序列指针+2,右子树区间[j+2, inR]
//由于左子树的根节点为level[levelL+1],所以在确定右子树时跳过左子树的根节点,故+2。
//【关于这点的解读详见评论区】
/*3. 返回值*/
return Parent; //不要忘记哦~~
}
void LeafNode(BT T)
{
if(T){
if (T->LT == NULL && T->RT == NULL) {
printf("%d ", T->Element);
}
else {
LeafNode(T->LT);
LeafNode(T->RT);
}
}
}
void PreOrderTraverse(BT T)
{
if(T)
{
printf("%d ", T->Element);
PreOrderTraverse(T->LT);
PreOrderTraverse(T->RT);
}
}
void PostOrderTraverse(BT T)
{
if(T)
{
PostOrderTraverse(T->LT);
PostOrderTraverse(T->RT);
printf("%d ", T->Element);
}
}
void InOrderTraverse(BT T)
{
if(T)
{
InOrderTraverse(T->LT);
printf("%d ", T->Element);
InOrderTraverse(T->RT);
}
}
总结
- 都需要中序: X+中序
- X确定结点,中序确定左右子树位置
- 递归求解