トピック
リトルバレンタインは二分木で遊ぶのがとても好きでした。彼女のお気に入りのゲームは、ノードに大文字を使用してランダムに見える二分木を構築することでした。
これは彼女の作品の1つの例です:
D
/ \
/ \
B E
/ \ \
/ \ \
A C G
/
/
F
将来の世代のためにツリーを記録するために、彼女はツリーごとに2つの文字列を書き留めました。プレオーダートラバーサル(ルート、左サブツリー、右サブツリー)とインオーダートラバーサル(左サブツリー、ルート、右サブツリー)です。上に描かれたツリーの場合、プレオーダートラバーサルはDBACEGFであり、インオーダートラバーサルはABCDEFGです。
彼女は、そのような文字列のペアが後でツリーを再構築するのに十分な情報を提供すると考えました(しかし、彼女はそれを試したことはありませんでした)。
さて、数年後、弦をもう一度見て、彼女は木を再構築することが確かに可能であることに気づきましたが、それは彼女が同じ木で同じ文字を二度使用したことがなかったからです。
しかし、手作業で再建を行うと、すぐに面倒であることが判明しました。
だから今、彼女はあなたに彼女のために仕事をするプログラムを書くように頼みます!
入力
入力には、1つ以上のテストケースが含まれます。
各テストケースは、バイナリツリーのプレオーダートラバーサルとインオーダートラバーサルを表す2つの文字列preordとinordを含む1行で構成されます。両方の文字列は一意の大文字で構成されています。(したがって、26文字以内です。)
入力はファイルの終わりで終了します。
出力
各テストケースについて、バレンタインの二分木を回復し、ツリーのポストオーダートラバーサル(左サブツリー、右サブツリー、ルート)を含む1行を出力します。
サンプル入力
DBACEGF ABCDEFG
BCAD CBADの
サンプル出力
ACBFGED
CDAB
タイトル説明:
二分木の一次走査と中次走査を与え、後者の順序で走査させます。
問題解決のアイデア:
二分木の一次、中、後次トラバーサルがどのように確立されるかについて話しましょう。二分木の
一次トラバーサルの操作は次のように定義されます。
二分木が空の場合、操作はありません。それ以外の場合は、
(I)ルートノードにアクセスします。
(2)最初に左の子ツリーを
トラバースします。(3)最初に右のサブツリーをトラバースします。
二分木の中次走査の操作は、次のように定義されます。
二分木が空の場合、操作はありません。それ以外の場合、
(1)左側のサブツリーの中次走査、
(2)ルートノードへのアクセス、
(3 )右のサブツリーの中次走査。
二分木のポストオーダートラバーサルの操作は、次のように定義されます。
バイナリツリーが空の場合、操作はありません。それ以外の場合、
(1)左側のサブツリーの
ポストオーダートラバーサル、(2)右側のポストオーダートラバーサル。サブツリー;
(3)ルートノードにアクセスします。
プレオーダートラバーサル:最初にルートノードにアクセスし、次に前の順序で左側のサブツリーと右側のサブツリーにアクセスします。
中次走査:左サブツリー、現在のノード、右サブツリー。
プレオーダートラバーサルとミドルオーダートラバーサルの特性に応じて、次のルールを見つけることができます。
プレオーダートラバーサルの各ノードは、現在のサブツリーのルートノードです。同時に、対応するノードを境界として、インオーダートラバーサルの結果が左側のサブツリーと右側のサブツリーに分割されます。
サンプル分析:
サンプル入力
DBACEGFABCDEFG
サンプル出力
ACBFGED
プレオーダー:DBACEGF'D
'はルートノードです。
ポストオーダートラバーサルでは、ルートノードは最後(ACBFGE D)
です。インオーダー:ABCDEFG'D
'はルートノードです。文字列を左に2つに分割し、右のサブツリー
「D 」は最初にノードの最初の要素を順番にトラバースします。中次のトラバースの結果を「ABC」と「EFG」の2つの部分、つまり左側のサブツリーに分割していることがわかります( ABC)と右のサブツリー(EFG)。
順序:ABC D EFG
は、左側のサブツリー(BAC)と右側のサブツリー(EGF)に対応するプレオーダートラバーサルを検索します。
事前注文:D BAC EGF
は、現在のルートノードとして「D」を取り、次に順次再帰することができるため、左側のサブツリーと右側のサブツリーのトラバーサル結果を順番に復元できます。
図
すべてのツリーを最も単純な二分木として扱います
プレオーダーおよびミドルオーダートラバーサルの特性からルートノードを見つけ、s3 [n-1 + ss1] = s1 [ss];を記録します(ポストオーダートラバーサルのルートノードは現在の終わりにあるため)二分木)
ルートノードを記録した後、左と右のサブツリーは最も単純な二分木と見なされます
kk(i、ss + 1、n1、ss1); //左のサブツリー
kk(ni-1、ss + i + 1、n1 + i + 1、ss1 + i); //右のサブツリー
総括する:
最初にルートノードを見つけ、次に左右のサブツリーを見つけ、次に左右のサブツリーを見つけ、最後に再帰によって順番にそれを実現します
(つまり、常にルートノードを検索します)
コード:
配列の実装
#include <stdio.h>
#include <string.h>
char s1[30],s2[30],s3[30];
void kk(int l, int ss, int l1, int ss1)
{
if(!l) //无子树
return;
int i;
for(i = 0; ; i++)
{
if(s1[ss] == s2[l1+i])//找到根结点
break;
}
s3[l-1+ss1] = s1[ss];//记录后序遍历结果
kk(i, ss+1, l1, ss1);//左子树
kk(l-i-1, ss+i+1, l1+i+1, ss1+i);//右子树
}
int main()
{
int n;
while(scanf("%s%s", s1, s2) != EOF)
{
n= strlen(s1);
kk(n, 0, 0, 0);
for(int i=0;i<n;i++)
printf("%c",s3[i]);
printf("\n");
}
return 0;
}
リンクリストの実装
#include <stdio.h>
#include <string.h>
#include <malloc.h>
typedef struct node
{
char ch;
struct node *left, *right;
}Node; //定义节点的结构
node *creat(char *p, char *p1, int len)
{
int k;
if (!len)//出口//无子树
return NULL;
Node *head= (Node*)malloc(sizeof(Node));
head -> ch = *p;
char *p2;
for (p2 = p1; p2 != NULL; p2++){
if (*p2 == *p) //找到根结点
break;
}
k = p2 - p1;
head -> left = creat(p + 1, p1, k); //左子树
head -> right = creat(p + k + 1, p2 + 1, len - k - 1); //右子树
return head;
}
void print(Node *head) //输出序列
{
if (head == NULL)
return ;
print(head -> left);
print(head -> right);
printf("%c",head -> ch);
}
int main()
{
char p[30], p1[30]; //存储先序和中序遍历的序列
Node *head;
head = (Node*)malloc(sizeof(Node));
while (scanf("%s %s",p,p1)!=EOF)
{
int len = strlen(p);
head = creat(p, p1, len);
print(head);
printf("\n");
}
return 0;
}