構造体の有理数をヒープソート【C言語】
Posted: 2016年12月21日(水) 13:12
/で区切られた有理数を最大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;
}