这是完整的问题:
编写一个获取两个长度为n的数组的函数。第一个数组是PreOrder一些 二叉树,第二个数组是二叉树的InOrder。功能输出 二叉树。
// the function recovers the tree from its inorder and preorder
BTnode_t* reconstruct_tree( int * preorder, int * inorder, int n)
给出的结构和功能:
struct BTnode {
int value;
struct BTnode* left;
struct BTnode* right;
struct BTnode* parent;
};
typedef struct BTnode BTnode_t;
BTnode_t* create_node(int val) {
BTnode_t* newNode = (BTnode_t*) malloc(sizeof(BTnode_t));
newNode->value = val;
newNode->left = NULL;
newNode->right = NULL;
newNode->parent = NULL;
return newNode;
}
我如何解决此问题的实现,目前无法正常工作,我认为我的错误在于我如何在递归步骤中发送索引。
#include <stdio.h>
#include <stdlib.h>
#include "assignment4.h"
int search(int arr[], int strt, int end, int value);
int search(int arr[], int strt, int end, int value)
{
int i;
for (i = strt; i <= end; i++) {
if (arr[i] == value)
return i;
}
}
// the function recovers the tree from its inorder and preorder
BTnode_t* reconstruct_tree(int* preorder, int* inorder, int n) {
// implement me
int preIndex = 0;
BTnode_t* newnode = create_node(preorder[preIndex]);
preIndex++;
if( sizeof(inorder) > n-1)
return NULL;
if( sizeof(inorder) == n-1)
return newnode;
int inIndex = search( inorder, 0, n - 1, newnode->value);
newnode->left = reconstruct_tree(preorder, inorder, inIndex -1);
newnode->right = reconstruct_tree(preorder, inorder + inIndex +1, n-1 );
return newnode;
}
用于测试这部分作业的代码:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "assignment4.h"
bool BT_equal(BTnode_t* t1, BTnode_t* t2) {
if (t1 == t2)
return true;
if ((t1 && !t2) || (!t1 && t2))
return false;
return (t1->value == t2->value) && BT_equal(t1->left, t2->left) && BT_equal(t1->right, t2->right);
}
BTnode_t* create_my_tree() {
BTnode_t* n1 = create_node(1);
BTnode_t* n2 = create_node(2);
BTnode_t* n3 = create_node(3);
BTnode_t* n4 = create_node(4);
BTnode_t* n5 = create_node(5);
BTnode_t* n6 = create_node(6);
BTnode_t* n7 = create_node(7);
n1->parent = NULL;
n1->left = n2;
n2->parent = n1;
n1->right = n3;
n3->parent = n1;
n2->left = n4;
n4->parent = n2;
n4->left = NULL;
n4->right = NULL;
n2->right = n5;
n5->parent = n2;
n5->left = NULL;
n5->right = NULL;
n3->left = n6;
n6->parent = n3;
n6->left = NULL;
n6->right = NULL;
n3->right = n7;
n7->parent = n3;
n7->left = NULL;
n7->right = NULL;
return n1;
}
bool test_q1() {
BTnode_t* n1 = create_my_tree();
int preorder[] = {1,2,4,5,3,6,7};
int inorder[] = {4,2,5,1,6,3,7};
BTnode_t* tree = reconstruct_tree(preorder, inorder, 7);
if (BT_equal(tree, n1)) {
printf("Q1 - ok\n");
return true;
}
else {
printf("Q1 - error\n");
return true;
}
}
我从视觉上理解算法,我已经考虑了很长时间并且很努力,我认为我正确地发送了索引。
我的问题:我是否错误地进行了递归调用?我认为sizeof()返回的是sizeof(int)返回的值,例如,我应该如何正确执行此操作?有人能指出我正确的方向吗?还是指出任何明显的问题?
提前谢谢!
重要修改
我知道了-这是正确的代码
BTnode_t* reconstruct_tree(int* preorder, int* inorder, int n) {
// implement me
static int preIndex = 0;
BTnode_t* newnode = create_node(preorder[preIndex]);
preIndex++;
if (n<=1){
return newnode;
}
int inIndex = search( inorder, 0, n - 1, newnode->value);
newnode->left = reconstruct_tree(preorder, inorder, inIndex);
newnode->right = reconstruct_tree(preorder, inorder + inIndex +1, n - inIndex -1 );
return newnode;
}
但是我仍然不明白为什么递归调用有效,有人可以解释一下递归是如何发生的
答案 0 :(得分:1)
好吧,首先要说的是,给定的序列上有一个简单的重映射,它允许您从有序序列中构造树,仅基于以下事实:重新映射只会使事情复杂化,而不会增加对问题。因此,我将对问题描述进行以下简化:
预排序序列集并不总是与给定的排序序列兼容。
证明:在这种情况下,让我们从一个有序序列(假设预序列为数字0..N-1的有序集合)中假设树的构建过程,对于作为某个子树根的每个节点,该树的id的最小值应为子树的根...,minimum + 1应该为其左节点的子树,除非左子树为空。让我们用以下符号表示这个事实:
(n)
/ \
[lllllll(n+1)llll] [rrrrrrrr]
和(n+1)
仅在右侧分区为空的情况下位于右侧分区:
(n)
/ \
* [rrrrrrrr(n+1)rrrrrrrrrrr]
因此,如果有序序列具有非空的左子树,并且预排序中的(n+1)
元素在序列中(n)
之后,则不可能构建其中有预排序序列的树已验证。这在您的代码中体现为搜索的项目不存在于左子树中,因为它是非空的。我的解决方案(找到的最小值)总是提供一个带有无效前序树的解决方案,但其中的所有节点都以升序插入,并将它们附加到已经存在的节点中。当该顺序为有效的预购订单时,则两种算法都会得出相同的结果。
我将为您提供一种解决方案,该解决方案将探索有序节点的数组,并在遇到最小id
值(应为子树的根)的点处对其进行划分,然后将该算法再次应用于代表左子树和右子树的数组。该算法将创建的节点附加到传递的父节点上,并返回匹配树的根:
#include <assert.h>
#include <stdlib.h>
#include "node.h"
struct node *build(const unsigned *l, int sz, struct node *parent)
{
if (sz == 0) return NULL;
struct node *res = malloc(sizeof *res);
assert(res != NULL);
int i, im = -1;
unsigned m = ~0;
for (i = 0; i < sz; i++) {
const unsigned c = l[i];
if (c < m) {
m = c;
im = i;
}
}
assert (im >= 0 && im < sz);
res->id = m;
res->parent = parent;
res->left = build(l, im, res);
res->right = build(l + im + 1, sz - im - 1, res);
return res;
}
一个完整的解决方案或此算法,它打印树(重新编号以产生与有效的有序正序序列相匹配的有效有序序列,对于同一棵树---允许产生有序/预序列数据集的有效序列)在github中给出。