【问题标题】:BST build tree double pointersBST 构建树双指针
【发布时间】:2014-12-11 07:33:17
【问题描述】:

我不确定如何将指针设置为指向构建树的指针。就像我曾经到一片叶子并调用插入一样,我应该如何插入另一个元素调用插入与根节点或根指针的地址?我认为这个函数的问题是名称根应该是双指针吗?

#include "bst.h"
#include <stdio.h>
#include <stdlib.h>

//arbitrary list of temp nodes

TreeNode *new_node, *root, *tmp, *parent;
int elemArray[100], i1, i2, i0;


int main( int argc, char *argv[] ) {

    //Throw error is *Argv[] is not an integer
    //assuming it was an integer
    int cnt = atoi( argv[1] );
    printf( "number is %d\n", cnt );
    //
    printf("Enter %i integer values to place in tree:\n", cnt);
    for ( i1 = 0; i1 < cnt; ++i1) {
        scanf( "%d", &elemArray[i1] );
    }

    //first ouput "INput Values"

    printf( " Input Values:\n " );  
     for ( i2 = 0; i2 < cnt; ++i2) {
               printf( "%d\n", elemArray[i2] );
        }
    TreeNode** root = (TreeNode*)malloc(sizeof(TreeNode*));

    buildTree(root, elemArray, cnt );

    printf( "Preorder:\n ");

    //traverse
    //TreeNode* tempN = malloc(sizeof(TreeNode*));
    //tempN->data= 5;

    traverse( root, PREORDER);

    //traverse a single node 
    printf( "Inorder:\n ");

    printf( "Postorder:\n ");


    //Build tree with each element

    return 0;
}

这是.h文件

/// The definition of the tree structure
typedef struct TreeNode {
    int data ;                  // the data stored in the node
    struct TreeNode* left ;     // node's left child
    struct TreeNode* right ;    // node's right child
} TreeNode;

/// The three supported traversals
typedef enum {
    PREORDER,           // parent -> left -> right
    INORDER,            // left -> parent -> right
    POSTORDER           // left -> right -> parent
} TraversalType;

最后是遍历函数,因为它没有通过第一次测试。

void traverse( const TreeNode* root, const TraversalType type ) {

    if ( type == PREORDER) {
             if (root != NULL)
             {
                printf("%d", root->data);
                traverse( root->left, PREORDER);
                traverse( root-> right, PREORDER);
            }
    }
}

void build_tree(TreeNode** root, const int elements[], const int count) {

    TreeNode* node = malloc(sizeof(TreeNode*));
    node->left = node ->right = NULL;

    *root = node;

    for ( int i0 = 0; i0 < count; ++i0 ){
        TreeNode* node = malloc(sizeof(TreeNode*));
        *root = node;
        node->data = elements[cnt];
        insertNode( &(*root), &node );
    }

}

为什么 insertNode 得到错误(多个),我不知道哪个是指针,哪个是结构。伙计们,任何提示会有所帮助吗?

bst.c:94:20: error: request for member 'left' in something not a structure or union
         insert(root->left, new_node);


void insertNode(TreeNode** root, TreeNode* new_node) {

   if (new_node-> data < &root-> data) {
      if (&root-> left == NULL) 
         &root-> left == new_node;
      else
        insert(root->left, new_node);
   }

  if (new_node->data > &root->data) {
    if(&root-> right ==NULL)
      &root->right = new_node;
    else
      insert(&root->right, new_node);
  }
}

编辑 2 的 SO:我确实有一个包含 build_Tree(**root, elems[], sizeofElem[]) 的头文件,这意味着我需要一个辅助函数插入。是的,通过输入开始*会更容易添加。

编辑 1

#include "bst.h"
#include <stdio.h>
#include <stdlib.h>

//arbitrary list of temp nodes

TreeNode *new_node, *root, *tmp, *parent, *current;
int elemArray[5], i1, i2, i0;

/*
Insert a new node into the tree by referencing the root and using recursion
*/

    TreeNode* getN(int dataElem) {
        TreeNode *newNode = malloc(sizeof(*newNode));
        if (newNode != NULL)
        {
            newNode->data = dataElem;
            newNode->left = NULL;
            newNode->right = NULL;
        }

        return newNode;
    } 

