简体   繁体   English

创建特定形状的二叉树

[英]Creating a binary tree of a specific shape

I want to create a binary tree from the following list, where in each line, the first number indicates the value to be stored at the node, second number indicates if the node has a left child (1 if yes, 0 if no) and third number indicates if the node has a right child:我想从下面的列表中创建一个二叉树,在每一行中,第一个数字表示要存储在节点上的值,第二个数字表示节点是否有左孩子(如果有,则为 1,如果没有,则为 0)和第三个数字表示节点是否有右孩子:
297 1 1 297 1 1
319 0 1 319 0 1
124 1 1 124 1 1
282 0 0 282 0 0
530 1 1 530 1 1
424 0 0 424 0 0
287 1 1 287 1 1
214 0 0 214 0 0
471 0 0 471 0 0
376 0 1 376 0 1
173 0 0 173 0 0

So the tree should look like this:所以树应该是这样的:
从列表中生成的树

Traversals of the tree should look like this:树的遍历应该是这样的:
Preorder: 297 319 282 124 530 287 471 376 173 214 424预购:297 319 282 124 530 287 471 376 173 214 424
Inorder: 319 282 297 471 287 376 173 530 214 124 424订购:319 282 297 471 287 376 173 530 214 124 424

But my program gives this output:但是我的程序给出了这个 output:
错误的输出画面

Here is my code.这是我的代码。 I have created an array of structures to represent the list:我创建了一个结构数组来表示列表:

struct node_info{
    int element;
    int leftbit;
    int rightbit;
};

struct node_info node_list[50];

Code describing tree node and new node:描述树节点和新节点的代码:

struct Node {
    int data;
    int ref_idx;
    struct Node *left, *right;
};

Node* newNode(int data, int idx){
    Node* temp = new Node;
    temp->data = data;
    temp->ref_idx = idx;
    temp->left = temp->right = NULL;
    return temp;
}

Below is the code to insert a new node.下面是插入新节点的代码。 I think this is where the problem is:我认为这就是问题所在:

void insertNode(struct Node* root, int list_idx){
    if(root->left == NULL && node_list[root->ref_idx].leftbit == 1){
        root->left = newNode(node_list[list_idx].element, list_idx);
        return;
    }
    else if(root->right == NULL && node_list[root->ref_idx].rightbit == 1){
        root->right = newNode(node_list[list_idx].element, list_idx);
        return;
    }
    else if(root->left != NULL){
        insertNode(root->left, list_idx);
    }
    else if(root->right != NULL){
        insertNode(root->right, list_idx);
    }
    else{
        cout << "\nInvalid case detected!\n";
    }
}

This is the main function where I give the inputs and build the tree.这是主要的 function,我在其中提供输入并构建树。 Notice that I have added the root node manually while using the insertNode function to add all the other nodes:请注意,我在使用 insertNode function 添加所有其他节点时手动添加了根节点:

int main(){
    node_list[0].element = 297;
    node_list[0].leftbit = 1;
    node_list[0].rightbit = 1;
    node_list[1].element = 319;
    node_list[1].leftbit = 0;
    node_list[1].rightbit = 1;
    node_list[2].element = 124;
    node_list[2].leftbit = 1;
    node_list[2].rightbit = 1;
    node_list[3].element = 282;
    node_list[3].leftbit = 0;
    node_list[3].rightbit = 0;
    node_list[4].element = 530;
    node_list[4].leftbit = 1;
    node_list[4].rightbit = 1;
    node_list[5].element = 424;
    node_list[5].leftbit = 0;
    node_list[5].rightbit = 0;
    node_list[6].element = 287;
    node_list[6].leftbit = 1;
    node_list[6].rightbit = 1;
    node_list[7].element = 214;
    node_list[7].leftbit = 0;
    node_list[7].rightbit = 0;
    node_list[8].element = 471;
    node_list[8].leftbit = 0;
    node_list[8].rightbit = 0;
    node_list[9].element = 376;
    node_list[9].leftbit = 0;
    node_list[9].rightbit = 1;
    node_list[10].element = 173;
    node_list[10].leftbit = 0;
    node_list[10].rightbit = 0;

    struct Node* test_root = newNode(node_list[0].element, 0);
    for(int i = 1; i < 11; i++){
        insertNode(test_root, i);
    }

    cout << "\nPreorder: ";
    printPreorder(test_root);

    cout << "\nInorder: ";
    printInorder(test_root);
}

