C言語で以下のプログラムを作りたいです。
大きさが10の整数型の配列を2つ作り、それぞれに1から10の乱数を代入して、共通する数とどちらかにある数をそれぞれ昇順に表示させる。
例えば
配列1:5 8 4 3 7 9 7 9 5 1
配列2:7 6 1 5 9 9 10 8 4 3
共通する数:1 3 4 5 7 8 9
どちらかにある数:1 3 4 5 6 7 8 9 10
自分はまず乱数を発生させて、それぞれの配列で複数回ある数を除き、それから&&や||を使って求めて、昇順に並べようと思いましたが、配列で複数回ある数を除く方法と昇順に並べる方法がわかりませんでした。
なので、その複数回ある数を除く事と昇順に並べる事の方法や考え方など教えてください。
ちなみに、配列で複数回ある数を除くとは
配列1:5 8 4 3 7 9 7 9 5 1では7が2回出てきているので1つにするという事です。
また、別の方法が良ければそれも教えて欲しいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ビット演算を学習しましょう。
C
1#include <stdio.h> 2 3#define N 10 // 配列の要素数 4#define A 1 // 要素の値の範囲 A以上 B以下 5#define B 10 6 7void print(int b) 8{ 9 for (int i = A; i <= B; i++) 10 if (b >> i & 1) printf(" %d", i); 11 putchar('\n'); 12} 13 14int main(void) 15{ 16 int a1[N] = { 5, 8, 4, 3, 7, 9, 7, 9, 5, 1 }; 17 int a2[N] = { 7, 6, 1, 5, 9, 9, 10, 8, 4, 3 }; 18 int b1 = 0, b2 = 0; 19 for (int i = 0; i < N; i++) b1 |= 1 << a1[i], b2 |= 1 << a2[i]; 20 printf("共通する数:"), print(b1 & b2); 21 printf("どちらかにある数:"), print(b1 | b2); 22}
追記
ビット演算を使わないやり方です。
C
1#include <stdio.h> 2 3#define N 10 // 配列の要素数 4#define A 1 // 要素の値の範囲 A以上 B以下 5#define B 10 6 7void print(int b[B+1]) 8{ 9 for (int i = A; i <= B; i++) 10 if (b[i]) printf(" %d", i); 11 putchar('\n'); 12} 13 14int main(void) 15{ 16 int a1[N] = { 5, 8, 4, 3, 7, 9, 7, 9, 5, 1 }; 17 int a2[N] = { 7, 6, 1, 5, 9, 9, 10, 8, 4, 3 }; 18 int b1[B+1] = { 0 }, b2[B+1] = { 0 }, c[B+1] = { 0 }, d[B+1] = { 0 }; 19 for (int i = 0; i < N; i++) b1[a1[i]] = b2[a2[i]] = 1; 20 for (int i = A; i <= B; i++) { 21 c[i] = b1[i] * b2[i]; // 積集合 22 d[i] = b1[i] + b2[i]; // 和集合 23 } 24 printf("共通する数:"), print(c); 25 printf("どちらかにある数:"), print(d); 26}
ビット演算を使わなければ理解できるのでしょうか?
コメントをお願いします。
追記2
ソートした 2つの配列を先頭から見ていって、積集合と和集合を求めるやり方。
C
1#include <stdio.h> 2 3#define N 10 // 配列の要素数 4#define A 1 // 要素の値の範囲 A以上 B以下 5#define B 10 6 7void print(int a[], int n) 8{ 9 for (int i = 0; i < n; i++) 10 printf(" %d", a[i]); 11 putchar('\n'); 12} 13 14void sort(int a[]) 15{ 16 for (int i = 0; i < N-1; i++) 17 for (int j = i+1; j < N; j++) 18 if (a[i] > a[j]) { 19 int t = a[i]; a[i] = a[j]; a[j] = t; 20 } 21} 22 23int intersection(int a1[], int a2[], int b[]) 24{ 25 int i = 0, j = 0, k = 0, t = A-1; 26 while (i < N && j < N) 27 if (a1[i] < a2[j]) 28 i++; 29 else if (a1[i] > a2[j]) 30 j++; 31 else { 32 if (a1[i] != t) b[k++] = t = a1[i]; 33 i++, j++; 34 } 35 return k; 36} 37 38int union_set(int a1[], int a2[], int b[]) 39{ 40 int i = 0, j = 0, k = 0, t = A-1; 41 while (i < N && j < N) 42 if (a1[i] < a2[j]) { 43 if (a1[i] != t) b[k++] = t = a1[i]; 44 i++; 45 } 46 else { 47 if (a2[j] != t) b[k++] = t = a2[j]; 48 j++; 49 } 50 for (; i < N; i++) 51 if (a1[i] != t) b[k++] = t = a1[i]; 52 for (; j < N; j++) 53 if (a2[j] != t) b[k++] = t = a2[j]; 54 return k; 55} 56 57int main(void) 58{ 59 int a1[N] = { 5, 8, 4, 3, 7, 9, 7, 9, 5, 1 }; 60 int a2[N] = { 7, 6, 1, 5, 9, 9, 10, 8, 4, 3 }; 61 printf("配列1:"), print(a1, N); 62 printf("配列2:"), print(a2, N); 63 sort(a1); 64 printf("配列1(昇順):"), print(a1, N); 65 sort(a2); 66 printf("配列2(昇順):"), print(a2, N); 67 int b[B-A+1], n; 68 n = intersection(a1, a2, b); 69 printf("共通する数:"), print(b, n); 70 n = union_set(a1, a2, b); 71 printf("どちらかにある数:"), print(b, n); 72}
実行結果
text
1配列1: 5 8 4 3 7 9 7 9 5 1 2配列2: 7 6 1 5 9 9 10 8 4 3 3配列1(昇順): 1 3 4 5 5 7 7 8 9 9 4配列2(昇順): 1 3 4 5 6 7 8 9 9 10 5共通する数: 1 3 4 5 7 8 9 6どちらかにある数: 1 3 4 5 6 7 8 9 10
投稿2021/01/29 09:51
編集2021/02/05 09:49総合スコア8224
0
ベストアンサー
複数回あるのを除くには、ソートしてから新しい配列を用意して、元の配列の小さい方から順に、数値が大きくなったときだけ、新しい配列に数値を入れていけばいいです。
「2つの配列を1つにまとめる→ソート→重複を除く」で和集合はできます。
積集合は「2つの配列をそれぞれソート→小さい方から比べつつ共通の数値があったら新しい配列に入れる」というような動作になります。添字の進め方に工夫が必要なので考えてみてください。
また、1~10ということがわかっているなら、ビット演算を用いることでもっと楽にできます。
0に対して元の配列から1<<(数値)との論理和を取っていけば、たとえば{1,2,3,5,5,5,8,8,9,9}なら2進数で1100101110になるので、2つの配列をこのようにint型の数値に変換してからビット論理和、論理積をそれぞれとって配列にもどせば終わりです。
追記
回答修正が迷走してしまってすみません。
「重複を消す」の例はこんな感じですね
c
1int main(void) { 2 int ab[20] = {1,1,2,3,3,4,5,6,7,7,7,7,7,8,8,9,9,9,9,10}; // aとbを連結してソートした配列 3 int or[10]; 4 or[0] = ab[0]; 5 for (int i=0,j=0;i<20;i++) { 6 if (ab[i] > or[j]) or[++j] = ab[i]; 7 } 8}
投稿2021/01/29 08:29
編集2021/01/30 11:37総合スコア1332
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/01 10:25
0
それぞれに1から10の乱数を代入
ということで,値の種類が少ないので,
1~10 のそれぞれの値が,{配列1にあるか?,配列2にあるか?}を調べるのが手っ取り早いように思います.
C
1//1~10の値が,{配列1にあるか?,配列2にあるか?}を調べた結果を入れる用. 2//各 CheckFlag[x] はbitフラグの組み合わせとして, 3//配列1にある場合は.0x01 を,配列2にある場合は0x02 をORする形で結果を作るとか,そんな感じで. 4unsigned char CheckFlag[10] = { 0,0,0,0,0, 0,0,0,0,0 };
こんな感じで.
C++
1#define ARRAY1_SIZE 10 2#define ARRAY2_SIZE 10 3 4int main(void) 5{ 6 //配列1と配列2 7 const int Array1[ARRAY1_SIZE] = { 5, 8, 4, 3, 7, 9, 7, 9, 5, 1 }; 8 const int Array2[ARRAY2_SIZE] = { 7, 6, 1, 5, 9, 9, 10, 8, 4, 3 }; 9 10 //調べる処理 11 unsigned char CheckFlag[10] = { 0,0,0,0,0, 0,0,0,0,0 }; 12 for( int i=0; i<ARRAY1_SIZE; ++i ){ CheckFlag[ Array1[i]-1 ] |= 0x01; } 13 for( int i=0; i<ARRAY2_SIZE; ++i ){ CheckFlag[ Array2[i]-1 ] |= 0x02; } 14 15 //結果表示 16 printf( "共通 : " ); 17 for( int i=0; i<10; ++i ) 18 { 19 if( CheckFlag[i]==0x03 ){ printf( "%d ", i+1 ); } 20 } 21 printf( "\n" ); 22 23 printf( "どっちかにある : " ); 24 for( int i=0; i<10; ++i ) 25 { 26 if( CheckFlag[i] ){ printf( "%d ", i+1 ); } 27 } 28 printf( "\n" ); 29 30 return 0; 31}
「bitがどうの」的な話が嫌なら,
配列1の調査結果と配列2の調査結果を別個に持てばいい.
調査結果データの表現方法が異なるだけで,やってることは一緒.
C++
1//調べる処理 2unsigned char CheckResult1[10] = { 0,0,0,0,0, 0,0,0,0,0 }; 3unsigned char CheckResult2[10] = { 0,0,0,0,0, 0,0,0,0,0 }; 4for( int i=0; i<ARRAY1_SIZE; ++i ){ CheckResult1[ Array1[i]-1 ] = 1; } 5for( int i=0; i<ARRAY2_SIZE; ++i ){ CheckResult2[ Array2[i]-1 ] = 1; } 6 7//結果表示 8printf( "共通 : " ); 9for( int i=0; i<10; ++i ) 10{ 11 if( CheckResult1[i] && CheckResult2[i] ){ printf( "%d ", i+1 ); } 12} 13printf( "\n" ); 14 15printf( "どっちかにある : " ); 16for( int i=0; i<10; ++i ) 17{ 18 if( CheckResult1[i] || CheckResult2[i] ){ printf( "%d ", i+1 ); } 19} 20printf( "\n" );
値の種類が少ないことを利用すれば,「重複を除去して昇順に」の話も同じ考えでやれる.
C++
1#define ARRAY_SIZE 10 2 3int main(void) 4{ 5 //元の配列 6 const int SrcArray[ARRAY_SIZE] = { 5, 8, 4, 3, 7, 9, 7, 9, 5, 1 }; 7 //結果配列用 8 int ResultArraySize = 0; 9 int ResultArray[ARRAY_SIZE] = { 0,0,0,0,0, 0,0,0,0,0 }; 10 11 //1~10の各値が元の配列に存在するか調べる 12 unsigned char CheckResult[10] = { 0,0,0,0,0, 0,0,0,0,0 }; 13 for( int i=0; i<ARRAY_SIZE; ++i ){ CheckResult[ SrcArray[i]-1 ] = 1; } 14 //調べた結果から,結果配列を作る 15 for( int i=0; i<10; ++i ) 16 { 17 if( CheckResult[i] ){ ResultArray[ ResultArraySize++ ] = i+1; } 18 } 19 20 //結果表示 21 printf( "重複を取り除いてソートした結果(%d 個になった)\n", ResultArraySize ); 22 for( int i=0; i<ResultArraySize; ++i ){ printf( "%d ", ResultArray[i] ); } 23 printf( "\n" ); 24 25 return 0; 26}
投稿2021/01/29 08:11
編集2021/01/29 08:59総合スコア11996
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/29 08:23
2021/01/29 08:32
2021/01/29 08:40
2021/01/30 09:57
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/30 10:00
2021/02/01 10:23