/** This func should just be the root of the tree in the parameter, 
but I like the idea of a pointer becuase it helps to create a tempory 
pointer rather than newNode
**/


TreeNode* addNodeToTree(TreeNode *root, int data) {

    TreeNode *current = *root; //define the current pointer to the root always
    TreeNode *parent = *root
    TreeNode *newNode = getN(data);

    if (*root == NULL)
    {
        printf("First Node");
        *root = newNode;
    }
    else
    {
        while(current != NULL)
        {
            parent = current;
            if (current->data > data)
                current = current->left;
            else if (current->data < data)
                current = current->right;
        }

        if (parent->data > data)
            parent->left = newNode;
        else if (parent->data < data)
            parent->right = newNode;
    }
}



void build_Tree(TreeNode** root, const int elements[], const int count) {

    *root = malloc(sizeof(TreeNode));

    for ( i0 = 0; i0 < count; ++i0 ){
        printf("%d\n", elements[count]);
        addNodeToTree(&root, elements[count]);
    }

}


int main( int argc, char *argv[] ) {

    //Throw error is *Argv[] is not an integer
    //assuming it was an integer
    int cnt = atoi( argv[1] );
    printf( "number is %d\n", cnt );
    //
    printf("Enter %i integer values to place in tree:\n", cnt);
    for ( i1 = 0; i1 < cnt; ++i1) {
        scanf( "%d", &elemArray[i1] );
    }


    //first ouput "INput Values"

    printf( " Input Values:\n " );  

     for ( i2 = 0; i2 < cnt; ++i2) {
               printf( "%d\n", elemArray[i2] );
               printf("building tree0\n");
        }

    printf("building tree\n");
    TreeNode** root = (TreeNode**)malloc(sizeof(TreeNode*));
    TreeNode *root = NULL;
    build_Tree(root, elemArray, cnt );
    printf( "Preorder:\n ");

    //traverse
    //TreeNode* tempN = malloc(sizeof(TreeNode*));
    //tempN->data= 5;

    traverse( *root, PREORDER);             //pass the pointer of root to traverse the tree

    //traverse a single node 
    printf( "Inorder:\n ");

    printf( "Postorder:\n ");


    //Build tree with each element

    return 0;
}

void traverse( const TreeNode* root, const TraversalType type ) {

    if ( type == PREORDER) {
             if (root != NULL)
             {
                printf("%d", root->data);
                traverse( root->left, PREORDER);
                traverse( root-> right, PREORDER);
            }
    }
}




    /**
    void insertNode(TreeNode** root, TreeNode* new_node) {

       if (new_node-> data < *root-> data) {
          if (*root-> left == NULL) 
             *root-> left == new_node;
          else
            insert(*root->left, new_node);
       }

      if (new_node->data > *root->data) {
        if(*root-> right ==NULL)
          *root->right = new_node;
        else
          insert(*root->right, new_node);
      }
    }
    **/


//question1: what is the 

为 main 和 build_tree 编辑 2

void build_Tree(TreeNode** root, const int elements[], const int count) {

    //*root = malloc(sizeof(TreeNode));

    for ( i0 = 0; i0 < count; i0++ ){

        //create the node
        //
        TreeNode *current = *root; //define the current pointer to the root always
        TreeNode *parent = *root;
        //dont create node
        int data = elements[i0];
        TreeNode *newNode = getN(data);

        if (*root == NULL)
        {
            printf("First Node %d\n", elements[i0]); 
            *root = newNode;
        }
        else
        {
            printf("Next Node %d\n", elements[i0]); 
            while(current != NULL)
            {
                parent = current;
                if (current->data > data)
                    current = current->left;
                else if (current->data < data)
                    current = current->right;
            }

            if (parent->data > data)
                parent->left = newNode;
            else if (parent->data < data)
                parent->right = newNode;
        }
        //return root;
    }
}

    TreeNode* getN(int dataElem) {
        TreeNode *newNode = malloc(sizeof(*newNode));
        if (newNode != NULL)
        {
            newNode->data = dataElem;
            newNode->left = NULL;
            newNode->right = NULL;
        }

        return newNode;
    } 

