構造体の有理数をヒープソート【C言語】

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

構造体の有理数をヒープソート【C言語】

#1

投稿記事 by kajagariconokiwami » 8年前

/で区切られた有理数を最大1000個まで入力し,小さい順に既約分数として出力するプログラミングを書きたいのですが,このままだとコンパイルは可能なのですが,約分はされるのですが,ソートがされずに困っています。

コード:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 1000

//有理数の構造体
struct rational
{
	int num;   //分子
	int denom; //分母
};


//関数プロトタイプ宣言
void reduce_rational(struct rational q[]);
int gcd(int a, int b);
void heapsort1(struct rational q[], int n);
void make_heap(struct rational q[],  int s, int t);
void swap_rational(struct rational q[], int i, int j);
void swap(int a, int b);
int compare_rational(struct rational q[], int i, int j);
int lcm(int a, int b);


//メイン関数
int main()
{
	//使用文字、配列の定義
	int i, n = 0;
	struct rational q[SIZE];
	
	//数値の入力
	while (scanf("%d/%d", &q[n].num, &q[n].denom) !=EOF) n++;
	printf("^D\n");
	
	//qを約分
	for(i = 0; i < n; i++)
	{
		reduce_rational(&q[i]);
	}
	
	//分数型有理数配列q[n]でヒープソートを行う
	heapsort1(&*q, n-1);
	
	//出力結果
	for (i = 0; i < n; i++)
	{
		printf("%d/%d\n", q[i].num, q[i].denom);
	}
	
	return 0;
}


//自作reduce_rational関数(分数型有理数を約分をする関数)の定義
void reduce_rational(struct rational q[])
{
	int d = gcd(abs(q->num), abs(q->denom));
	q->num /= d;
	q->denom /= d;
}


//自作gcd関数(最大公約数を返す関数)の定義
int gcd(int a, int b)
{
	for (;;)
	{
		int r = a % b;
		if (r == 0) break;
		a = b;
		b = r;
	}
	return b; 
}


//自作heapsort関数(ヒープソートを行う関数)の定義
void heapsort1 (struct rational q[], int n)
{
	//末尾の要素の添字nをs、その親の添字をtとする
	int s = n, t = n / 2;                 
	
	//二分ヒープを構成
	while (t > 0)
	{
		make_heap (&*q, s, t);
		t--;
	}
	
	while(s > 0)
	{
		//二分ヒープの根と一番最後の要素を交換
		swap_rational (&*q, 1, s);
		//一番最後の要素を二分木から出す
		s--;
		//二分ヒープを再構成
		make_heap (&*q, s, 1);
	}
}


//自作make_heap関数(二分ヒープを構成する関数)の定義
void make_heap(struct rational q[],  int s, int t)
{
	int i = t * 2;
	while (i <= s)
	{
		//すでにq[i] < q[i + 1]ならば次の節点へ
		if (i < s && compare_rational(&*q, i, i + 1) == -1) i++;
		
		//そうでないときq[t]とその子のq[i]とを比べて、もし子の方が大きいならば入れ替える
		if (compare_rational(&*q, i, i + 1) >= 0) break;
		swap_rational (&*q, t, i);
		//更新して次の親子で調べる
		t = i;
		i = t * 2;
    }
}


//自作swap_rational関数(配列の要素を交換する関数)の定義
void swap_rational(struct rational q[], int i, int j)
{
	swap (q[i].num, q[j].num);
	swap (q[i].denom, q[j].denom);
}


//自作swap関数(数値を交換する関数)の定義
void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}


//自作compare_rational関数(有理数の大小関係を比較する関数)の定義
int compare_rational(struct rational q[], int i, int j)
{
	int k, c1, c2, s, t;
	
	k = lcm(q[i].denom, q[j].denom);
	c1 = k / q[j].denom;
	c2 = k / q[i].denom;
	s = c2 * q[i].num;
	t = c1 * q[j].num;
	
	if(s - t < 0) return -1;
	if(s - t == 0) return 0;
	if(s - t > 0) return 1;
}


//自作lcm関数(最小公倍数を返す関数)の定義
int lcm(int a, int b)
{
	int x, r, tmp;
	x = a * b;
	
	//自然数 a > b を確認・入替
	if (a < b)
	{
		tmp = a;
		a = b;
		b = tmp;
	}
	//ユークリッドの互除法
	r = a % b;
	while(r != 0)
	{
		a = b;
		b = r;
		r = a % b;
	}
	return x / b;
}

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

Re: 構造体の有理数をヒープソート【C言語】

#2

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

kajagariconokiwami さんが書きました:

コード:

//自作swap関数(数値を交換する関数)の定義
void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
}
仮引数を書き換えても呼び出し元の実引数には影響を与えないので、この関数は実質何もしていないのと同じです。
よくある間違いですね。
呼び出す関数内で呼び出し元のデータを書き換えてもらいたい場合は、関数に書き換えてもらいたいデータのポインタを渡さなければいけません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kajagariconokiwami

Re: 構造体の有理数をヒープソート【C言語】

#3

投稿記事 by kajagariconokiwami » 8年前

コード:

//自作swap_rational関数(配列の要素を交換する関数)の定義
void swap_rational(struct rational q[], int i, int j)
{
	swap (&q[i].num, &q[j].num);
	swap (&q[i].denom, &q[j].denom);
}


//自作swap関数(数値を交換する関数)の定義
void swap(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
[\code]

この部分だけこのように書き換えてコンパイルし実行してみたのですが,
ソートが正しくソートされずに無茶苦茶にソートされてしまいました。
配列の要素番号などの違いで起きていると考えたのですが上手く処理できませんでした。
どこがどう違っているのか、どなたかわかる方、みえませんか?

kajagariconokiwami

Re: 構造体の有理数をヒープソート【C言語】

#4

投稿記事 by kajagariconokiwami » 8年前

自己解決できしました、ありがとうございました。

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

Re: 構造体の有理数をヒープソート【C言語】

#5

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

フォーラムルールより転載
4. 義務行為

[C言語何でも質問掲示板でのみ適用される事項]

・トピックを立て、解決した場合は「解決しました」とだけ書かず、どうやって解決したか他の人に分かるように書いてからトピックを終了して下さい。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kajagariconokiwami

Re: 構造体の有理数をヒープソート【C言語】

#6

投稿記事 by kajagariconokiwami » 8年前

すみません。
利用が初めてでしたのでマナーとルールを守れていませんでした。

自己解決した点はmake_heapの中の2つ目のcompare_rationalの添え字をケアレスミスしていたので、そこを修正しコンパイルすることで、うまく実行できました。

閉鎖

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