0

だから、私はあなたが顧客を作成/変更/検索/リストできるこの顧客アプリケーションをやっています。その後、これは注文などで顧客を製品にリンクすることにも拡大しますが、現在の私の焦点は顧客だけです。二分木を作成しましたが、これらの関数はすべて機能しますが、作成した顧客を別の機会に保存する方法が必要です。

何らかの方法で、(各ノードにある)すべての顧客を配列に転送してから、その配列をファイル「customer.dat」にfwriteする必要があると考えました。それに多くの時間を費やしてきました。これが私が持っている関数と構造体をよりよく理解するのに役立ついくつかのコードスニペットです:

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;

上記は構造体です。ノードにはCstmrタイプのアイテムが含まれ、左右のノードがリンクされています。ツリーには、ルートノードとサイズが含まれています。

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);
    }
} 

これらの関数は、関数を追加して顧客を一覧表示するために使用されます

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

そして最後に書くことによって実行されます

Traverse(tree,printItem); 

配列に追加するために(画面ではなくファイルに出力する)printItemを別の関数に変更しようとしましたが、今では物事が複雑になりすぎています!助言がありますか?

4

5 に答える 5

0

データを配列に格納することが必須でない場合は、代わりに をprintItem使用して、関数をファイルに直接書き込むように調整できます。関数にファイル ハンドルを渡す必要もあります。fprintfprintf

あなたのInOrderトラバーサルも少しバグがあります。すぐ上に戻ると、その行InOrder(root->right, pfun);は実行されません。returnキーワードのみを削除します。トラバーサルが適切に機能していることを確認したらInOrder、ファイルに出力するように適切な変更を加えてみてください (できれば のように関数ポインタを使用しますprintItem)。

実際に配列に書き込みたい場合は、ツリー内のアイテムの総数を知るか、動的コンテナーを使用する必要があります (独自に作成しない限り、C では使用できません)。ただし、必要なことは達成できます。配列なし。

于 2013-01-05T19:09:33.273 に答える
0

すべての助けに感謝します。ツリーから配列への問題の解決策を見つけました。実際、それは非常に簡単です。

まず、Cstmr 型の配列を宣言しました。

Cstmr save[MAXITEMS];

あとは、printItem(Cstmr C) 関数をコピーして少し編集するだけでした。printf の代わりに、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
}

後で、ツリーが空かどうかをチェックして Traverse 関数を使用する別の関数を作成しました。

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

すべての迅速な対応に感謝します!

于 2013-01-06T10:41:29.487 に答える
0

他の人が言ったように、「リターン」は次のコードの実行を無効にします。void 関数で値を返しているため、コンパイラもエラーを排出する必要があります。

次のようなものを使用して、データを (配列なしで) 書き出すだけです。

/* 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);
    }
}

関数 BUFFERED_WRITE は、ファイル記述子へのバッファリングされた書き込みを行う関数の単なるプレースホルダーです。「write(export_fd, cust.Name, strlen(cust.Name) + 1)」のようなものでもかまいません。

インポートはその逆で、境界チェックが追加されます。

于 2013-01-05T19:31:20.027 に答える
0

inorder 関数の途中で戻ってはいけません。トラバーサルの「右側」は実行されません。関数は実際には何も返さないので、余分な「戻り値」を削除するだけで問題ありません。

このような:

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

また、コンパイラで警告を有効にし、実際に表示された警告を修正することをお勧めします。これは、コンパイラが、ここでの戻り値が間違っていることに気付くことができるはずだからです [単に「値を返すべきではないときに値を返している」場合でも] .

于 2013-01-05T19:01:41.800 に答える
0

手始めに、順序通りのトラバーサルを行うためのロジックにバグがあります。ここにコードを転載しました:

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);
    }
} 

returnロジックの途中にステートメントがあることに注意してください。これは、左のサブツリーに降りた後、現在のノードで関数を評価し、右のサブツリーの処理を続行する前に戻ることを意味します。ステートメントを削除すると、returnこれが修正されます。

あなたの問題に対する良い解決策については、ソートされた要素の配列を完全にバランスの取れた二分探索木に変換するための、かなり単純な再帰アルゴリズムがあります。二分探索ツリーの各要素を順番にファイルに書き出すことができる場合、そのツリーを巨大な配列に読み取ってから、その配列から BST を再構築することで、そのツリーを再構築できます。

配列から二分探索木を再構築するためのロジックを擬似コードで示します。

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;
}

お役に立てれば!

于 2013-01-05T19:03:16.697 に答える