int main( int argc, char *argv[] ) {

    //Throw error is *Argv[] is not an integer
    //assuming it was an integer
    int cnt = atoi( argv[1] );
    printf( "number is %d\n", cnt );
    //
    printf("Enter %i integer values to place in tree:\n", cnt);
    for ( i1 = 0; i1 < cnt; ++i1) {
        scanf( "%d", &elemArray[i1] );
    }


    //first ouput "INput Values"

    printf( " Input Values:\n " );  

     for ( i2 = 0; i2 < cnt; ++i2) {
               printf( "%d\n", elemArray[i2] );
               printf("building tree0\n");
        }

    printf("building tree\n");
    TreeNode* root; //= malloc(sizeof(TreeNode*));
    root = NULL;
    build_Tree(&root, elemArray, cnt );
    printf( "Preorder:\n ");

    //traverse
    //TreeNode* tempN = malloc(sizeof(TreeNode*));
    //tempN->data= 5;

    //traverse( *root, PREORDER);               //pass the pointer of root to traverse the tree

    //traverse a single node 
    printf( "Inorder:\n ");

    printf( "Postorder:\n ");


    //Build tree with each element

    return 0;
}

【问题讨论】:

  • 请尝试使用if (new_node-&gt;data &gt; (*root)-&gt;data) 代替if (new_node-&gt;data &gt; &amp;root-&gt;data)&amp;root 指定了root 的地址,虽然这里因为它是一个指向指针的指针,因此您需要root 中的值,它又是另一个节点的地址。
  • 您也可以使用pointer to a pointer,在这种情况下,您不必从函数中返回任何内容,因为函数内部发生的任何事情实际上都发生在实际变量上,并且不在它的副本上。但是如果一个人只使用一个指针,那么一次必须返回根,以回报所做的更改,返回调用函数:-)
  • 好的,这适用于所有调用 &root 的调用吗?在 insertNode 函数中。
  • 我宁愿不返回任何东西,因为我不知道如何在构建树中实现它,除非我使用递归(或将所做的更改返回到调用函数))指针和递归不要一起编译。
  • build_tree(...) 函数不应该为 root 分配内存,因为这是在内部完成的,addNodeToTree(...) 方法。是否必须通过数组向树中输入值?

标签: c debugging insert binary-search-tree code-hinting


【解决方案1】:

假设您创建了一个函数addNodeToTree(TreeNode *root, int data),将root 节点和data 作为参数传递给它。

现在在这个函数中,简单地创建另一个变量TreeNode *current = root,这将帮助我们基本上遍历树并将节点放置在其各自的位置,以及TreeNode *newNode = NULL(这将成为新节点,即插入)。

现在在继续之前,要实际放置节点,我们将首先检查root 是否不为空,即树是EMPTY。为此,我们将测试:

if (root == NULL)
{
    newNode = malloc(sizeof(*newNode)); // else we can make a function for this 
                                        // thingy too. Creating a function too,
                                        // for you to look at.
    root = newNode;
}

如果树不是EMPTY,即它已经包含一个节点,那么我们将遍历树找到放置新节点的位置。所以else 部分就像:

else
{
    parent = current = root;
    // This loop will actually help us, find the `parent`, 
    // of the `newNode`(which is to be inserted)
    while (current != NULL)
    {
        parent = current;
        if (current->data > data)
            current = current->left;
        else if (current->data < data)
            current = current->right;
    }
    // Now once, we have found, the node, under which the
    // newNode will be placed, now we have to check, whether
    // newNode will become a `left child/right child` of the 
    // parent.
    newNode = getNewNode(data);
    if (parent->data > data)
        parent->left = newNode;
    else if (parent->data < data)
        parent->right = newNode;


    return root;
}

TreeNode * getNewNode(int data)
{
    TreeNode *newNode = malloc(sizeof(*newNode));
    if (newNode != NULL)
    {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }

    return newNode;
}

现在newNode 已插入,您可以简单地以任意顺序遍历查看树。

编辑 1:

这是一个工作示例,看看这是否有意义。否则,请务必提出任何可能出现的问题。

#include <stdio.h>
#include <stdlib.h>

typedef struct TREENODE
{
    int data;
    struct TREENODE *left;
    struct TREENODE *right;
}TreeNode;

void display(TreeNode *node)
{
    printf("*********************************\n");
    printf("Address of Node: %p\n", node);
    printf("Data: %d\n", node->data);
    printf("Left Child: %p\n", node->left);
    printf("Right Child: %p\n", node->right);
    printf("*********************************\n");
}

