入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
po_po
記事: 38
登録日時: 10年前

入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#1

投稿記事 by po_po » 9年前

氏名,年齢[歳],身長[cm](整数),体重[kg](整数)の4つのデータをメンバにして,構造体keisokuを宣言し,
キーボードから入力された身長の値に一番近い人のデータを出力するというプログラムです。
ファイルから構造体に値を入力します。そのファイルの中身は
25
佐藤 41 189 97
鈴木 22 178 61
高橋 47 178 80
田中 14 180 80
渡辺 33 192 94
伊藤 12 150 51
山本 55 185 98
中村 17 170 88
小林 35 187 77
加藤 49 179 91
吉田 36 182 61
山田 44 184 71
佐々木 15 151 81
山口 50 188 93
松本 17 178 68
井上 13 144 81
斎藤 17 163 55
木村 23 175 105
林 29 161 79
清水 49 185 102
山崎 40 187 99
森 34 189 80
阿部 50 183 81
池田 37 186 97
橋本 15 185 83
です。
実行した結果が、入力した値が最高の身長192を超える値と最低身長144を下回るときは結果が正しいのですが、
その2つの間で例えば178を入力すると
高橋(47)178[cm]
鈴木(22)178[cm]
松本(17)178[cm]
高橋(47)178[cm]
鈴木(22)178[cm]
松本(17)178[cm]
といったように同じものが2回表示され、
162を入力すると
斎藤(17)163[cm]
林(29)161[cm]
斎藤(17)163[cm]
のように表示されてしまいます
どこが間違っているのか教えてください

コード:

#include<stdio.h>
#include<stdlib.h>

typedef struct {
  char name[10];
  int age;
  int stature;
  int weight;
} keisoku;

keisoku a[25];
keisoku ca[25];

int search(int n, keisoku *a, int st){
	int i,head,tail,mid,r;


head = 0;
tail = n - 1;

while(head <= tail){
 mid = (head + tail) / 2;
 if(a[mid].stature == st){
  printf("%s(%d)%d[cm]\n",a[mid].name,a[mid].age,a[mid].stature);
  for(i = 1; a[mid - i].stature == a[mid].stature; i++){
   printf("%s(%d)%d[cm]\n",a[mid - i].name,a[mid - i].age,a[mid - i].stature);
}
for(i = 1; a[mid + i].stature == a[mid].stature; i++){
   printf("%s(%d)%d[cm]\n",a[mid + i].name,a[mid + i].age,a[mid + i].stature);
}
break;
 }
	if(a[mid].stature < st){
		head = mid + 1;
	}else{
		tail = mid - 1;
	
	}
		
}
	if(head > tail){
		r = 0;
	}else{
		r = 1;
	}
	return r;
}

int main(void){
FILE *fp;
char filename[10];
printf("ファイル名を入力して下さい\n");
scanf("%s",filename);
int n;
if(( fp=fopen( filename, "r" ))==NULL ) {
fprintf ( stderr, "File open error\n" ); exit( 1 );
}
fscanf( fp, "%d", &n );
int b;
for(b = 0; b < 25; b++){
	fscanf( fp, "%s%d%d%d",a[b].name,&a[b].age,&a[b].stature,&a[b].weight);
}
	
 fclose(fp);
	
int s[25];
int i;
for(i = 0; i < 25; i++){
	s[i] = a[i].stature;
}

int j, tmp;
for(i = 0; i < 24; i++){//バブルソートで並べかえ
	for(j = 24; j > i; j--){
		if(s[j] < s[j-1]){
		tmp = s[j];
		s[j] = s[j-1];
		s[j-1] = tmp;
		}
	}
}

int rank[25];

for(i = 0 ; i < 25; i++){//構造体のi番目がどの順位にいるかをrank[i]に代入する
	for(j = 0; j < 25; j++){
		if(a[i].stature == s[j]){
			rank[i] = j;
			break;
		}
	}
}

for(i = 0; i < 24; i++){
	for(j = i + 1; j < 24; j++){//順位の重複をなくす
	if(rank[i] == rank[j]){
		rank[j] = rank[i]+1;
	}
}
}
	
int copy[25];
for(i = 0; i < 25; i++){
	copy[i] = rank[i];
}

for(i = 0; i < 25; i++){//配列の添え字と中身の値を入れ替える
	rank[copy[i]] = i;
}
	
for(i = 24; i >= 0; i--){
	ca[i] = a[i];
}
for(i = 0; i < 25; i++){
	a[i] = ca[rank[i]];	
}
	int st;
	printf("身長を入力してください");
scanf("%d",&st);

	i = 1;

	if(search(n, a, st) == 1){
		search(n, a, st);
	}
	else{
		search(n, a, st + i);
		search(n, a, st - i);
	while( search(n, a, st + i) == 0 && search(n, a, st - i) == 0){
			search(n, a, st + i);
			search(n, a, st - i);
		i++;
		}
	}

}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#2