What exactly is wrong with my insertNode function?我的 insertNode function 到底出了什么问题? Note that I want my program to be able to handle any kind of input so I cannot build the tree manually and therefore need a function to find where to place each node.请注意,我希望我的程序能够处理任何类型的输入,因此我无法手动构建树,因此需要 function 来查找放置每个节点的位置。

I think you have made this way to hard for yourself.我认为你已经为自己努力了。

Fixing the code you provided is going to be hard.修复您提供的代码将很难。 You would need to write this in a way that retained information between calls to insertNode() to remember where you had reached previously to understand where you need to insert the next value.您需要以在调用insertNode()之间保留信息的方式编写此代码,以记住您之前到达的位置以了解您需要插入下一个值的位置。 Simply returning the "last" node is not enough, as you need to be able to go back up the tree at some point.仅仅返回“最后一个”节点是不够的,因为您需要能够在某个时候 go 备份树。

You have defined your input in a bread first order.您已经在面包第一顺序中定义了您的输入。 So the standard technique for solving that is to push each where new values go onto a stack and use that to keep track of your position.因此,解决这个问题的标准技术是将每个新值 go 推送到堆栈上,并使用它来跟踪您的 position。

I am sure it can be done (but its hard).我相信它可以完成(但很难)。
Also in my opinion ugly.在我看来也是丑陋的。

So I would suggest you use an alternative solution (see below).因此,我建议您使用替代解决方案(见下文)。

Let us give it a go at solving your problem:让我们给它一个 go 来解决您的问题:

// This is the state you need to remember
// between calls to insertNode()
std::list<Node**>  nextNode;

// This is the root of your tree.
struct Node* root = nullptr

// Setup. Push the root as the first node.
nextNode.push_front(&root);   // The location of the first node.

// Now lets loop over your input.
for(int i = 0; i < 11; i++){
    if (nextNode.empty()) {
        // ERROR
    }
    // Pull out the pointer we want to update.
    Node** node = nextNode.pop_back();
    // Create the node for that pointer.
    (*node) = insertNode(ode_list[i].element);

    // Push the pointers we want to assign.
    if (node_list[i].leftbit) {
        nextNode.push_front(&((*node)->left));
    }
    if (node_list[i].rightbit) {
        nextNode.push_front(&((*node)->right));
    }
}
if (!nextNode.empty()) {
    // ERROR
}

I would redesign the input format into something that can be easily parsed recursively.我会将输入格式重新设计为可以轻松递归解析的格式。 At the heart of this is a Node .它的核心是一个Node So you should define a format that represents a node.所以你应该定义一个代表节点的格式。

Node => Integer Left Right

The main issue is that Left and Right are recursively pointing toanother Node or potentially null .主要问题是LeftRight递归地指向另一个Node或可能null So you have to be able to distinguish this.所以你必须能够区分这一点。 So When you start reading Left you have to know if it is null or a value.因此,当您开始阅读Left时,您必须知道它是null还是一个值。 So let us introduce X as the null value in out input as this does not conflict with the alternative which is Integer .因此,让我们在输出输入中引入X作为null值,因为这与替代方案Integer不冲突。

So now we define the input as:所以现在我们将输入定义为:

 Node =>   'X'                             // The null node
      =>   Integer Node(left) Node(right)  // A value followed by two nodes.

So we can now represent your tree like this:所以我们现在可以像这样表示你的树:

 297 319 X 282 X X 124 530 287 471 X X 376 X 173 X X 214 X X X X

Let's try and break that up visually:让我们尝试在视觉上分解它:

 297 319 X 282 X X 124 530 287 471 X X 376 X 173 X X 214 X X 424 X X
 V   -----L------- -----------------R-------------------------------

 // The left sub-tree from Root 
 // This is easier to visualize
 //       A value of 319
 //       left is null
 //       right is another sub-tree with 282 and two nulls.
 319 X 282 X X 
 V   L ---R---

 // The right sub-tree from Root
 // Not as easy to see (but I leave you home work
 // to see if you can break that down by hand.
 124 530 287 471 X X 376 X 173 X X 214 X X 424 X X
 V   --------------L---------------------- ---R---

