数据结构作业:利用中序遍历和后序遍历构建二叉树(RMQ转LCA)

  最近数据结构课给了一个二叉树的作业,给出二叉树的中序和后序遍历的序列,要求构建出改二叉树。我最初的时候是想到用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

转载于:https://www.cnblogs.com/LyonLys/archive/2012/11/06/DS_20121106_Lyon.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值