単連結リストの整列 #88 負数も含めた桁数制限のある整数の整列

これまで3桁の自然数という範囲にリスト要素の値がある場合の基数ソートだったが、
桁数に制限は付くのは同じだが負の場合も含む整数値に拡大した時の整列について。
とりあえず10進数一桁を単位とする基数ソートで行ってみる。

#include <stdio.h>
#include <stdlib.h>
#include "intlist.h"

static int issup(cintelem_t p, cintelem_t q, void *base)
{
    if (base == 0) {
        return intelem_get_val(p) >= 0 && intelem_get_val(q) < 0;
    } else {
        int ip = intelem_get_val(p), iq = intelem_get_val(q);
        ip = ip >= 0 ? ip / (int)base % 10 : (10 - 1) - (-ip) / (int)base % 10;
        iq = iq >= 0 ? iq / (int)base % 10 : (10 - 1) - (-iq) / (int)base % 10;
        return ip > iq;
    }
}

static void print(intlist_t list)
{
    intiter_t i = intlist_iterator(list);
    while (intiter_has_next(i)) {
        cintelem_t e = intiter_next(i);
        printf("%4d ", intelem_get_val(e));
    }
    intiter_dispose(i);
    putchar('\n');
}

int main(void)
{
    int i;
    intlist_t list = intlist_new();
    srand(100);
    for (i = 0; i < 20; i++) intlist_add_first(list, (int)(rand() / (RAND_MAX + 1.0) * 1999) - 999);
    print(list);
    intlist_sort(list, issup, (void *)1);
    print(list);
    intlist_sort(list, issup, (void *)10);
    print(list);
    intlist_sort(list, issup, (void *)100);
    print(list);
    intlist_sort(list, issup, (void *)0);
    print(list);
    return 0;
}

整列は一の位、十の位、百の位と進み、最後に符号のみによる整列を行って終了する。
順位定義関数issupは、baseに0が与えられると、非負数が負数よりも上位であるという定義に基づいた結果を返す。
baseが正数の場合、比較対象が正数の時に10進数でbaseの位のみの大小関係で順位の上下を判断するのは今まで通りだが、
比較対象が負数の時は、対象の一桁を取り出した後に9から引いている。
負数では0 > 1 > 2 > \ldots > 9のような順位になっているとみなせるからである。
そのため、9から対象の一桁を引いて順位を逆転している。
実行すると、

-521  357 -937 -770 -205 -296    8  195  983  454 -656  416 -896  507 -313  495   20 -669 -925 -977
  20 -669 -937 -977 -296  983 -656 -896 -205  454 -925  195  495  416 -313  357  507 -521    8 -770
-296 -896  507    8  416   20 -977 -770 -669 -656  454  357 -937 -925 -521  983 -313 -205  195  495
   8   20 -977 -937 -925 -896  195 -770 -669 -656  357  416  454 -521  495  507 -313 -296 -205  983
-977 -937 -925 -896 -770 -669 -656 -521 -313 -296 -205    8   20  195  357  416  454  495  507  983

最上段のオリジナルリストが最下段のように昇順に整列する。
一の位だけで整列した第二段の最初の方のように、20の0と-669の9とは同順位である。