このコード内の物事の自由度は豊富です。目立たないものもありますが、最終的にはマージ機能です。典型的なマージ アルゴリズムは、いずれかのリストが使い果たされるまで、反復ごとに1 つの項目をターゲット バッファーに移動します。それが発生すると、残りのリストの残りの項目が所定の場所に一括コピーされ、アルゴリズムが終了します。
あなたには根本的な欠陥があります。ここでそれをカバーします。メイン ループは まで実行k
されますがn
、少なくともそれは正しいです。ただし、if-else-if 条件の最初の式を見てください。
if((i<mid)&&(j>= n))
{
memcpy(temp+(k*size), a+i*size, size);
i++;
}
else if((i<mid)&&(fcmp(a + i*size, a+j*size) <= 0))
{
memcpy(temp+(k*size), a+j*size, size);
j++;
}
どちらもを持っているi<mid
ので、これは次のように簡略化できます。
if (i<mid)
{
if (j>=n)
{
memcpy(temp+(k*size), a+i*size, size);
i++;
}
else if (fcmp(a + i*size, a+j*size) <= 0))
{
memcpy(temp+(k*size), a+j*size, size);
j++;
}
}
つまり、あなたのi
-side があなたの -side の前に使い果たされた場合、その時点から何もせず、に達するまでインクリメントするだけです。分割リストの - 側の残りは完全に無視されます。次に、関数の最後で、初期化されていないデータを元の配列のすぐ上にコピーします。j
k
n
j
考慮すべきいくつかのこと。まず、コンパレータ関数の要件を定義し、それに固執します。コールバック リクエスタの要件に従うのは、コンパレータの責任です。その逆ではありません。
typedef int (*fn_cmp)(const void*, const void*);
その標準へのコールバックを実装することにより、これを正しく使用します。
// compare two nodes.
int compare_node(const void* lhs, const void* rhs)
{
const node* lhn = lhs;
const node* rhn = rhs;
return (strcmp(lhn->name, rhn->name));
}
これにより、一般的なマージソートもよりクリーンになります。
// generic mergesort algorithm
void genmsort(void *src, unsigned int len, unsigned int size, fn_cmp fcmp)
{
if (len < 2)
return;
unsigned int mid = len/2;
genmsort(src, mid, size, fcmp);
genmsort((unsigned char*)src+(mid*size), len - mid, size, fcmp);
merge(src, mid, len-mid, size, fcmp);
}
読みやすさは別として、以下とあなたのものの最大の違いはmerge
、2 番目の長さパラメーターが追加されていることです (これが機能するという事実はボーナスと見なされます)。この値は、最初に渡された単一の長さから推測されたコードです。再帰的なパーティション サイズを計算するときにコード内のまったく別の場所で行ったこと 一貫性や使いやすさを含む複数の理由から、ここでも同じサイズを渡す必要があります)。
以下をご検討ください。このアルゴリズムに注釈を付けたり、より明確にしたりできる場合は、どうすればよいかわかりません。
// merges two lists back to back in a single sequence.
void merge(void *src,
unsigned int alen, // note parition size.
unsigned int blen, // and again here.
unsigned int size,
fn_cmp fcmp)
{
void *bsrc = (unsigned char*)src + alen * size;
void *dst = malloc((alen + blen)*size);
unsigned int a = 0, b = 0, k = 0;
for (k=0; k<(alen+blen); ++k)
{
// still got a's ?
if (a < alen)
{
// still got b's ?
if (b < blen)
{
// get "lesser" of the two.
if (fcmp((const unsigned char*)src + a*size,
(const unsigned char*)bsrc + b*size) <= 0)
{
// a is less. move it in.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)src + a++*size, size);
}
else
{ // b is less. move it in.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)bsrc + b++*size, size);
}
}
else
{ // no more b's. move the rest of the a's
// into the target and leave.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)src + a*size, (alen - a)*size);
k += (alen-a);
}
}
else
{ // else no a's. move the rest of the b's into
// the target and leave.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)bsrc + b*size, (blen - b)*size);
k += (blen-b);
}
}
// copy final output.
memcpy(src, dst, (alen+blen)*size);
free(dst);
}
最後に、このコードは、コードで非常に悪用された標準に違反するインクリメンタルなどのコンパイラ拡張機能を必要としません。void*
このような拡張機能には近づかないことを強くお勧めします。
以下は、上記のアルゴリズムとそのインターフェイスを検証するために使用される完全なテスト プログラムです。よくお読みください。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <time.h>
// simple node definition.
typedef struct node
{
char name[32];
int id;
} node;
// compare two nodes.
int compare_node_names(const void* lhs, const void* rhs)
{
const node* lhn = lhs;
const node* rhn = rhs;
return (strcmp(lhn->name, rhn->name));
}
// compare two nodes.
int compare_node_ids(const void* lhs, const void* rhs)
{
const node* lhn = lhs;
const node* rhn = rhs;
return (lhn->id - rhn->id);
}
// comparator requirements.
typedef int (*fn_cmp)(const void*, const void*);
// merges two lists back to back in a single sequence.
void merge(void *src,
unsigned int alen, // note parition size.
unsigned int blen, // and again here.
unsigned int size,
fn_cmp fcmp)
{
void *bsrc = (unsigned char*)src + alen * size;
void *dst = malloc((alen + blen)*size);
unsigned int a = 0, b = 0, k = 0;
for (k=0; k<(alen+blen); ++k)
{
// still got a's ?
if (a < alen)
{
// still got b's ?
if (b < blen)
{
// get "lesser" of the two.
if (fcmp((const unsigned char*)src + a*size,
(const unsigned char*)bsrc + b*size) <= 0)
{
// a is less. move it in.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)src + a++*size, size);
}
else
{ // b is less. move it in.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)bsrc + b++*size, size);
}
}
else
{ // no more b's. move the rest of the a's
// into the target and leave.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)src + a*size, (alen - a)*size);
k += (alen-a);
}
}
else
{ // else no a's. move the rest of the b's into
// the target and leave.
memcpy((unsigned char *)dst + k*size,
(const unsigned char*)bsrc + b*size, (blen - b)*size);
k += (blen-b);
}
}
// copy final output.
memcpy(src, dst, (alen+blen)*size);
free(dst);
}
// generic mergesort algorithm
void genmsort(void *src, unsigned int len, unsigned int size, fn_cmp fcmp)
{
if (len < 2)
return;
unsigned int mid = len/2;
genmsort(src, mid, size, fcmp);
genmsort((unsigned char*)src+(mid*size), len - mid, size, fcmp);
merge(src, mid, len-mid, size, fcmp);
}
int main()
{
static const unsigned int N = 50;
node *data = malloc(N * sizeof(*data));
int i=0;
srand((unsigned)time(NULL));
for (i=0;i<N;++i)
{
data[i].id = i+1;
sprintf(data[i].name, "String%.3d", 1 + rand() % 999);
}
// sort on names.
genmsort(data, N, sizeof(data[0]), compare_node_names);
for (i=0;i<N;++i)
printf("%s : %u\n", data[i].name, data[i].id);
printf("\n");
// use a different comparator, this time by id.
genmsort(data, N, sizeof(data[0]), compare_node_ids);
for (i=0;i<N;++i)
printf("%s : %u\n", data[i].name, data[i].id);
printf("\n");
free(data);
return 0;
}
出力
String053 : 49
String097 : 38
String104 : 46
String122 : 41
String129 : 8
String139 : 3
String168 : 30
String184 : 22
String222 : 16
String230 : 28
String249 : 4
String265 : 34
String285 : 44
String295 : 20
String298 : 47
String300 : 19
String321 : 2
String375 : 37
String396 : 50
String408 : 13
String430 : 31
String466 : 35
String483 : 24
String484 : 27
String491 : 25
String494 : 39
String507 : 10
String513 : 7
String514 : 11
String539 : 5
String556 : 29
String570 : 43
String583 : 33
String584 : 42
String620 : 15
String632 : 12
String671 : 21
String705 : 23
String710 : 14
String714 : 45
String724 : 18
String733 : 9
String755 : 48
String805 : 36
String814 : 6
String847 : 32
String876 : 40
String893 : 26
String906 : 17
String972 : 1
String972 : 1
String321 : 2
String139 : 3
String249 : 4
String539 : 5
String814 : 6
String513 : 7
String129 : 8
String733 : 9
String507 : 10
String514 : 11
String632 : 12
String408 : 13
String710 : 14
String620 : 15
String222 : 16
String906 : 17
String724 : 18
String300 : 19
String295 : 20
String671 : 21
String184 : 22
String705 : 23
String483 : 24
String491 : 25
String893 : 26
String484 : 27
String230 : 28
String556 : 29
String168 : 30
String430 : 31
String847 : 32
String583 : 33
String265 : 34
String466 : 35
String805 : 36
String375 : 37
String097 : 38
String494 : 39
String876 : 40
String122 : 41
String584 : 42
String570 : 43
String285 : 44
String714 : 45
String104 : 46
String298 : 47
String755 : 48
String053 : 49
String396 : 50