Farmer John takes the heritage of his cows very seriously. He is not, however, a truly fine bookkeeper. He keeps his cow genealogies as binary trees and, instead of writing them in graphic form, he records them in the more linear `tree in-order' and `tree pre-order' notations.
Your job is to create the `tree post-order' notation of a cow's heritage after being given the in-order and pre-order notations. Each cow name is encoded as a unique letter. (You may already know that you can frequently reconstruct a tree from any two of the ordered traversals.) Obviously, the trees will have no more than 26 nodes.
Here is a graphical representation of the tree used in the sample input and output:
C / \ / \ B G / \ / A D H / \ E F
The in-order traversal of this tree prints the left sub-tree, the root, and the right sub-tree.
The pre-order traversal of this tree prints the root, the left sub-tree, and the right sub-tree.
The post-order traversal of this tree print the left sub-tree, the right sub-tree, and the root.
Line 1: | The in-order representation of a tree. |
Line 2: | The pre-order representation of that same tree. |
ABEDFCHG CBADEFGH
AEFDBHGC思路:一、已知二叉树的前序序列和中序序列,求解树。
/* ID:nealgav1 LANG:C++ PROG:heritage */ #include<fstream> #include<cstring> using namespace std; const int mm=55; ifstream cin("heritage.in"); ofstream cout("heritage.out"); class node { public:char v; node*l,*r; node(){l=r=NULL;} }*pn; char pre[mm],mid[mm],post[mm]; ///i为在pre中的位置,j为在mid的开始端,len为长度 void creattree(node*&p,int i,int j,int len) { if(len<=0)return; p=new node(); p->v=pre[i]; int m=strchr(mid,pre[i])-mid; creattree(p->l,i+1,j,m-j); creattree(p->r,i+m-j+1,m+1,len-(m-j)-1); } void postvisit(node*p) { if(p!=NULL) { postvisit(p->l); postvisit(p->r); cout<<p->v; } } int main() { while(cin>>mid>>pre) { pn=NULL; creattree(pn,0,0,strlen(mid)); postvisit(pn); cout<<"\n"; } }
USER: Neal Gavin Gavin [nealgav1] TASK: heritage LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.000 secs, 3364 KB] Test 2: TEST OK [0.000 secs, 3364 KB] Test 3: TEST OK [0.000 secs, 3364 KB] Test 4: TEST OK [0.000 secs, 3364 KB] Test 5: TEST OK [0.000 secs, 3364 KB] Test 6: TEST OK [0.000 secs, 3364 KB] Test 7: TEST OK [0.000 secs, 3364 KB] Test 8: TEST OK [0.000 secs, 3364 KB] Test 9: TEST OK [0.000 secs, 3364 KB] All tests OK.YOUR PROGRAM ('heritage') WORKED FIRST TIME! That's fantastic -- and a rare thing. Please accept these special automated congratulations.
Here are the test data inputs:
------- test 1 ---- ABEDFCHG CBADEFGH ------- test 2 ---- F F ------- test 3 ---- BCAD ABCD ------- test 4 ---- GOLEAFS SFAELOG ------- test 5 ---- GSHBAQTPM ABGHSPQTM ------- test 6 ---- AUBYCVDZEWFXGTH ZYUABVCDXWEFTGH ------- test 7 ---- ABDCJHKILMNPOQFEGRS ABCDEFHJIKLMNOPQGRS ------- test 8 ---- GFDIHKLJMBNESRTPOQAUCWVZYX ABDFGHIJKLMENOPRSTQCUVWXYZ ------- test 9 ---- EHGDIFJLKMBNCOQSPRAWUXZYTV ABDEGHFIJKLMCNOPQSRTUWXYZVKeep up the good work!
American Heritage
Here's one way: We use a recursive procedure to generate the actual binary tree. Once we have the tree, we execute a postorder traversal to print the node values.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> FILE *fout; typedef struct Tree Tree; struct Tree { int c; Tree *left; Tree *right; }; Tree* mktree(int c, Tree *left, Tree *right) { Tree *t; t = (Tree*)malloc(sizeof *t); assert(t); t->c = c; t->left = left; t->right = right; return t; } /* * Pre and in point at strings of length len * that describe the same tree, in pre-order * and in-order traversals. Return a * corresponding binary tree. */ Tree* prein2tree(char *pre, char *in, int len) { char *p; int llen, rlen; assert(strlen(pre)>=len && strlen(in)>=len); if(len == 0) return NULL; /* * The first character of the preorder traversal is the root. * If we find the root in the inorder traversal, then everything * to its left is on the left side, and everything to its right on the * right side. Recur on both sides. */ p = strchr(in, pre[0]); assert(p != NULL); assert(p-in < len); llen = p-in; rlen = len-llen-1; return mktree(pre[0], prein2tree(pre+1, in, llen), prein2tree(pre+1+llen, p+1, rlen)); } void postorder(Tree *t) { if(t == NULL) return; postorder(t->left); postorder(t->right); fprintf(fout, "%c", t->c); } void main(void) { FILE *fin; char pre[50], in[50]; fin = fopen("heritage.in", "r"); fout = fopen("heritage.out", "w"); assert(fin != NULL && fout != NULL); fscanf(fin, "%s %s", in, pre); postorder(prein2tree(pre, in, strlen(pre))); fprintf(fout, "\n"); exit(0); }From Greg Price:
We don't need to reconstruct the original tree explicitly for this problem. Instead, we use a recursive function that plucks the root from the start of the preorder traversal, uses it to divide the inorder traversal, calls itself recursively on the left and right subtrees, and outputs the root.
#include <fstream.h> #include <string.h> ifstream fin("heritage.in"); ofstream fout("heritage.out"); const short maxn = 26 + 2; short len; char in[maxn], pre[maxn]; void makepost(short ina, short inb, short prea, short preb) { char root; short rt_in; short lsize, rsize; if (ina == inb) // Null tree return; root = pre[prea]; // Find root in inorder for (rt_in = ina; rt_in < inb; rt_in++) if (in[rt_in] == root) break; // Size of left-hand subtree lsize = rt_in - ina; makepost(ina, rt_in, prea+1, prea+1 + lsize); // Left subtree makepost(rt_in+1, inb, prea+1 + lsize, preb); // Right subtree fout << root; } void main() { fin.getline(in , maxn); fin.getline(pre, maxn); len = strlen(in); makepost(0, len, 0, len); fout << endl; }Another Solution -- Daniel Bundala
Here is a better and faster solution for problem "heritage". I usedstandard recursive approach like solutions in analysis for theproblem. But insert new element into the tree can be made faster.Because solutions in analysis in each recursive call are findingthe position of inserting element in in-order representation of thetree. It is O(N) in O(N) calls worth case = O(N^2).
But what we can do is to precompute positions of elements in in-orderrepresentation and when we are inserting new elment e into the noden, e is in left subtree if and only if position_in_inorder[i] <position_in_inorder[n->value] otherwise element e is in rightsubtree.
Now inserting: O(1) in O(N) recursive call - worth case = O(N).All algorithm is O(N^2) and before was O(N^3) - worth case. And O(Nlog N) now, before O(N^2) - average case; N = number of cows
My implementation (I'm using index into the array instead of pointer):
/* LANG: C++ PROG: heritage */ #include <stdio.h> #include <string.h> FILE *in,*out; char ino[200], preo[200]; int place[255]; struct NODE{ int left, right; char name; }; NODE node[200]; int count = 1; //return true if who is before the value of node[n] in inorder; O(1) bool isBefore(char who, int n){ return place[who] < place[node[n].name]; }; void insert(char c, int where){ if (isBefore(c, where)){ //in the left subtree if (node[where].left == -1){ //left subtree is empty node[count].left = node[count].right = -1; node[count].name = c; node[where].left = count++; } else { insert(c, node[where].left); //insert into the left subtree }; } else { // in the right subtree if (node[where].right == -1){ //right subtree is empty node[count].left = node[count].right = -1; node[count].name = c; node[where].right = count++; } else { insert(c, node[where].right); //insert into the right subtree }; }; }; void write(int kde){ if (kde==-1) return; write(node[kde].left); write(node[kde].right); fprintf(out, "%c", node[kde].name); }; int main () { in=fopen("heritage.in","r"); out = fopen ("heritage.out", "w"); fgets(ino, 200, in); fgets(preo, 200, in); for (int i=0; i<strlen(ino); i++) place[ino[i]] = i; //insert root node[0].left = node[0].right = -1; node[0].name = preo[0]; //insert next element for (int i=1; i<strlen(ino) - 1; i++) insert(preo[i], 0); write(0); fprintf(out, "\n"); fclose(in); fclose(out); return 0; }India's Nishant Redkar had a much simpler solution:#include <fstream> #include <string> using namespace std; ofstream out ("heritage.out"); void recursex (string sin, string spre) { int i; if (sin.length() < 2) { out << sin; return; } for (i = 0; sin[i] != spre[0]; i++); recursex (sin.substr(0,i), spre.substr(1,i)); recursex (sin.substr(i+1), spre.substr(i+1)); out << spre[0]; } int main () { string sin, spre; ifstream in("heritage.in"); in >> sin >> spre; recursex (sin, spre); out << endl; in.close(); out.close(); return 0; }