|
一応再帰版のクイックソートプログラムが出来ました。
内容はバカ正直にリストの先頭セルをピボットとし、それより小さな文字
列idと大きな文字列idを持つ3つのリストに分け、小さな文字列のリストと
大きな文字列のリストにそれぞれ自分自身を適用し、最後に3つをくっつけ
てソート済みリストとしています。
しかし最近はstd::listばかり使っているせいか、append()やpush_front()
で思わぬバグを出していました。std::listならstd::list::sort()が使え
るし、事実上ポインタの付け替えといった煩雑な操作は一切不要です。
特に今回は大きな改良点を残しています。折角BiDirectionalIteratorなの
にend()を使わずbegin()のみを使っているためこのプログラムはForwardI
teratorとしてしか動作していません。もちろんそのため単方向リストにも
適用できるというメリットは残しているわけですが。
取り敢えず完全動作しますのでアップしておきます。C++でstd::listコン
テナを使わずとも双方向リストクラスを作ればもっとスマートに書けます
よ。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define N 20
typedef struct cell {
struct cell *prev;
struct cell *next;
char *id;
} CELL;
CELL *push_front(CELL *x, CELL *y)
{
if (x != NULL) {
x->prev = y;
y->next = x;
}
return y;
}
CELL *append(CELL *x, CELL *y)
{
CELL *p = x;
/* x を全長に渡って走査するので、改良の余地あり。出来ればxのtailを覚えておければ。 */
if (y == NULL) return x;
if (p == NULL) return y;
while (p->next != NULL) p = p->next;
p->next = y;
y->prev = p;
return x;
}
CELL *quicksort(CELL *x)
{
CELL *c, *i, *j, *k, *t;
/* *xが空か既に単一セルなら戻る */
if (x == NULL || x->next == NULL) return x;
else c = x->next;
/* x を単一セルとして切り落とす(先頭のセルをピボットとする) */
x->prev = x->next = NULL;
c->prev = NULL;
k = c;
/* xより小さいidを持つセルをi, 大きいidを持つセルをjに分ける */
i = j = NULL;
while (c != NULL) {
/* c を単一セルとして切り落とす */
if (c->next == NULL)
t = NULL;
else {
t = c->next;
c->next->prev = NULL;
c->next = NULL;
}
if (strcmp(c->id, x->id) < 0) i = push_front(i, c);
else if (strcmp(c->id, x->id)) j = push_front(j, c);
else push_front(x, c);
c = t;
}
/* i, j を更にquicksortする */
i = quicksort(i); j = quicksort(j);
/* i, x, j の順につなげる */
i = append(i, x);
i = append(i, j);
return i;
}
int main(void)
{
CELL cl[N], *p;
int i, j;
char s[11];
srand((unsigned)time(NULL));
/* リストの初期化を楽するため配列を使っている */
for (i = 0; i < N; i++) {
for (j = 0; j < 10; j++) s[j] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[rand() % 36];
s[10] = '\0';
cl[i].id = strdup(s);
if (i == 0) {
cl[i].prev = NULL;
cl[i].next = &cl[i + 1];
cl[i + 1].prev = &cl[i];
} else if (i == N - 1) {
cl[i].prev = &cl[i - 1];
cl[i].next = NULL;
} else {
cl[i].next = &cl[i + 1];
cl[i].prev = &cl[i - 1];
}
}
printf("before quick sort: ");
for (p = &cl[0]; p != NULL; p = p->next)
printf("%s ", p->id);
putchar('\n');
p = quicksort(&cl[0]);
printf("\nafter quick sort: ");
for (; p != NULL; p = p->next)
printf("%s ", p->id);
putchar('\n');
for (i = 0; i < N; i++) free(cl[i].id);
return 0;
}
|