With this format it becomes relatively easy to read as the function;使用这种格式,function 变得相对容易阅读; read a node simply reads an X and returns null, or reads a value creates a node and then recursively tries to read the left and right values.读取一个节点只是读取一个 X 并返回 null,或者读取一个值创建一个节点,然后递归地尝试读取左右值。

 Node* readNodeFromStream(std::istream& stream)
 {
      char next;
      if(stream >> next) {
          if (next == 'X') {
              return nullptr;
          }
      }
      else {
          // There is an error reading from the stream
          // Take appropriate action.
      }

      stream.unget(); // Put last character that was not an X
                      // back on the stream so we can read it
                      // as part of the number.
      int value;
      if (stream >> value) {
          Node* result = new Node{value};
          result->left  = readNodeFromStream(stream);
          result->right = readNodeFromStream(stream);
          return result;
      }
      else {
          // Error reading from stream.
          // Take appropriate action
      }
 }

 int main()
 {
     std::string input = "297 319 X 282 X X 124 530 287 471 X X 376 X 173 X X 214 X X X X";
     std::stringstream instream(input);

     Node* root = readNodeFromStream(instream);
 }

As I write this, you have one person who addresses reading your data.在我写这篇文章时,您有一个人负责读取您的数据。 But that doesn't explain your error.但这并不能解释你的错误。

Consider the path to add 530. By the time you add 530, you're going to proceed down the left path to the 282, which can't take children, and that leaves you with nowhere to put it.考虑添加 530 的路径。当您添加 530 时,您将沿着左侧路径前往 282,它不能带孩子,这让您无处可放。

You need to think of your insert code as "try to insert" and return bool true if success, false if not.您需要将插入代码视为“尝试插入”,如果成功则返回 bool true,否则返回 false。 If it fails to be able to insert when you try the left path, you can then try the right path.如果尝试左侧路径时无法插入,则可以尝试右侧路径。

But right now, you go down to the 282, can't add children, and return that error because you make no effort to take another path on failure.但是现在,您将 go 降到 282,无法添加子项,并返回该错误,因为您不努力在失败时采取另一条路径。

Seems that @JosephLarson explain why your implementation doesn't work.似乎@JosephLarson 解释了为什么您的实现不起作用。 If u want to parse format which you described in question (if not, so @Martin York offer other format and how to parse it) u cant do it recursively.如果你想解析你所描述的格式(如果不是,那么@Martin York 提供其他格式以及如何解析它)你不能递归地做。 You must do it level by level no subtree by subtree (recursive method).您必须逐级进行,没有子树的子树(递归方法)。 So i offer u to use queue to understand which will be parent for current.所以我让你使用队列来了解哪个是当前的父级。 My implementation:我的实现:

Node* insertNode(int list_idx){
    static std::queue < Node* > q;
    Node* new_node = newNode(node_list[list_idx].element, list_idx);
    if (!q.empty()){
        Node* parent = q.front();
        q.pop();
        if (parent->left == nullptr && node_list[parent->ref_idx].leftbit == 1){
            parent->left = new_node;
        } else if (parent->right == nullptr && node_list[parent->ref_idx].rightbit == 1){
            parent->right = new_node;
        } else {
            std::cerr << "Something goes wrong";
            exit(1);
        }
    } else {
        // means that it's root and we have no parent
        // we will return root several lines below
    }
    if (node_list[list_idx].leftbit == 1){
        q.push(new_node);
    }
    if (node_list[list_idx].rightbit == 1){
        q.push(new_node);
    }
    return new_node;
}

int main(){
    // --- some initialization ---
    // then action:
    struct Node* test_root = insertNode(0);
    for(int i = 1; i < 11; i++){
        insertNode(i);
    }


    cout << "\nPreorder: ";
    printPreorder(test_root);

    cout << "\nInorder: ";
    printInorder(test_root);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM