最近数据结构课给了一个二叉树的作业,给出二叉树的中序和后序遍历的序列,要求构建出改二叉树。我最初的时候是想到用map和RMQ来,以稳定O(nlogn)的时间构建这棵树。这样的复杂度已经是比普通的构建方法最坏情况O(n^2)(也就是单链的情况下)的复杂度要快不少的了。不过,今天在我打模板的时候找回我的笛卡尔树算法,那时忘记了是用来处理RMQ转LCA还是LCA转RMQ的了。于是,我就去回顾了一下LCA和RMQ的资料,发现RMQ是可以转成LCA的,其中区间最小值就是二叉树的对应的那两个端点结点的LCA(最低公共祖先)。以RMQ构建出来的树也恰好是我们想要的树。代码测试通过过小数据,准备用大数据来试下有没有什么漏洞 !
用RMQ的代码,有点复杂。。。囧:
View Code
用笛卡尔树的代码,主要操作比较简短:
View Code
1 /* 2 Author : SCAU_Lyon 3 Class : Software Engineering Class 10 4 Stu_ID : 201131001011 5 Problem : build binary tree by in-order && post-order traverse 6 Time Complexity : O(n) 7 Algorithm : Cartesian Tree, Hash Table 8 Date : 2012-11-05 9 Declaration : At the second day, I find a new method to solve this problem with a more efficient and space-saving algorithm. 10 Usage : First, input the size; then, input the in-order traverse list; last, input the post-order traverse list. 11 Warning : Every key should be unique! And, the tree's size is better lower than 100000! 12 */ 13 14 #include <cstdio> 15 #include <cstring> 16 #include <vector> 17 #include <algorithm> 18 19 using namespace std; 20 21 typedef vector<int> vi; 22 const int maxHash = 400009; 23 const int HASH = 0x55555555; 24 vi inOrder, postOrder; 25 int hash[maxHash], hashPos[maxHash]; 26 27 void initHash() { 28 memset(hashPos, -1, sizeof(hashPos)); 29 } 30 31 void insHash(int pos, int key) { 32 int p = ((key << 4) ^ HASH) % maxHash; 33 34 if (p < 0) p += maxHash; 35 while (hash[p] != key && ~hashPos[p]) { 36 p++; 37 if (p >= maxHash) p -= maxHash; 38 } 39 40 hash[p] = key; 41 hashPos[p] = pos; 42 } 43 44 int getHash(int key) { 45 int p = ((key << 4) ^ HASH) % maxHash; 46 47 if (p < 0) p += maxHash; 48 while (hash[p] != key && ~hashPos[p]) { 49 p++; 50 if (p >= maxHash) p -= maxHash; 51 } 52 53 return hashPos[p]; 54 } 55 56 struct Node { 57 int key, fix; 58 Node *c[2], *p; // c[0] is the left child, c[1] is the right child 59 60 Node(int _key = 0, int _fix = 0) { 61 key = _key; 62 fix = _fix; 63 p = c[0] = c[1] = NULL; 64 } 65 } ; 66 67 struct Cartesian { 68 Node *Root, *Back; 69 70 Cartesian() { 71 Root = Back = NULL; 72 } 73 74 void delMain(Node *&rt) { 75 if (!rt) return ; 76 delMain(rt->c[0]); 77 delMain(rt->c[1]); 78 delete rt; 79 rt = NULL; 80 } 81 82 void delTree() { 83 delMain(Root); 84 } 85 86 void pushBack(Node *x) { 87 while (Back && Back->fix < x->fix) { 88 Back = Back->p; 89 } 90 if (Back) { 91 x->c[0] = Back->c[1]; 92 if (Back->c[1]) { 93 Back->c[1]->p = x; 94 } 95 Back->c[1] = x; 96 x->p = Back; 97 } else { 98 x->c[0] = Root; 99 if (Root) Root->p = x; 100 Root = x; 101 } 102 Back = x; 103 } 104 105 void _pushBack(int key, int fix) { 106 Node *tmp = new Node(key, fix); 107 pushBack(tmp); 108 } 109 110 void preTra(Node *rt) { 111 if (!rt) return ; 112 printf("%d ", rt->key); 113 preTra(rt->c[0]); 114 preTra(rt->c[1]); 115 } 116 117 void preTraverse() { 118 puts("pre-traverse : "); 119 preTra(Root); 120 puts(""); 121 } 122 123 void inTra(Node *rt) { 124 if (!rt) return ; 125 inTra(rt->c[0]); 126 printf("%d ", rt->key); 127 inTra(rt->c[1]); 128 } 129 130 void inTraverse() { 131 puts("in-traverse : "); 132 inTra(Root); 133 puts(""); 134 } 135 136 void postTra(Node *rt) { 137 if (!rt) return ; 138 postTra(rt->c[0]); 139 postTra(rt->c[1]); 140 printf("%d ", rt->key); 141 } 142 143 void postTraverse() { 144 puts("post-traverse : "); 145 postTra(Root); 146 puts(""); 147 } 148 } cart; 149 150 void input(int n) { 151 int x; 152 153 inOrder.clear(); 154 postOrder.clear(); 155 initHash(); 156 157 for (int i = 0; i < n; i++) { 158 scanf("%d", &x); 159 inOrder.push_back(x); 160 } 161 for (int i = 0; i < n; i++) { 162 scanf("%d", &x); 163 postOrder.push_back(x); 164 insHash(i, x); 165 } 166 } 167 168 void buildTree(int n) { 169 cart = Cartesian(); 170 for (int i = 0; i < n; i++) { 171 cart._pushBack(inOrder[i], getHash(inOrder[i])); 172 } 173 } 174 175 int main() { 176 int n; 177 178 // freopen("in", "r", stdin); 179 while (~scanf("%d", &n)) { 180 input(n); 181 buildTree(n); 182 puts("Built Successfully!"); 183 184 // cart.preTraverse(); 185 // cart.inTraverse(); 186 // cart.postTraverse(); 187 // puts(""); 188 /*** You can add other functions here! ***/ 189 190 /*****************************************/ 191 192 cart.delTree(); 193 } 194 195 return 0; 196 }
一个简单的算法就这样被我搞复杂了,还用了不少非教材上的算法。。。囧!不过还是挺好玩的~
补充:通过大数据(100组约60000个结点的随机数据)的运算,算法1平均要27秒,算法2平均只要9秒~
——written by Lyon