投稿記事 by みけCAT » 9年前

po_po さんが書きました:

コード:

	if(search(n, a, st) == 1){
		search(n, a, st);
	}
	else{
		search(n, a, st + i);
		search(n, a, st - i);
	while( search(n, a, st + i) == 0 && search(n, a, st - i) == 0){
			search(n, a, st + i);
			search(n, a, st - i);
		i++;
		}
	}
まだ詳しく見てはいませんが、とりあえず出力を行う関数を同じパラメータで何度も呼び出すのはおかしい気がします。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

po_po
記事: 38
登録日時: 10年前

Re: 入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#3

投稿記事 by po_po » 9年前

条件文にsearch()関数を使っているのが悪いということでしょうか?

box
記事: 2002
登録日時: 14年前

Re: 入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#4

投稿記事 by box » 9年前

po_po さんが書きました:条件文にsearch()関数を使っているのが悪いということでしょうか?
たぶん。
他にも原因があるかもしれません。

ところで、グチャグチャな字下げを何とかする方がいいような気がします。
読みづらいです。
せめてこれぐらいには書けないものかと…

コード:

#include<stdio.h>
#include<stdlib.h>

typedef struct {
    char name[10];
    int age;
    int stature;
    int weight;
} keisoku;

keisoku a[25];
keisoku ca[25];

int search(int n, keisoku *a, int st){
    int i,head,tail,mid,r;


    head = 0;
    tail = n - 1;

    while(head <= tail){
        mid = (head + tail) / 2;
        if(a[mid].stature == st){
            printf("%s(%d)%d[cm]\n",a[mid].name,a[mid].age,a[mid].stature);
            for(i = 1; a[mid - i].stature == a[mid].stature; i++){
                printf("%s(%d)%d[cm]\n",a[mid - i].name,a[mid - i].age,a[mid - i].stature);
            }
            for(i = 1; a[mid + i].stature == a[mid].stature; i++){
                printf("%s(%d)%d[cm]\n",a[mid + i].name,a[mid + i].age,a[mid + i].stature);
            }
            break;
        }
        if(a[mid].stature < st){
            head = mid + 1;
        }else{
            tail = mid - 1;

        }

    }
    if(head > tail){
        r = 0;
    }else{
        r = 1;
    }
    return r;
}

