假设我们获得了一个级别顺序遍历输出。如何从填充了正确位置的数据构建二叉树?
请注意,我不是要尝试从给定的遍历输出中绘制树,而是从数组中读取遍历数据,然后通过C中的实际编码填充二叉树。
例如:
设a [] = {A,B,C,D,E,F,G}; //数组中的遍历输出
所以级别顺序树看起来像这样:
A
/ \
B C
/ \ / \
D E F G
假设有一个树节点结构,如下所示:
typedef struct node
{
char data;
struct node* left;
struct node* right;
}tree;
现在我正在尝试读取[]值并对此树进行编码,使其看起来像图。有许多级别顺序遍历的例子,但是在二叉树构造的实际编码中找不到任何相关的东西。这有点像“遍历的逆转”。
另请注意,这不是家庭作业,但如果有更多人会注意到这一点我没有标记问题。 :)
答案 0 :(得分:6)
这就像 BFS ,因此您可以使用队列。
请注意,您始终指定左孩子,然后立即分配正确的孩子。 所以从包含root的队列开始。在每次迭代时,从队列中弹出节点,然后从数组(或流)中读取接下来的两个值。使第一个成为弹出节点的左子节点并将其推入队列。然后使第二个成为正确的孩子并将其推入队列。依此类推,直到数组(或流)中没有任何元素。
答案 1 :(得分:5)
对于完整(或填充)二叉树,可以轻松将级别遍历转换为任何遍历,因为位置n
处的节点的子项位于 2n
并且当数组为1索引时为2n+1
,当数组为0索引时为 2n+1
和2n+2
。
因此,您可以轻松地使用该公式将其转换为您最喜欢的遍历顺序,以便将节点插入树中(如预订)。
e.g。递归的伪代码:
void fill( TreeNode* node, char a[], int arrayLength, int n ){
// n is the position of the current "node" in the array
if( n < arrayLength ){
node->data = a[n];
fill( node->left, a, arrayLength, 2n+1 );
fill( node->right, a, arrayLength, 2n+2 );
}
}
答案 2 :(得分:5)
一种可能的解决方案:
char a[SIZE] = {A,B,C,D,E,F,G};
node* func(int index){
if(index < SIZE){
node *tmp = new node();
tmp->data = a[index];
tmp->left = func(2*index + 1);
tmp->right = func(2*index + 2);
}
return tmp;
}
树的stacktrace:
A->a[0]
B->func(2*0 + 1)=[1] C->func(2*0 + 2)=[2]
D->func(2*1 + 1)=[3] E->func(2*1 + 2)=[4] F->func(2*2 + 1)=[5] G->func(2*2 + 2)=[6]
答案 3 :(得分:2)
如果使用一些额外的存储空间,可以相当容易地以迭代方式执行此操作,从而节省递归解决方案的调用开销。这就是我要做的事情:
node* theTree (char[] a, int arraylength) {
if (arraylength == 0) return NULL;
node** nodes = new node*[arraylength];
nodes[0] = new node();
nodes[0]->data = a[0];
for (int i = 0, j = 0; TRUE ; j++) {
if (++i >= arraylength) return nodes[0];
nodes[i] = new node();
nodes[i]->data = a[i];
nodes[j]->left = nodes[i];
if (++i >= arraylength) return nodes[0];
nodes[i] = new node();
nodes[i]->data = a[i];
nodes[j]->right = nodes[i];
}
}
可能的改进包括通过在i> 1之后重写指针数组的部分来将所需的存储器减少两倍。 arraylength / 2,并且可能自己在数组中一次性预分配所有节点(尽管你需要小心重新分配)。