[英]BST in array traversal
我在数组中有以下二叉树的实现;
32
/ \
2 -5
/ \
-331 399
数据一次被分组为3个索引。 index%3==0
是节点的值, index%3==1
是左节点的值的index%3==2
, index%3==2
是右节点的值的索引。 如果左或右索引参考为0,则没有该方向的节点。
我试图找到这棵树的深度(高度)。 我已经递归地写了
height(node):
if node == null:
return 0
else:
return max(height(node.L), height(node.R)) + 1
我想找到一个非递归的解决方案。
这是我拥有的一些伪代码,假设树不为空
int i = 0; int left = 0; int right = 0;
while (i != n ){
if ( a[i+1] != 0 ){
left++;
}
else if ( a[i+2] != 0 ){
right++;
}
i = i + 3;
}
return max ( left, right ) + 1;
我认为这是不对的,我希望获得一些帮助来弄清楚如何正确执行此操作。
您没有说过递归问题是什么,以便我们了解您想要改善的行为。
有很多解决方案,但是几乎所有这些解决方案都具有与递归解决方案相同或更差的性能。 确实,最好的解决方案将是在创建树时必须要做的事情。 例如,您可以将每个节点的高度存储在每个节点的第四个数组索引中。 然后,对每个第四个索引进行琐碎的扫描以找到最大高度。 如果节点上存储有父级引用,这也将变得更加容易,这样就不必在高度检查期间进行计算。
一种解决方案是使用堆栈模拟递归,但这实际上与递归没有什么不同。
另一种解决方案是遍历每个节点并根据其父节点确定其高度,但不按特定遍历的顺序进行。 但是,由于配置方式的原因,而没有用于存储层次结构的辅助数据结构,效率会降低O(n ^ 2)。 问题是,如果没有完整的阵列扫描,您将无法从孩子那里得到父母。 然后,您可以在线性时间内做到这一点(但是递归也是线性时间,因此我不确定我们做得更好。从内存的角度来看,也不会变得更好)。
您可以定义要提高哪种效率?
这是每个的伪代码 ,但是我依赖于一些不容易呈现的数据结构:
“递归不递归”解决方案:
int get_height(int * tree, int length) {
Stack stack;
int max_height = 0;
if (length == 0) {
return 0;
}
// push an "array" of the node index to process and the height of its parent.
// make this a struct and use that for real c code
stack.push(0,0);
while(!stack.empty()) {
int node_index, parent_height = stack.pop();
int height = parent_height + 1;
if (height > max_height) {
max_height=height;
}
if (tree[node_index+1] != 0 )
stack.push(tree[node_index+1], height);
if (tree[node_index+2] != 0 )
stack.push(tree[node_index+2], height);
}
return max_height;
}
现在正在研究一种非常慢的解决方案,该解决方案不使用任何额外的内存,但这确实很糟糕。 就像递归地写斐波那契一样。 原始算法遍历每个节点并执行O(n)检查最坏情况,以获取O(n ^ 2)的运行时间(实际上并没有我最初想象的那么糟糕)
编辑:很久以后,我要添加一个优化,以跳过所有带有孩子的节点。 这非常重要,因为它可以减少大量呼叫。 最好的情况是,树实际上是一个链表,在这种情况下,树的运行时间为O(n)。 最坏的情况是一棵完全平衡的树-每个登录树的叶子节点都进行登录,然后检查回O((log(n)^ 2)的根。这还不算太糟。下面的几行标记为
“确实很慢,但没有额外的内存”解决方案(但现在更新为不会太慢):
int get_height(int * tree, int length) {
int max_height = 0;
for (int i = 0; i < length; i+=3) {
// Optimization I added later
// if the node has children, it can't be the tallest node, so don't
// bother checking from here, as the child will be checked
if (tree[i+1] != 0 || tree[i+2] != 0)
continue;
int height = 0;
int index_pointing_at_me;
// while we haven't gotten back to the head of the tree, keep working up
while (index_pointing_at_me != 0) {
height += 1;
for (int j = 0; j < length; j+=3) {
if (tree[j+1] == tree[i] ||
tree[j+2] == tree[i]) {
index_pointing_at_me = j;
break;
}
}
}
if (height > max_height) {
max_height = height;
}
}
return max_height;
}
在以前的解决方案上进行了改进,但是使用了O(n)内存-假设父母总是在数组中的孩子之前(我认为这在技术上不是必需的)
int get_height(int * tree, int length) {
if (length == 0)
return 0;
// two more nodes per node - one for which node is its parent, the other for its height
int * reverse_mapping = malloc((sizeof(int) * length / 3) * 2)
reverse_mapping[1] = 1; // set height to 1 for first node
// make a mapping from each node to the node that points TO it.
// for example, for the first node
// a[0] = 32
// a[1] = 3
// a[2] = 6
// store that the node at 3 and 6 are both pointed to by node 0 (divide by 3 just saves space since only one value is needed) and that each child node is one taller than its parent
int max_height = 0;
for (int i = 0; i < length; i+=3) {
int current_height = reverse_mapping[(i/3)*2+1];
if (current_height > max_height)
max_height = current_height;
reverse_mapping[(tree[i+1]/3)*2] = i;
reverse_mapping[(tree[i+1]/3)*2 + 1] = current_height + 1;
reverse_mapping[(tree[i+2]/3)*2] = i;
reverse_mapping[(tree[i+2]/3)*2 + 1] = current_height + 1;
}
return max_height
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.