int main(void){
    FILE *fp;
    char filename[10];
    printf("ファイル名を入力して下さい\n");
    scanf("%s",filename);
    int n;
    if(( fp=fopen( filename, "r" ))==NULL ) {
        fprintf ( stderr, "File open error\n" ); exit( 1 );
    }
    fscanf( fp, "%d", &n );
    int b;
    for(b = 0; b < 25; b++){
        fscanf( fp, "%s%d%d%d",a[b].name,&a[b].age,&a[b].stature,&a[b].weight);
    }

    fclose(fp);

    int s[25];
    int i;
    for(i = 0; i < 25; i++){
        s[i] = a[i].stature;
    }

    int j, tmp;
    for(i = 0; i < 24; i++){//バブルソートで並べかえ
        for(j = 24; j > i; j--){
            if(s[j] < s[j-1]){
                tmp = s[j];
                s[j] = s[j-1];
                s[j-1] = tmp;
            }
        }
    }

    int rank[25];

    for(i = 0 ; i < 25; i++){//構造体のi番目がどの順位にいるかをrank[i]に代入する
        for(j = 0; j < 25; j++){
            if(a[i].stature == s[j]){
                rank[i] = j;
                break;
            }
        }
    }

    for(i = 0; i < 24; i++){
        for(j = i + 1; j < 24; j++){//順位の重複をなくす
            if(rank[i] == rank[j]){
                rank[j] = rank[i]+1;
            }
        }
    }

    int copy[25];
    for(i = 0; i < 25; i++){
        copy[i] = rank[i];
    }

    for(i = 0; i < 25; i++){//配列の添え字と中身の値を入れ替える
        rank[copy[i]] = i;
    }

    for(i = 24; i >= 0; i--){
        ca[i] = a[i];
    }
    for(i = 0; i < 25; i++){
        a[i] = ca[rank[i]];
    }
    int st;
    printf("身長を入力してください");
    scanf("%d",&st);

    i = 1;

    if(search(n, a, st) == 1){
        search(n, a, st);
    }
    else{
        search(n, a, st + i);
        search(n, a, st - i);
        while( search(n, a, st + i) == 0 && search(n, a, st - i) == 0){
            search(n, a, st + i);
            search(n, a, st - i);
            i++;
        }
    }

}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

zack

Re: 入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#5

投稿記事 by zack » 9年前

直接の答えにはなっていませんが、そもそものアルゴリズムを
変更することをお勧めします。

以下は一例です。
分かりやすさ重視で、速度面の最適化はしていません。

コード:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

typedef struct{
  char name[10];
  int age;
  int stature;
  int weight;
}keisoku;

int main(void){

  //a[]の入力部は省略
  keisoku a[5] ={
    {"佐藤",41,189,97},
    {"鈴木",22,178,61},
    {"高橋",47,178,80},
    {"田中",14,180,80},
    {"渡辺",33,192,94}
  };

  //stの入力も省略
  int st = 178;

  //a[].statureの中で最もstと近いものの差を調べる
  int min_difference=1000;//厳密にしたければlimit.hを使う
  for(int i = 0;i<5;++i){
    //差がmin_differenceより小さければ
    //min_differenceを更新
    if(abs(st - a[i].stature) < min_difference){
      min_difference = abs(st - a[i].stature);
    }
  }

  //差がmin_differenceと等しいa[]を表示
  for(int i = 0;i<5;++i){
    if(abs(st - a[i].stature) == min_difference){
      printf("%s(%d)%d[cm]\n",a[i].name,a[i].age,a[i].stature);
    }
  }

  return 0;
}


アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#6

投稿記事 by みけCAT » 9年前

zack さんが書きました:厳密にしたければlimit.hを使う
入力がかならず1個以上あるのであれば、最初の要素の評価値で初期化するといいでしょう。

コード:

  //a[].statureの中で最もstと近いものの差を調べる
  int min_difference=abs(st - a[0].stature);
  for(int i = 1;i<5;++i){
    //差がmin_differenceより小さければ
    //min_differenceを更新
    if(abs(st - a[i].stature) < min_difference){
      min_difference = abs(st - a[i].stature);
    }
  }
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)


po_po
記事: 38
登録日時: 10年前

Re: 入力された値と、構造体のある1つのメンバの値を比べ、それに最も近いものを表示するプログラム

#8

投稿記事 by po_po » 9年前

条件文に出力をする関数を使っていたのがまずかったようなので、出力をする関数と、値を返す関数とを別々にして条件文に値だけを返す関数を使ったところうまくいきました。
みけCATさん、boxさん、Zackさんありがとうございました。

閉鎖

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