TreeNode * getNewNode(int data)
{
    TreeNode *newNode = malloc(sizeof(*newNode));
    if (newNode != NULL)
    {
        newNode->data = data;
        newNode->left = NULL;
        newNode->right = NULL;
    }

    return newNode;
}

int getIntData(char *message)
{
    int value = 0;
    char buffer[BUFSIZ] = {'\0'};
    fputs(message, stdout);
    fgets(buffer, sizeof(buffer), stdin);
    sscanf(buffer, "%d", &value);

    return value;
}

TreeNode * addNodeToTree(TreeNode *root, int data)
{
    TreeNode *current = root, *parent = root;
    TreeNode *newNode = getNewNode(data);

    if (root == NULL)
    {
        root = newNode;
    }
    else
    {
        while(current != NULL)
        {
            parent = current;
            if (current->data > data)
                current = current->left;
            else if (current->data < data)
                current = current->right;
        }

        if (parent->data > data)
            parent->left = newNode;
        else if (parent->data < data)
            parent->right = newNode;
    }

    return root;
}

void inOrderTraversal(TreeNode *root)
{
    if (root != NULL)
    {
        inOrderTraversal(root->left);
        display(root);
        inOrderTraversal(root->right);
    }
}

int main(void)
{
    TreeNode *root = NULL;
    int data = 0;
    data = getIntData("Enter Data: ");
    root = addNodeToTree(root, data);
    data = getIntData("Enter Data: ");
    root = addNodeToTree(root, data);
    data = getIntData("Enter Data: ");
    root = addNodeToTree(root, data);
    inOrderTraversal(root);

    return EXIT_SUCCESS;
}

编辑 2:

要使addNodeToTree(...),实现指向指针的指针,只需将函数改成:

void addNodeToTree(TreeNode **root, int data)
{
    TreeNode *current = *root;
    TreeNode *parent = *root;
    TreeNode *newNode = getNewNode(data);

    if (*root == NULL)
    {
        *root = newNode;
    }
    else
    {
        // same as before, just don't return anythingy, from the function.
        // As the function uses pointer to a pointer, hence whatever changes
        // are done, here will be reciprocated in the main function automatically
    }

    // no need to return anythingy
}

来自main 的电话现在看起来像:

int main(void)
{
    TreeNode *root = NULL;
    int data = 0;
    data = getIntData("Enter Data: ");
    addNodeToTree(&root, data);
    // Just see the call to addNodeToTree(...), the rest is same, as before
}

编辑 3:

为了从数组中获取元素而不是将它们直接添加到树中,只需将main 方法更改为这种形式:

int main(void)
{
    TreeNode *root = NULL;
    int element[5] = {19, 11, 5, 28, 25};
    int size = sizeof(element) / sizeof(element[0]);
    int counter = 0;
    for (counter = 0; counter < size; ++counter)
    {
        addNodeToTree(&root, element[counter]);
    }
    inOrderTraversal(root);

    return EXIT_SUCCESS;
}

【讨论】:

  • 那么你的意思是getNewNode是在遍历树之后创建的?如果是这种情况,那么在哪里创建父节点以及再次调用 addNodetoTree() 时 root 会发生什么?一旦我稍微了解了一点,我会在修改我的代码之前选择你的答案。
  • @arrowinfedex:一个简单的获取对 root 的引用,作为函数的参数。现在parent and current 只是指向root 指向的同一个节点。现在我们将current 移动到另一个节点,这取决于newNode 将放置在当前节点的哪一侧(考虑到newNode 的数据是> 还是left/right 之前,我们只需创建 parent = current。简单来说,在这个循环中,我们实际上找到了一个叶子节点(这样父节点就会指向这个叶子节点),
  • @arrowinfedex:我们的newNode将被放置在其下方
  • 是的,完美赚了 0.02 美元。我只是不知道更改 void insert() 以返回一个节点。这将如何帮助 build_tree()。换句话说,我是否想在循环的参数处返回 root: for ( i0 = 0; i0
  • @arrowinfedex:请看一下这个。我希望,现在关于我在 cmets 中写的内容,在以前的 sn-p 中是有道理的。这个工作示例可能会帮助您以更好的方式理解整个事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
  • 2020-03-01
  • 1970-01-01
相关资源
最近更新 更多