二つの配列の合併について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
しょう

二つの配列の合併について

#1

投稿記事 by しょう » 17年前

問題は

2つの集合配列set0[/url],set1[/url]を入力とし、共通および合併の集合演算を施施した結果でset0[/url]を更新する関数を作成する。
入出力も整備したプログラムをC言語で作成せよ。

というものなんです。共通のほうはできたのですが、合併のほうがひとつしか要素が追加されません。

合併というのはもしset0[1,3,5]、set1[2,3,6]であったときset0[1,3,5,2,6]を出力するものとします。


下のプログラムを作成しましたがどこか間違っていますか?教えてください!!

//====================================================================
// ヘッダ情報
//====================================================================

#include <stdio.h>

//====================================================================
// 定数定義マクロ
//====================================================================

#define LEN 100 // 配列最大長
#define EOA -99999999 // 配列終端の番兵(End of Array)

#define TRUE 1 // 真値
#define FALSE 0 // 偽値

//====================================================================
// データ型定義
//====================================================================

typedef int Data; // 文字列
typedef int Bool; // 真偽値

//====================================================================
// 関数宣言
//====================================================================

void set_input(Data set[/url], int num);
void set_output(const Data set[/url]);
void set_normal(Data set[/url]);
Bool set_elem(const Data set[/url], Data elem);
//---- 共通演算
void set_common(Data set0[/url], const Data set1[/url]);

//---- 合併演算
void set_union(Data set0[/url], const Data set1[/url]);

//====================================================================
// メイン関数
//====================================================================

int main(void) {
//---- 宣言
Data set1[LEN], set0[LEN];
int n1, n0;
int s;

//---- 集合set0の要素数と各要素の入力
printf("n0 = ? "); scanf("%d", &n0);
set_input(set0, n0);
set_normal(set0);

//---- 集合set1の要素数と各要素の入力
printf("n1 = ? "); scanf("%d", &n1);
set_input(set1, n1);
set_normal(set1);

//---- 集合演算と出力

printf("1:共通 2:合併\n");
scanf("%d", &s);

switch( s ){
case 1: set_common(set0, set1); // 共通演算
printf("共通 = "); set_output(set0);
break;
case 2: set_union(set0, set1); // 合併演算
printf("合併 = "); set_output(set0);
break;
default: puts("入力エラー"); break;
}

return 0;
}


//====================================================================
// 集合データの入出力
//====================================================================

//--------------------------------------------------------------------
// 配列への入力
//--------------------------------------------------------------------

void set_input(Data set[/url], int num) {
int k;
for ( k = 0; k < num; k++ ) { scanf("%d", &set[k]); }
set[num] = EOA;
}

//--------------------------------------------------------------------
// 配列からの出力
//--------------------------------------------------------------------

void set_output(const Data set[/url]) {
int k;
for ( k = 0; set[k] != EOA; k++ ) { printf("%d ", set[k]); }
puts("");
}



//--------------------------------------------------------------------
// 共通演算
//--------------------------------------------------------------------

void set_common(Data set0[/url], const Data set1[/url]) {
int k1, k0 = 0;
for ( k1 = 0; set1[k1] != EOA; k1++ ) {
if ( set_elem(set0, set1[k1]) ) { set0[k0++] = set1[k1]; }
}
set0[k0] = EOA;
}

//--------------------------------------------------------------------
// 合併演算
//--------------------------------------------------------------------

void set_union(Data set0[/url], const Data set1[/url] ) {
int k1, k2;
int k0 = 0;
for ( k1 = 0; set0[k1] != EOA; k1++ ) { k0++; }
//---- s1の要素を走査し、s0に属さない要素のみを新たに追加する
for ( k1 = 0; set1[k1] != EOA; k1++ ) {
if ( ! set_elem(set0, set1[k1]) ) { set0[k0++] = set1[k1]; }
}
set0[k0] = EOA;
}

//--------------------------------------------------------------------
// 集合の正規化
//--------------------------------------------------------------------

void set_normal(Data set[/url]) {
int k1, k2, k0 = 0;
Bool check;
// sの要素に対し、正規化した部分と照合し、重複していない要素のみを追加
for ( k1 = 0; set[k1] != EOA; k1++ ) {
check = TRUE;
for ( k2 = 0; k2 < k0; k2++ ) {
if ( set[k1] == set[k2] ) { check = FALSE; break; }
}
if ( check == TRUE ) { set[k0++] = set[k1]; }
}
set[k0] = EOA;
}

//--------------------------------------------------------------------
// 所属性
//--------------------------------------------------------------------

Bool set_elem(const Data set[/url], Data elem) {
int k;
for ( k = 0; set[k] != EOA; k++ ) {
if ( set[k] == elem ) { return TRUE; }
}
return FALSE;
}

box

Re:二つの配列の合併について

#2

投稿記事 by box » 17年前

適宜printfを入れるなどして、配列の内容がどうなっているかを
確認すれば、わかると思います。

set_union関数の

>		if (!set_elem(set0, set1[k1])) {
>			set0[k0++] = set1[k1];
>		}

ここで、set0[/url]のEOAを上書きしている点に問題がありそうです。

組木紙織

Re:二つの配列の合併について

#3

投稿記事 by 組木紙織 » 17年前

以前も同じような質問がありました。

ttp://www.play21.jp/board/formz.cgi?action=res&resno=13993&page=&lognum=45&id=dixq&rln=14310

しょう

Re:二つの配列の合併について

#4

投稿記事 by しょう » 17年前

boxさん

set0[k0]=EOAを消してみましたが、ごちゃごちゃしたものが出てきて変になってしまいます…
そこじゃなくて
> if (!set_elem(set0, set1[k1])) {
> set0[k0++] = set1[k1];
> }
をどーにかしないといけないんですか?


組木紙織さん

そのページを見ましたが、解決策が載っていなかったので……

box

Re:二つの配列の合併について

#5

投稿記事 by box » 17年前

>set0[k0]=EOAを消してみました

配列set0[/url]に終わりの印を付けることは必要です。
付けるタイミングが正しくないのではないか、ということです。

しょう

Re:二つの配列の合併について

#6

投稿記事 by しょう » 17年前

なるほど!!
できました!!
ありがとうございます♪

組木紙織

Re:二つの配列の合併について

#7

投稿記事 by 組木紙織 » 17年前

boxさんのに一言付け加えるとすると、
set0[/url]はどのような変化をしているのか?
というところです。


私が過去ログを提示した理由は今問題にしている部分が解決できたとしても、
set0[1,3,5]、set1[2,3,6]であったときに合併演算をすると、set0[1,3,5,2,6]
と出力されるようになっており、正規化していない部分が問題かなと思ったので
過去ログにあげたソースを利用すると、出力されるのがset0[1,2,3,5,6]
となり正規化した結果で、出て来るので後が使いやすいと思ったからです。

仕様に正規化してない結果を返すようにしているようなので余計な御世話だったようです。
混乱させてしまったようですみません。

しょ

Re:二つの配列の合併について

#8

投稿記事 by しょ » 17年前

組木紙織さん

いや、そこまで深く考えてませんでしたので、わざわざありがとうございます!

閉鎖

“C言語何でも質問掲示板” へ戻る