Converting a Binary Tree into an Array (and later save) in C

白昼怎懂夜的黑 提交于 2019-12-20 04:37:01

问题


So, I'm doing this customer application where you can create/Modify/Search/List Customers. Later on this expands to linking customers to products with an order and so on, but my focus right now is just on customers. I have created a binary tree and all these functions work, however I need a way to store created customers for another time.

I figured that in some way I would have to transfer all the customers (found in each node) into an array, and then fwrite that array into a file "customer.dat". have spent a lot of hours on it. here is some code snippets to help better understand what function and structs I have:

typedef struct customer
{
    char Name[MAXNAME];
    char Surname[MAXNAME];
    char ID[MAXID];
    char Address[MAXADDRESS];
} Cstmr;

typedef struct node
{
    Cstmr item;
    struct node * left;
    struct node * right;
} Node;

typedef struct tree
{
    Node * root;
    int size;
} Tree;

the above are structs, Node contains item of type Cstmr and linked left and right nodes. Tree contains a root node and size.

void Traverse (const Tree * ptree, void (* pfun)(Cstmr item))
{
    if (ptree != NULL)
        InOrder(ptree->root,pfun);
}

static void InOrder(const Node * root, void(* pfun)(Cstmr item))
{
    if (root != NULL)
    {
    InOrder(root->left, pfun);
    (*pfun)(root->item);
    InOrder(root->right, pfun);
    }
} 

these functions where used for listing Customers with the addition of the function

void printItem(Cstmr C)
{ 
    printf("%-10s %-10s %-8s\n", C.Name, C.Surname, C.ID);
}

and finally executed by writing

Traverse(tree,printItem); 

I tried to alter printItem into another function in order to add to an array (outputting to a file instead of the screen), but now things just got way too complicated! any suggestions?


回答1:


If it's not essential that you store your data in an array, you can adapt your printItem function to write directly to a file using fprintf instead of printf. You will need to also pass a file handle to your function.

Your InOrder traversal is also a bit buggy. The line InOrder(root->right, pfun); is never executed as you return immediately above it. Remove only the return keyword. Once you verify your InOrder traversal is properly working, try making the proper modifications to have it print to a file (preferably using a function pointer like you do with printItem).

If you actually do want to write to an array, you'll need to know the total number of items in your tree or use a dynamic container (not available in C, unless you write your own), though you can accomplish what you need without an array.




回答2:


For starters, you have a bug in your logic for doing an in-order traversal. I've reprinted the code here:

static void InOrder(const Node * root, void(* pfun)(Cstmr item))
{
    if (root != NULL)
    {
        InOrder(root->left, pfun);
        return (*pfun)(root->item);
        InOrder(root->right, pfun);
    }
} 

Notice that you have a return statement in the middle of the logic. This means that after you descend into the left subtree, you will evaluate the function at the current node and return before continuing on to process the right subtree. Removing the return statement should fix this.

As for a nice solution to your problem - there is a reasonably straightforward recursive algorithm for converting a sorted array of elements into a perfectly balanced binary search tree. If you are able to write out each element of the binary search tree in-order to a file, you could reconstruct that tree by reading it into a giant array, then rebuilding the BST from that array.

The logic for rebuilding the binary search tree from the array is given here in pseudocode:

Node* arrayToTree(Item array[], int start, int end) {
    if (start >= end) return NULL;

    int mid = (start + end) / 2;
    Node* result  = /* Convert array[mid] to a Node. */
    result->left  = arrayToTree(array, start, mid);
    result->right = arrayToTree(array, mid + 1, end);

    return result;
}

Hope this helps!




回答3:


As the others said the "return" disables execution of the following code. Your compiler should also eject an error because you are returning a value in a void-function.

Just use something like this to write your data out (without an array):

/* sure it may be "static"? */
static void InOrder(const Node * root)
{
    if (root != NULL)
    {
    InOrder(root->left);

    Cstmr cust = root->item;
    BUFFERED_WRITE(cust.Name, strlen(cust.Name) + 1);
    BUFFERED_WRITE(cust.Surname, strlen(cust.Surname) + 1);
    BUFFERED_WRITE(cust.ID, strlen(cust.Surname) + 1);
    BUFFERED_WRITE(cust.Address, strlen(cust.Address) + 1);

    InOrder(root->right, pfun);
    }
}

The function BUFFERED_WRITE is just a placeholder for a function which do buffered writes to a file descriptor. It could be also just something like "write(export_fd, cust.Name, strlen(cust.Name) + 1)".

Importing is vice versa with additional boundary checks.




回答4:


You mustn't return in the middle of your inorder function - it won't execute the "right" side of your traversal. Since your function doesn't actually return anything, it should be no problem to just remove the surplus "return".

Like this:

static void InOrder(const Node * root, void(* pfun)(Cstmr item))
{
    if (root != NULL)
    {
    InOrder(root->left, pfun);
    (*pfun)(root->item);
    InOrder(root->right, pfun);
    }
} 

I would also suggest that you enable warnings in your compiler and actually fix any warnings you get as the compiler should be able to notice that you return here is incorrect [even if it's just "you are returning a value when you shouldn't"].




回答5:


thanks for all the help, I have found the solution for the tree to array problem, and it is quite simple in fact.

First I declared and array of type Cstmr:

Cstmr save[MAXITEMS];

then all I had to do was copy and slightly edit the printItem(Cstmr C) function. Instead of printf, it just adds to save[MAXITEMS].

void saveItem(Cstmr C)
{
    int size = TreeItemCount(&id);
    save[size] = C;
    printf("%s...saved", save[size].Name); //just to check that it works
}

Later I created another function that checks if the tree is empty, then uses the Traverse function:

void SaveCustomers(Tree*pt)
{
    if (TreeIsEmpty(pt))
        puts("Nothing to save!");
    else
        Traverse(pt,saveItem);
}

Thanks for all the quick responses!



来源:https://stackoverflow.com/questions/14175205/converting-a-binary-tree-into-an-array-and-later-save-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!