

集合A:0,2,4,6,8,10,12,14,16,18  
集合B:0,1,2,3,4,5,6,7,8,9  
の二つの集合の和集合を計算する関数を作成したいのですが、その際に扱うmain関数の以下に示す ？ の部分が分かりませんでした。

[code]

    /*size個のデータが入っている配列を　配列の先頭から順に出力する*/
    void printIntArray(int a[],int size)
    {
    int i;
    for(i=0;i≦size;i=i+1) {
    printf("%d",a[i]);
    }
    printf("\n");
    }
    
    /*na個のデータが入っている場合にxと等しい要素があるかどうかを判定する*/
    int memberOf(int x,int a[],int na) 
    {
    int i, resurt=0;
    for(i=0;i≦na;i=i+1) {
    if (x==a[i]){
    result=1;
    }
    }
    return result;
    }
    
    //集合aと集合bの和集合を集合cとして求める
    //na,nbは、集合a,bの要素数
    //返り値は、集合cの要素数
    int unionSet(int a[],int na,int b[],int nb,int c[])
    {
    int i,j;
    j=0;
    for (i=0;i≦na;i=i+1) {
    if (!memberOf(a[i],b,nb)) {
    c[j]=a[i];
    j=j+1;
    }
    }
    for (i=0;i≦nb;i=i+1) {
    c[j]=a[i];
    j=j+1;
    }
    return j;
    }
    
    int main(void)
    {
    int SA[1024]={0,2,4,6,8,10,12,14,16,18};
    int SB[1024]={0,1,2,3,4,5,6,7,8,9};
    /* ？ */
    printf("集合A:\n");
    printIntArray(SA,10);
    printf("集合B:\n");
    printIntArray(SB,10);
    result=？
    printf("集合A∪B:\n");
    printIntArray(？，？）;
    
    return 0;
    }
    
[/code]

回答よろしくお願いします。


CC BY-SA 4.0
2019-10-29T14:00:46.763
60088
2019-10-30T02:32:14.107
2019-10-29T14:07:33.610
19110
36404
question
c
2つの集合の和集合を計算するプログラム


和集合を計算する関数を実装してみたものの、その関数の使い方が分からないという質問だと理解しました。

今回の関数 `unionSet` は次のように定義されています。

[code]

    //集合aと集合bの和集合を集合cとして求める
    //na,nbは、集合a,bの要素数
    //返り値は、集合cの要素数
    int unionSet(int a[],int na,int b[],int nb,int c[])
    
[/code]

`c` は配列であることに注意すると、次のように呼び出すことで関数呼び出しから返ってきたときには変数 `SC` に計算結果が格納されることが分かります。

[code]

    int SC[1024] = {};
    int length = unionSet(SA, 10, SB, 10, SC);
    printIntArray(SC, length);
    
[/code]


CC BY-SA 4.0
2019-10-29T14:21:36.943
60089
2019-10-29T14:21:36.943
19110
60088
answer


自分で作ったものが自分自身で使い方がわからないというのは理解しがたいのですが、数か月後の自分は他人とも言いますし、こういうのは「使い方コメント」を「関数の実装を行う前に」書く習慣をつけると将来にわたって役に立つでしょう。使い方コメントとは結局のところ設計意図と実装仕様書になり、それを実装前に書くことでブレがなくなります。仕様変更の際も先に使い方コメントのほうを更新してから実装に手を付けるようにします。

この手の説明を行うには `JavaDoc` であるとか `Doxygen` とか既知のツールの仕様をもらってくるのが手軽でしょう。下記は `Doxygen`
の `autobrief` な例。

[code]

    /// 和集合を得る.
    /// 配列 a と配列 b の和集合を求めて配列 c に返却する。
    /// @param [in] a : 元集合の１（ソート不要、呼び出し側で領域を用意する）
    /// @param [in] na : a の個数（ a[0] ... a[na-1] の na 個）
    /// @param [in] b : 元集合の２（ソート不要、呼び出し側で領域を用意する）
    /// @param [in] nb : b の個数（ b[0] ... b[nb-1] の nb 個）
    /// @param [out] c : 出力先（呼び出し側で na+nb 個数以上の十分な領域を用意する）
    /// @return 和集合の個数 （ c[0] ... c[retval-1] の retval 個数が有効）
    /// @note c にはソートされない結果が出力される
    /// @note 所要時間は (na+nb) の２乗オーダーとなる 
    /// @warning 出力先が小さいとメモリ破壊を起こす
    size_t unionSet(const int* a, size_t na, const int* b, size_t nb, int* c) { ... }
    
[/code]

これくらい書いてあれば１年後に当該関数を使いたくなった時にコメントだけ見れば十分実装可能です。関数の中まで読んでいると時間を取られてしまいます。

現代的セキュリティとしては、呼ぶ側でバッファサイズが足らないとメモリ破壊を起こす関数は許されないので、引数に１つ `size_t nc`
を付け加えるのが適切です。

和集合は、元ネタがソート済みで良いなら `O(n)` で済むのでそっちのほうが実用的。


CC BY-SA 4.0
2019-10-30T02:32:14.107
60102
2019-10-30T02:32:14.107
8589
60088
answer