Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
qsort() / bsearch()
任意の型の配列を汎用的にソートおよび検索する関数です。比較ロジックを関数ポインタで渡すことで、構造体など複雑なデータ型にも対応できます。
構文
// 配列を比較関数に基づいてソートします(クイックソートの実装が多いです)。
// base: 配列の先頭アドレス。nmemb: 要素数。size: 1要素のバイト数。
// compar: 比較関数(負・0・正を返します)。
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
// ソート済み配列から key を二分探索します。
// 戻り値: 見つかった要素へのポインタ、見つからなければ NULL。
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
比較関数の戻り値
| 戻り値 | 意味 | 概要 |
|---|---|---|
| 負の値 | a < b | 第1引数が第2引数より小さいと判断します。昇順ソートで前に来ます。 |
| 0 | a == b | 2つの要素は等しいと判断します。 |
| 正の値 | a > b | 第1引数が第2引数より大きいと判断します。昇順ソートで後ろに来ます。 |
サンプルコード
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// int 昇順の比較関数です。
int cmp_int_asc(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
// 構造体を score の降順で比較します。
typedef struct { char name[32]; int score; } Player;
int cmp_score_desc(const void *a, const void *b) {
return ((Player *)b)->score - ((Player *)a)->score;
}
int main(void) {
// int 配列を昇順にソートします。
int nums[] = {5, 2, 8, 1, 9, 3};
int n = sizeof(nums) / sizeof(nums[0]);
qsort(nums, n, sizeof(int), cmp_int_asc);
printf("ソート後: ");
for (int i = 0; i < n; i++) printf("%d ", nums[i]);
printf("\n"); // 『1 2 3 5 8 9』と出力されます。
// bsearch でソート済み配列から値を探します。
int key = 5;
int *found = (int *)bsearch(&key, nums, n, sizeof(int), cmp_int_asc);
if (found) printf("見つかりました: %d\n", *found); // 『見つかりました: 5』。
int key2 = 7;
if (!bsearch(&key2, nums, n, sizeof(int), cmp_int_asc))
printf("7は見つかりませんでした。\n");
// 構造体配列を score 降順でソートします。
Player players[] = {{"Alice", 85}, {"Bob", 92}, {"Carol", 78}};
int np = sizeof(players) / sizeof(players[0]);
qsort(players, np, sizeof(Player), cmp_score_desc);
for (int i = 0; i < np; i++)
printf("%d位: %s (%d点)\n", i + 1, players[i].name, players[i].score);
return 0;
}
概要
比較関数内で単純な引き算(例:『return *(int*)a - *(int*)b』)を使うのは直感的ですが、大きな正の値と大きな負の値の組み合わせでオーバーフローが起きる場合があります。厳密には『if (*a < *b) return -1; if (*a > *b) return 1; return 0;』と書くのが安全です。
『bsearch()』は配列が比較関数に対してソート済みであることが前提です。ソートされていない配列で使うと誤った結果が返ります。あらかじめ『qsort()』でソートしてから使用してください。
要素の比較方法の詳細は『strcmp()』(文字列比較)も参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。