c言語初心者です。二分探索法のソースコードを書いてみたのですがwhile以下でのループに異状があります。二回目まではしっかりとループして指定した数値がどこに配置しているのか教えてくれますが、三回目以降は「見つかりませんでした」の表示しかされません。これはなぜ起こるのでしょうか。解決策を教えてください。ファイルの中身は「1 2 6 43 123」の五つです。
#include <stdio.h>
#include <stdlib.h>
#define MAXDATA 10000
int main(void)
{
int x, a[MAXDATA];
int n, i;
char filename[20];
FILE *fin;
int j, k;
int tmp;
int number=sizeof(filename)/sizeof(int);
int min = 0;
int max = number-1;
int mid;
printf("file name = ");
scanf("%s", filename);
if ((fin=fopen(filename, "r"))==NULL) {
printf("ファイルをオープンできません\n");
return (1);
}
n=0;
while (fscanf(fin, "%d", &a[n])==1) n++;
fclose(fin);
for(i=0; i < n-1; i++){
j=i;
for(k=i+1; k < n; k++){
if (a[j] > a[k]){j=k; }
}
while (scanf("%d", &x)==1) {
while(min <= max ) {
mid = (min + max) / 2;
if (a[mid]==x) {
break;
} else if (a[mid] < x) {
min = mid + 1;
} else if (a[mid] > x){
max = mid - 1;
}
}
if(a[mid]==x){
printf(" x=%d ---> %d\n",x ,mid );
}
else {
printf("見つかりませんでした。\n",x);
}
}
printf("またお会いしましょう\n");
return (0);
}
二分探索について質問です。
Re: 二分探索について質問です。
ソースコードを提示する際は、BBCodeが有効な(無効にしない)状態で、
BBCodeのcodeタグの開始タグと終了タグの組(開始タグが先)で囲んでいただけると、
見やすくてありがたいです。
また、インデントもきちんと整えるといいでしょう。
さらに、提示されているコードはコンパイルが通らなかったので、最後に}を追加したコードでテストしました。
ただし、1を何回か入力 → 2を何回か入力 → 6を入力 とすると、「見つかりませんでした」が出ました。
BBCodeのcodeタグの開始タグと終了タグの組(開始タグが先)で囲んでいただけると、
見やすくてありがたいです。
また、インデントもきちんと整えるといいでしょう。
さらに、提示されているコードはコンパイルが通らなかったので、最後に}を追加したコードでテストしました。
再現できませんでした。1を入力し続けると、何回目でもきちんと見つかるようでした。初心マン さんが書きました:二回目まではしっかりとループして指定した数値がどこに配置しているのか教えてくれますが、三回目以降は「見つかりませんでした」の表示しかされません。
ただし、1を何回か入力 → 2を何回か入力 → 6を入力 とすると、「見つかりませんでした」が出ました。
minおよびmaxをきちんと初期化せずに探索を繰り返しているからだと思います。初心マン さんが書きました:これはなぜ起こるのでしょうか。
scanfで探索する値を読み込んだ後、whileループで探索を開始する前に、minを0、maxをn-1で初期化するといいと思います。初心マン さんが書きました:解決策を教えてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: 二分探索について質問です。
関数があったので (Windows10,VS2017Community,開発者用コマンドプロント,TeraPadを使用)
それを使えばわかりやすいかな。
[c1.c]
[c.bat]
実行結果
それを使えばわかりやすいかな。
[c1.c]
#include <stdio.h>
#include <stdlib.h>
#define KEY_NOT_FOUND 9999
int binary_search(int ary[], int key, int imin, int imax) {
if (imax < imin) {
return KEY_NOT_FOUND;
} else {
int imid = imin + (imax - imin) / 2;
if (ary[imid] > key) {
return binary_search(ary, key, imin, imid - 1);
} else if (ary[imid] < key) {
return binary_search(ary, key, imid + 1, imax);
} else {
return imid;
}
}
}
int main(void){
int ans;
int ary[]={ 1,2,6,43,123, };
int key;
while(1){
scanf("%d", &key);
ans=binary_search(ary, key, 0, 5-1);
if(ans==9999){printf("KEY_NOT_FOUND\n");}
else{printf("result : ary[%d]=%d\n",ans,ary[ans]);}
}
return 0;
}
D:\z17c\c\0718>c
D:\z17c\c\0718>rem コンパイル後リンク
D:\z17c\c\0718>cl /TC c1.c
Microsoft(R) C/C++ Optimizing Compiler Version 19.10.25019 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
c1.c
Microsoft (R) Incremental Linker Version 14.10.25019.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:c1.exe
c1.obj
D:\z17c\c\0718>rem 実行結果
D:\z17c\c\0718>c1.exe
1
result : ary[0]=1
2
result : ary[1]=2
6
result : ary[2]=6
43
result : ary[3]=43
123
result : ary[4]=123
125
KEY_NOT_FOUND
2
result : ary[1]=2
43
result : ary[3]=43
^Cバッチ ジョブを終了しますか (Y/N)?
Re: 二分探索について質問です。
★の部分が抜けているからでしょう。初心マン さんが書きました:これはなぜ起こるのでしょうか。解決策を教えてください。
#include <stdio.h>
#define MAXDATA 10000
int main(void)
{
int x, a[MAXDATA];
int n;
char filename[200];
FILE *fin;
int i, j, k, tmp;
int min, max, mid;
printf("file name = ");
scanf("%s", filename);
if ((fin = fopen(filename, "r")) == NULL) {
printf("ファイルをオープンできません\n");
return 1;
}
n = 0;
while (fscanf(fin, "%d", &a[n]) == 1) n++;
fclose(fin);
for (i = 0; i < n-1; i++) {
j = i;
for (k = i+1; k < n; k++) {
if (a[j] > a[k]) j = k;
}
tmp = a[i], a[i] = a[j], a[j] = tmp; // ★
} // ★
while (scanf("%d", &x) == 1) {
min = 0; // ★
max = n - 1; // ★
while (min <= max) {
mid = (min + max) / 2;
if (a[mid] == x) {
break;
} else if (a[mid] < x) {
min = mid + 1;
} else if (a[mid] > x) {
max = mid - 1;
}
}
if (a[mid] == x) {
printf(" x=%d ---> %d\n", x, mid);
} else {
printf("見つかりませんでした。\n");
}
}
printf("またお会いしましょう\n");
return 0;
}