■この記事の概要
この記事では、C言語でqsort
関数を使用した整数、文字列、構造体配列のソート方法を紹介しています。
具体的なコード例と共に、各ソートの実行結果や比較関数の使い方を説明しています。
■整数配列のソート方法
一番簡単なqsortを使って整数配列をソートする方法です。
第1引数から第4引数までをそれぞれ以下のように準備するとqsortが使えます。
●第1引数 ソート対象の配列
int 配列[] = { 3,1,4,1,5,9,2,6,5,3 };
●第2引数 配列の要素数
size_t 要素数 = sizeof(配列) / sizeof(配列[0]) ;
●第3引数 配列1個のサイズ
●第4引数 比較関数
int 比較関数(const void *p1, const void *p2) {
int n1 = *(const int *)p1;
int n2 = *(const int *)p2;
return n1 - n2;
}
➡うまくソート出来ない時は比較関数を疑う
ソートがうまく出来ない時は以下を読んで下さい。
大抵
return n1 < n2
等としています。
これでは0/1しか返りません。
https://manpages.ubuntu.com/manpages/xenial/ja/man3/qsort.3.html
から引用
「
比較関数は、第一引き数が第二引き数に対して
1) 小さい、
2) 等しい、
3) 大きい
のそれぞれに応じて、
1) ゼロより小さい整数、
2) ゼロ、
3) ゼロより大きい整数の
いずれかを返さなければならない。
」
●qsort使用例-整数配列編
#include <stdio.h>
#include <stdlib.h>
int 比較関数(const void *p1, const void *p2) {
int n1 = *(const int *)p1;
int n2 = *(const int *)p2;
return n1 - n2;
}
int main(void){
int 配列[] = { 3,1,4,1,5,9,2,6,5,3 };
size_t 要素数 = sizeof(配列) / sizeof(配列[0]) ;
for (size_t i = 0 ; i < 要素数 ; i++)
printf("ソート前△:%d\n", 配列[i]);
qsort(配列,要素数,sizeof(配列[0]),比較関数);//整数ソート
for (size_t i = 0 ; i < 要素数 ; i++)
printf("ソート後▼:%d\n", 配列[i]);
}
./a.out
ソート前△:3
ソート前△:1
ソート前△:4
ソート前△:1
ソート前△:5
ソート前△:9
ソート前△:2
ソート前△:6
ソート前△:5
ソート前△:3
ソート後▼:1
ソート後▼:1
ソート後▼:2
ソート後▼:3
ソート後▼:3
ソート後▼:4
ソート後▼:5
ソート後▼:5
ソート後▼:6
ソート後▼:9
n1 – n2の引き算の結果で
数値の大きさ順にソートします。
■文字列ポインタ配列のソート方法
●第1引数:ソート対象の配列
const char *配列[]={
"moshi",
"moshi",
"kame",
"yo",
"kamesan",
"yo",
"sekai",
"no",
"uchini"
};
■第2引数:配列の要素数
size_t 要素数 = sizeof(配列) / sizeof(配列[0]) ;
●第3引数:配列1個のサイズ
●第4引数:比較関数
int 比較関数(
const void *argv1,
const void *argv2)
{
const char *s1 = ((char *const*)argv1)[0];
const char *s2 = ((char *const*)argv2)[0];
return strcmp(s1,s2) ;
}
strcmp()で辞書並び順にソートします。
●qsort使用例–文字列編
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int 比較関数(
const void *argv1,
const void *argv2)
{
const char *s1 = ((char *const*)argv1)[0];
const char *s2 = ((char *const*)argv2)[0];
return strcmp(s1,s2) ;
}
//文字列ソート
int main(void){
const char *配列[]={
"moshi",
"moshi",
"kame",
"yo",
"kamesan",
"yo",
"sekai",
"no",
"uchini"
};
size_t 要素数 = sizeof(配列) / sizeof(配列[0]) ;
for (size_t i=0 ; i < 要素数; i++)
printf("ソート前△:%s\n", 配列[i]);
qsort(配列,要素数,sizeof(配列[0]),比較関数);
for (size_t i=0 ; i < 要素数; i++)
printf("ソート後▼:%s\n", 配列[i]);
}
./a.out
ソート前△:moshi
ソート前△:moshi
ソート前△:kame
ソート前△:yo
ソート前△:kamesan
ソート前△:yo
ソート前△:sekai
ソート前△:no
ソート前△:uchini
ソート後▼:kame
ソート後▼:kamesan
ソート後▼:moshi
ソート後▼:moshi
ソート後▼:no
ソート後▼:sekai
ソート後▼:uchini
ソート後▼:yo
ソート後▼:yo
■構造体配列のソート方法
●第1引数 ソート対象の配列
typedef struct {
char 名前[128];
int 年齢;
char 郵便番号[128];
} 構造体枠_t ;
static 構造体枠_t 配列[]={
{.名前="佐藤",.年齢=98, .郵便番号="111-2345"},
{.名前="鈴木",.年齢=108, .郵便番号="222-3456"},
{.名前="田中",.年齢=88, .郵便番号="333-4567"},
{.名前="加藤",.年齢=78, .郵便番号="111-2345"},
{.名前="伊藤",.年齢=78, .郵便番号="333-4567"},
{.名前="武藤",.年齢=78, .郵便番号="222-3456"},
{.名前="須藤",.年齢=78, .郵便番号="111-2345"},
};
●第2引数 配列の要素数
size_t 要素数 = sizeof(配列) / sizeof(配列[0]) ;
●第3引数 配列1個のサイズ
●第4引数 qsort比較関数(ソートキーが複数の時)
int 比較関数(const void *p1, const void *p2){
//第1ソートキーを年齢とする
int n1 = ((const 構造体枠_t *)p1)->年齢;
int n2 = ((const 構造体枠_t *)p2)->年齢;
if(n1 != n2){
return n1 - n2;
}
//第2ソートキーを郵便番号とする
const char *s1 = ((const 構造体枠_t *)p1)->郵便番号;
const char *s2 = ((const 構造体枠_t *)p2)->郵便番号;
return strcmp(s1,s2);
}
➡ソートキーが複数ある場合の書き方
第1ソートキーを年齢(若い順)
第2ソートキーを郵便番号(辞書並び)
としています。
●qsort使用例–構造体編
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char 名前[128];
int 年齢;
char 郵便番号[128];
} 構造体枠_t ;
static 構造体枠_t 配列[]={
{.名前="佐藤",.年齢=98, .郵便番号="111-2345"},
{.名前="鈴木",.年齢=108, .郵便番号="222-3456"},
{.名前="田中",.年齢=88, .郵便番号="333-4567"},
{.名前="加藤",.年齢=78, .郵便番号="111-2345"},
{.名前="伊藤",.年齢=78, .郵便番号="333-4567"},
{.名前="武藤",.年齢=78, .郵便番号="222-3456"},
{.名前="須藤",.年齢=78, .郵便番号="111-2345"},
};
int 比較関数(const void *p1, const void *p2){
//第1ソートキーを年齢とする
int n1 = ((const 構造体枠_t *)p1)->年齢;
int n2 = ((const 構造体枠_t *)p2)->年齢;
if(n1 != n2){
return n1 - n2;
}
//第2ソートキーを郵便番号とする
const char *s1 = ((const 構造体枠_t *)p1)->郵便番号;
const char *s2 = ((const 構造体枠_t *)p2)->郵便番号;
return strcmp(s1,s2);
}
void DMP(const char *mess,構造体枠_t ary[],size_t max){
for(size_t i = 0;i < max;i++) {
printf("%s:年齢=%-3d 〒=%s 名前=%s\n",
mess,
ary[i].年齢,
ary[i].郵便番号,
ary[i].名前
);
}
}
// 構造体ソート
int main(void){
size_t 要素数 = sizeof(配列) / sizeof(配列[0]) ;
DMP("ソート前△:",配列,要素数);
qsort(配列,要素数,sizeof(配列[0]),比較関数);
DMP("ソート後▼:",配列,要素数);
}
./a.out
ソート前△::年齢=98 〒=111-2345 名前=佐藤
ソート前△::年齢=108 〒=222-3456 名前=鈴木
ソート前△::年齢=88 〒=333-4567 名前=田中
ソート前△::年齢=78 〒=111-2345 名前=加藤
ソート前△::年齢=78 〒=333-4567 名前=伊藤
ソート前△::年齢=78 〒=222-3456 名前=武藤
ソート前△::年齢=78 〒=111-2345 名前=須藤
ソート後▼::年齢=78 〒=111-2345 名前=加藤
ソート後▼::年齢=78 〒=111-2345 名前=須藤
ソート後▼::年齢=78 〒=222-3456 名前=武藤
ソート後▼::年齢=78 〒=333-4567 名前=伊藤
ソート後▼::年齢=88 〒=333-4567 名前=田中
ソート後▼::年齢=98 〒=111-2345 名前=佐藤
ソート後▼::年齢=108 〒=222-3456 名前=鈴木