如何按字母顺序对字符串数组进行排序(区分大小写,非标准排序规则)

时间:2012-09-28 20:09:43

标签: c sorting case-sensitive alphabetical

我需要一个c语言代码来排序一些字符串,它应该区分大小写,对于大写和小写的相同字母,小写必须首先。例如,以下字符串的排序结果:

eggs
bacon
cheese
Milk
spinach
potatoes
milk
spaghetti

应该是:

bacon
cheese
eggs
milk
Milk
potatoes
spaghetti
spinach

我写了一段代码,但我得到的结果是:

Milk
bacon
cheese
eggs
milk
potatoes
spaghetti
spinach

我不知道如何改进这一点,我搜索了很多。有人可以帮我这个吗?

#include <stdio.h>
#include <string.h>

int main(){
    char c;
    char name[20][10], temp[10];
    int count_name = 0;
    int name_index = 0;
    int i, j;

    while ((c = getchar()) != EOF){
        if (c == 10){
            name[count_name][name_index] = '\0';
            count_name++;
            name_index = 0;
        } else {
            name[count_name][name_index] = c;
            name_index++;
        }
    }

    for(i=0; i < count_name-1 ; i++){
        for(j=i+1; j< count_name; j++)
        {
            if(strcmp(name[i],name[j]) > 0)
            {
                strcpy(temp,name[i]);
                strcpy(name[i],name[j]);
                strcpy(name[j],temp);
            }
        }
    }

    for (i = 0; i < count_name; i++){
        printf("%s\n", name[i]);
    }
}

6 个答案:

答案 0 :(得分:21)

保持相同的词语......

对于单词列表,将“相同”单词组合在一起通常更有用(即使它们在大小写上有所不同)。例如:

Keeping things together:          Simple "M after m":
------------------------          -------------------
mars                              mars
mars bar                          mars bar
Mars bar                          milk
milk                              milk-duds
Milk                              milky-way
milk-duds                         Mars bar
milky-way                         Milk
Milky-way                         Milky-way

如果你想要像第一栏那样排列的话,我提出了三种方法:

  • strcasecmp()strcmp()结合使用。
  • 使用isalpha()tolower()isupper()跟踪字符类型的单一传递实现。
  • 使用整理表的单一传递实现。

最后,我讨论了两种选择:

  • 使用整理表建立任意顺序。
  • 将区域设置设置为使用基于区域设置的整理。

使用可用的库函数

如果可以这样做,请避免重新发明轮子。在这种情况下,我们可以使用POSIX函数strcasecmp()来查看它们是否与不区分大小写的比较相等,并在它们出现时返回strcmp()

int alphaBetize (const char *a, const char *b) {
    int r = strcasecmp(a, b);
    if (r) return r;
    /* if equal ignoring case, use opposite of strcmp() result to get
     * lower before upper */
    return -strcmp(a, b); /* aka: return strcmp(b, a); */
}

(在某些系统上,不区分大小写的比较函数称为stricmp()_stricmp()。如果您无法使用,则下面提供了一个实现。)

#ifdef I_DONT_HAVE_STRCASECMP
int strcasecmp (const char *a, const char *b) {
    while (*a && *b) {
        if (tolower(*a) != tolower(*b)) {
            break;
        }
        ++a;
        ++b;
    }
    return tolower(*a) - tolower(*b);
}
#endif

避免在字符串上进行两次传递

有时候,现有功能的表现不够好,你必须做些其他事情才能让事情变得更快。以下函数在单次传递中以大致相同的方式进行比较,并且不使用strcasecmp()strcmp()。但是,它将所有非字母字符视为小于字母。

int alphaBetize (const char *a, const char *b) {
    int weight = 0;
    do {
        if (*a != *b) {
            if (!(isalpha(*a) && isalpha(*b))) {
                if (isalpha(*a) || isalpha(*b)) {
                    return isalpha(*a) - isalpha(*b);
                }
                return *a - *b;
            }
            if (tolower(*a) != tolower(*b)) {
                return tolower(*a) - tolower(*b);
            }
            /* treat as equal, but mark the weight if not set */
            if (weight == 0) {
                weight = isupper(*a) - isupper(*b);
            }
        }
        ++a;
        ++b;
    } while (*a && *b);
    /* if the words compared equal, use the weight as tie breaker */
    if (*a == *b) {
        return weight;
    }
    return !*b - !*a;
}

使用此比较进行排序会使milkMilk彼此相邻,即使该列表包含milk-duds

使用整理表

这是一种从“配置”动态创建整理表的方法。它用于说明一种改变字符串比较方式的对比技术。

您可以将字母表中的字母与一种简单表格进行比较,该表格描述了您希望字母(或除NUL字节之外的任何字符)的相对顺序:

const char * alphaBetical =
    "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";

从这个排序中,我们可以创建一个查找表来查看两个字母应该如何相互比较。如果表尚未完成,则以下函数初始化表,否则执行表查找。

int alphaBeta_lookup (int c) {
    static int initialized;
    static char table[CHAR_MAX+1];
    if (!initialized) {
        /* leave all non-alphaBeticals in their relative order, but below
           alphaBeticals */
        int i, j;
        for (i = j = 1; i < CHAR_MAX+1; ++i) {
            if (strchr(alphaBetical, i)) continue;
            table[i] = j++;
        }
        /* now run through the alphaBeticals */
        for (i = 0; alphaBetical[i]; ++i) {
            table[(int)alphaBetical[i]] = j++;
        }
        initialized = 1;
    }
    /* return the computed ordinal of the provided character */
    if (c < 0 || c > CHAR_MAX) return c;
    return table[c];
}

使用这个查找表,我们现在可以简化alphaBetize()比较函数的循环体:

int alphaBetize (const char *a, const char *b) {
    int ax = alphaBeta_lookup(*a);
    int bx = alphaBeta_lookup(*b);
    int weight = 0;
    do {
        char al = tolower(*a);
        char bl = tolower(*b);
        if (ax != bx) {
            if (al != bl) {
                return alphaBeta_lookup(al) - alphaBeta_lookup(bl);
            }
            if (weight == 0) {
                weight = ax - bx;
            }
        }
        ax = alphaBeta_lookup(*++a);
        bx = alphaBeta_lookup(*++b);
    } while (ax && bx);
    /* if the words compared equal, use the weight as tie breaker */
    return (ax != bx) ? !bx - !ax : weight;
}

我们可以让事情更简单吗?

使用整理表,您可以使用简化的比较功能创建许多不同的顺序,例如:

int simple_collating (const char *a, const char *b) {
    while (alphaBeta_lookup(*a) == alphaBeta_lookup(*b)) {
        if (*a == '\0') break;
        ++a, ++b;
    }
    return alphaBeta_lookup(*a) - alphaBeta_lookup(*b);
}

使用同样的功能并通过修改alphaBetical字符串,您几乎可以实现任何所需的顺序(按字母顺序,反向字母顺序,辅音之前的元音等)。然而,将类似单词保持在一起的安排需要在大写单词中散布大写单词,这只能通过进行忽略大小写的比较来完成。

请注意,使用上面的simple_collating()函数和我提供的alphaBetical字符串,Bacon将在milk之前,但Mars将在milk之后1}}和Milk之前。

如果要根据您的区域设置进行排序。

如果要使用已为区域设置定义的整理顺序,可以设置区域设置并调用整理比较功能:

/*
 * To change the collating locale, use (for example):
       setlocale(LC_COLLATE, "en.US");
 */
int iso_collating (const char *a, const char *b) {
    return strcoll(a, b);
}

现在,通过更改区域设置,排序顺序将基于标准化的整理顺序。

答案 1 :(得分:10)

您可以编写自定义比较函数进行排序。

首先,查看默认的strcmp排序顺序:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

const char *tgt[]={
    "bacon", "Bacon", "mIlk", "Milk", "spinach", "MILK", "milk", "eggs"
};
int tgt_size=8;

static int cmp(const void *p1, const void *p2){
    return strcmp(* (char * const *) p1, * (char * const *) p2);
}

int main(int argc, char *argv[]) {
    printf("Before sort:\n\t");
    for(int n=0; n<tgt_size; n++)
        printf("%s ", tgt[n]);

    qsort(tgt, tgt_size, sizeof(char *), cmp);

    printf("\nAfter sort:\n\t");
    for(int n=0; n<tgt_size; n++)
        printf("%s ", tgt[n]);

    return 0;
}

strcmp按ASCII字符代码排序;即它排序A-Z然后排序a-z所以所有大写字母A-Z出现在任何带小写字母的单词之前:

Before sort:
    bacon Bacon mIlk Milk spinach MILK milk eggs 
After sort:
    Bacon MILK Milk bacon eggs mIlk milk spinach 

我们可以编写cmp中使用的qsort中使用的忽略大小写的自己的比较函数。看起来像这样:

int mycmp(const char *a, const char *b) {
    const char *cp1 = a, *cp2 = b;

    for (; toupper(*cp1) == toupper(*cp2); cp1++, cp2++)
        if (*cp1 == '\0')
            return 0;
    return ((toupper(*cp1) < toupper(*cp2)) ? -1 : +1);
} 

请务必将cmp更改为:

static int cmp(const void *p1, const void *p2){
    return mycmp(* (char * const *) p1, * (char * const *) p2);
}

案例忽略版本现在打印:

Before sort:
    bacon Bacon mIlk Milk spinach MILK milk eggs 
After sort:
    bacon Bacon eggs Milk MILK milk mIlk spinach 

这与POSIX函数strcasecmp的输出相同。

函数mycmp首先按正常顺序[a|A]-[z|Z]按字典顺序进行比较。这意味着你会得到一些字母单词,但你可能会bacon, Bacon Bacon, baconint mycmp(const char *a, const char *b) { const char *cp1 = a, *cp2 = b; int sccmp=1; for (; toupper(*cp1) == toupper(*cp2); cp1++, cp2++) if (*cp1 == '\0') sccmp = 0; if (sccmp) return ((toupper(*cp1) < toupper(*cp2)) ? -1 : +1); for (; *a == *b; a++, b++) if (*a == '\0') return 0; return ((*a < *b) ? +1 : -1); } 。这是因为qsort不是stable sort和&#39;培根&#39;比较等于&#39;培根&#39;。

现在我们想要的是如果比较为0而忽略大小写(即同样的单词,如&#39; MILK&#39;和牛奶)现在比较包括大小写并反转顺序:

Before sort:
    bacon Bacon mIlk Milk spinach MILK milk eggs 
After sort:
    bacon Bacon eggs milk mIlk Milk MILK spinach 

最终版本打印:

Swedish                      z < ö
                             y == w
German                       ö < z
Danish                       Z < Å
Lithuanian                   i < y < k
Tr German                    ä == æ
Tr Spanish                   c < ch < d   
German Dictionary Sort:      of < öf
German Phonebook Sort:       öf < of

不幸的是,这种方法对UNICODE来说变得难以处理。对于复杂排序,请考虑使用带有stable sort的映射或多步排序。

对于复杂和位置感知的字母排序规则,请考虑Unicode collations。例如,在不同的位置,字母按字母顺序不同:

Level   Description           Examples
L1      Base characters       role < roles < rule
L2      Accents               role < rôle < roles
L3      Case/Variants         role < Role < rôle
L4      Punctuation           role < “role” < Role
Ln      Identical             role < ro□le < “role”

默认Unicode排序规则元素表(DUCET)中捕获了这些区别的默认值,该表提供了UNICODE排序规则和字符串比较的默认映射。您可以修改默认值以捕获字典排序和电话簿排序,不同位置或案例的不同处理之间的区别。在Unicode公共区域设置数据存储库(CLDR)中主动跟踪各个位置变体。

多级排序的推荐是分层的:

b < B < bad < Bad < bäd
c < C < cote < coté < côte < côté 

广泛使用的Unicode排序规则实现在ICU Library中。几个示例的默认DUCET排序规则是:

{{1}}

您可以浏览ICU库并使用ICU Explorer

更改位置和目标

如果您想为咯咯笑声实现自己的DUCET版本,可以按照此Python script中使用的常规方法进行操作。它不是压倒性的,但不是无足轻重的。

答案 2 :(得分:3)

OP代码的关键是使用函数strcmp()来比较两个字符串 因此,我将从另一个替换此标准函数开始,如下所示:

  // We assume that the collating sequence satisfies the following rules:
  // 'A' < 'B' < 'C' < ...
  // 'a' < 'b' < 'c' < ...
  // We don't make any other assumptions.

  #include <ctype.h>      
  int my_strcmp(const char * s1, const char * s2)
  {
      const char *p1 = s1, *p2 = s2;
      while(*p1 == *p2 && *p1 != '\0' && *p2 != '\0')
          p1++, p2++;  /* keep searching... */

      if (*p1 == *p2)
         return 0;
      if (*p1 == '\0')
         return -1;
      if (*p2 == '\0')
         return +1;

      char c1 = tolower(*p1),      c2 = tolower(*p2);
      int  u1 = isupper(*p1) != 0, u2 = isupper(*p2) != 0;
      if (c1 != c2)
        return c1 - c2;  // <<--- Alphabetical order assumption is used here 
      if (c1 == c2)
        return u1 - u2;
  }

最后一行可以用这种方式压缩:

     return (c1 != c2)? c1 - c2: u1 - u2;

现在,将strcmp()替换为my_strcmp(),您将获得所需的结果。

在排序算法中,分别考虑它的3个主要方面是个好主意:

  • 比较函数。
  • 我们将使用的抽象排序算法。
  • 该数据的方式将被移动&#34;在数组中必须交换两个项目时。

这些方面可以独立优化 因此,举例来说,一旦你的比较函数得到很好的解决,下一个优化步骤可能是用快速排序来替换双重排序算法。
特别是,标准库qsort()的函数<stdlib.h>为您提供了这样的算法,因此您不需要关心它的编程。
最后,用于存储阵列信息的策略可能会对性能产生影响 将字符串和#34;指针数组存储到char&#34;中会更有效率。而不是&#34; char&#34;数组的数组,因为交换指针比交换两个整个字符数组更快。

Arrays of pointers

附加说明:前三个if()实际上是多余的,因为以下句子的逻辑意味着在*p1的情况下所需的结果或*p2为0.但是,通过保留这些if(),代码变得更具可读性。

答案 3 :(得分:3)

在这里,如果我做对了,你想要的东西如我所描述的那样:

不区分大小写的排序,在tie中,将使用tiebreaker条件“小写首先出现”。

所以就像:

  1. earlier_letter_in_the_alphabet < later_letter_in_the_alphabet忽略此案

  2. lowercase < uppercase

  3. shorter_word < wider_word
    • 没有提及,我是从字典顺序中借用它,字典中的那个
    • 只需将'\0'作为比较中最低的
    • 即可使用
  4. 仅当1没有区分任何东西时才采取步骤2。步骤3已经用1进行检查。所有这些都是逐字母完成的,这意味着一旦你在相应的字符之间取得平局就应该切换到2,而不是在整个字符串处于平局时。 / p>


    假设这是正确的,我们现在需要做的就是编写一个函数,对任何给定的两个字符串进行比较。

    #include <ctype.h>  // for tolower and islower
    
    int my_character_compare(const char a, const char b)
    {
        int my_result;
    
        my_result = tolower(a) - tolower(b);
        // unless it is zero, my_result is definitely the result here
        // Note: if any one of them was 0, result will also properly favour that one
    
    
        if (my_result == 0 && a != b)
        // if (could not be distinguished with #1, but are different)
        {
            // means that they are case-insensitively same
            // but different...
            // means that one of them are lowercase, the other one is upper
            if (islower(a))
                return -1;  // favour a
            else
                return 1;   // favour b
        }
    
    
        // regardless if zero or not, my_result is definitely just the result
        return my_result;
    }
    
    int my_string_compare(const char * a, const char * b)
    {
        int my_result;
    
        my_result = my_character_compare(*a, *b);
        // unless it is zero, my_result is definitely the result here
    
        while (my_result == 0 && *a != 0)
        // current characters deemed to be same
        // if they are not both just 0 we will have to check the next ones
        {
            my_result = my_character_compare(*++a, *++b);
        }
    
        // whatever the my_result has been:
        //   whether it became != zero on the way and broke out of the loop
        //   or it is still zero, but we have also reached the end of the road/strings
        return my_result;
    }
    

    按惯例/规则,比较函数应该返回一个负值,用于支持第一个参数在前面,负值用于支持第二个参数,如果它不能区分它们则为零。您可能已经通过使用strcmp的方式获知的其他信息。

    就是这样!用strcmp替换代码中的my_string_compare,同时提出我们在顶部制作的这些定义应提供正确的结果。实际上,它为所讨论的示例输入提供了预期的结果。

    可以缩短当然的定义,我已经做了很长时间,以便更容易理解正在发生的事情。例如,我可以将其全部归结为以下内容:

    #include <ctype.h>
    
    int my_string_compare(const char * a, const char * b)
    {
        int my_result;
    
        while (*a || *b)
        {
            if ((my_result = tolower(*a) - tolower(*b)))
                return my_result;
            if (*a != *b)
                return (islower(*a)) ? -1 : 1;
            a++;
            b++;
        }
    
        return 0;
    }
    

    与另一个基本相同,你可以使用任何你喜欢的;甚至更好,写一个。

答案 4 :(得分:3)

我迟到了这个讨论,并没有特别期望天鹅投入并获得神话般的奖品,但没有看到使用我首先看到的习语的解决方案,我想我钟声。

我在阅读问题规范时的第一个想法是某种形式的自定义整理顺序,我基本上在@ jxh&#39; s 使用整理表概念中找到了。我不认为不区分大小写是一个核心概念,只是奇怪的订单。

因此,我提供以下代码纯粹作为替代实现。它使用了glibc特有的 - qsort_r(3) - 但感觉就像一个更轻量级的方法,并且在运行时支持许多整理顺序。但它经过了轻微的测试,我很可能会错过各种各样的弱点。其中:我没有特别注意Unicode或一般的宽字符世界,并且为了避免负数组下标而使用unsigned char的转换感到可疑。

#include <stdio.h>
#include <limits.h>

/*
 * Initialize an index array associated with the collating
 * sequence in co. The affected array can subsequently be
 * passed in as the final client data pointer into qsort_r
 * to be used by collating_compare below.
 */
int
collating_init(const char *co, int *cv, size_t n)
{
    const unsigned char *uco = (const unsigned char *) co;
    const unsigned char *s;
    size_t i;

    if (n <= UCHAR_MAX) {
        return -1;
    }
    for (i = 0; i < n; i++) {
        /* default for chars not named in the sequence */
        cv[i] = UCHAR_MAX;
    }
    for (s = uco; *s; s++) {
        /*
         * the "collating value" for a character's own
         * character code is its ordinal (starting from
         * zero) in the collating sequence. I.e., we
         * compare the values of cv['a'] and cv['A'] -
         * rather than 'a' and 'A' - to determine order.
         */
        cv[*s] = (s - uco);
    }

    return 0;
}

static int
_collating_compare(const char *str1, const char *str2, int *ip)
{
    const unsigned char *s1 = (const unsigned char *) str1;
    const unsigned char *s2 = (const unsigned char *) str2;

    while (*s1 != '\0' && *s2 != '\0') {
        int cv1 = ip[*s1++];
        int cv2 = ip[*s2++];

        if (cv1 < cv2) return -1;
        if (cv1 > cv2) return 1;
    }

    if (*s1 == '\0' && *s2 == '\0') {
        return 0;
    } else {
        return *s1 == '\0' ? -1 : 1;
    }
}

int
collating_compare(const void *v1, const void *v2, void *p)
{
    return _collating_compare(*(const char **) v1,
                              *(const char **) v2,
                              (int *) p);
}

前一个代码可以放在单独的模块或库中,但缺少自己的头文件(或头文件中的条目)。我自己的测试只是将上面和下面的代码连接到一个名为custom_collat​​e_sort.c的文件中,并使用

gcc -DMAIN_TEST -Wall -o custom_collate_sort custom_collate_sort.c

...编译它。

#if defined(MAIN_TEST)

/* qsort_r is a GNU-ey thing... */

#define __USE_GNU
#include <stdlib.h>
#include <string.h>

#define NELEM(x) (sizeof x / sizeof 0[x])

static int
cmp(const void *v1, const void *v2)
{
    return strcmp(*(const char **) v1, *(const char **) v2);
}

static int
casecmp(const void *v1, const void *v2)
{
    return strcasecmp(*(const char **) v1, *(const char **) v2);
}

int
main(int ac, char *av[])
{
    size_t i;

    int cval[256], ret;
    int cval_rev[256], rret;

    char *tosort[] = {
        "cheeSE", "eggs", "Milk", "potatoes", "cheese", "spaghetti",
        "eggs", "milk", "spinach", "bacon", "egg", "apple", "PEAR",
        "pea", "berry"
    };

    ret = collating_init("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVxXyYzZ",
                         cval, NELEM(cval));

    rret = collating_init("ZzYyXxVvUuTtSsRrQqPpOoNnMmLlKkJjIiHhGgFfEeDdCcBbAa",
                          cval_rev, NELEM(cval_rev));

    if (ret == -1 || rret == -1) {
        fputs("collating value array must accomodate an index of UCHAR_MAX\n", stderr);
        return 1;
    }

    puts("Unsorted:");
    for (i = 0; i < NELEM(tosort); i++) {
        printf("  %s\n", tosort[i]);
    }

    qsort((void *) tosort, NELEM(tosort), sizeof tosort[0], cmp);

    puts("Sorted w/ strcmp:");
    for (i = 0; i < NELEM(tosort); i++) {
        printf("  %s\n", tosort[i]);
    }

    qsort((void *) tosort, NELEM(tosort), sizeof tosort[0], casecmp);

    puts("Sorted w/ strcasecmp:");
    for (i = 0; i < NELEM(tosort); i++) {
        printf("  %s\n", tosort[i]);
    }

    qsort_r((void *) tosort, NELEM(tosort), sizeof tosort[0],
            collating_compare, (void *) cval);

    puts("Sorted w/ collating sequence:");
    for (i = 0; i < NELEM(tosort); i++) {
        printf("  %s\n", tosort[i]);
    }

    qsort_r((void *) tosort, NELEM(tosort), sizeof tosort[0],
            collating_compare, (void *) cval_rev);

    puts("Sorted w/ reversed collating sequence:");
    for (i = 0; i < NELEM(tosort); i++) {
        printf("  %s\n", tosort[i]);
    }

    return 0;
}

#endif /* MAIN_TEST */

答案 5 :(得分:1)

程序所需的标准头文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

主程序从这里开始:

//Global Variables Required
//=========
const char *tgt[]={"bacon", "Bacon", "mIlk", 
        "Milk", "spinach", "MILK", "milk", "eggs"};    //Array for sorting
int tgt_size=8;                                        //Total Number of Records
int     SortLookupTable[128];                          //Custom sorting table
typedef int      cmp_t (const void *, const void *);




int main(int argc, char *argv[]) {
    printf("Before sort:\n\n");
    int n=0;
    for(n=0; n<tgt_size; n++)
        printf("%s\n", tgt[n]);

    CreateSortTable();

    myQsort(tgt, tgt_size, sizeof(char *), &compare);
    printf("\n\n====\n\n");
    for(n=0; n<tgt_size; n++)
        printf("%s\n", tgt[n]);

    return 0;
}

根据需要自定义排序表:

void CreateSortTable(void){
    int     i;
    for (i = 0; i < 128; i++){
        SortLookupTable[i] = 0;
    }
    char *s;
    s=(char *)malloc(64);
    memset(s, 0, 64);
    strcpy(s, "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ");

    i=1;
    for (; *s; s++){
        SortLookupTable[(int) ((unsigned char) *s)]=i;
        i++;
    }
}

快速排序算法,您也可以使用提供的标准库:

//Some important Definations required by Quick Sort
=======
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
    es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;

#define swap(a, b)                          \
    if (swaptype == 0) {                    \
        long t = *(long *)(a);              \
        *(long *)(a) = *(long *)(b);        \
        *(long *)(b) = t;                   \
    } else                                  \
        swapfunc(a, b, es, swaptype)

#define vecswap(a, b, n)    if ((n) > 0) swapfunc(a, b, n, swaptype)


#define swapcode(TYPE, parmi, parmj, n) {       \
    long i = (n) / sizeof (TYPE);               \
    register TYPE *pi = (TYPE *) (parmi);       \
    register TYPE *pj = (TYPE *) (parmj);       \
    do {                                        \
        register TYPE   t = *pi;                \
        *pi++ = *pj;                            \
        *pj++ = t;                              \
        } while (--i > 0);                      \
}

#define min(a, b)   (a) < (b) ? a : b


//Other important function
void swapfunc(char *a, char *b, int n, int swaptype){
    if(swaptype <= 1)
        swapcode(long, a, b, n)
    else
        swapcode(char, a, b, n)
}

char * med3(char *a, char *b, char *c, cmp_t *cmp){
    if ( cmp(a, b) < 0){
        if (cmp(b, c) < 0){
            return b;
        }else{
            if ( cmp(a, c) < 0){

                return c;
            }else{
                return a;
            }
        }
    }else{
        if (cmp(b, c) < 0){
            return b;
        }else{
            if ( cmp(a, c) < 0){
                return a;
            }else{
                return c;
            }
        }
    }
}

//Custom Quick Sort

void myQsort(void *a, unsigned int n, unsigned int es, cmp_t *cmp){
    char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
    int d, r, swaptype, swap_cnt;

loop:   SWAPINIT(a, es);
    swap_cnt = 0;
    if (n < 7) {
        for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
            for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; pl -= es){
                swap(pl, pl - es);
            }
        return;
    }
    pm = (char *)a + (n / 2) * es;
    if (n > 7) {
        pl = a;
        pn = (char *)a + (n - 1) * es;
        if (n > 40) {
            d = (n / 8) * es;
            pl = med3(pl, pl + d, pl + 2 * d, cmp);
            pm = med3(pm - d, pm, pm + d, cmp);
            pn = med3(pn - 2 * d, pn - d, pn, cmp);
        }
        pm = med3(pl, pm, pn, cmp);
    }
    swap(a, pm);
    pa = pb = (char *)a + es;

    pc = pd = (char *)a + (n - 1) * es;
    for (;;) {
        while (pb <= pc && (r = cmp(pb, a)) <= 0) {
            if (r == 0) {
                swap_cnt = 1;
                swap(pa, pb);
                pa += es;
            }
            pb += es;
        }
        while (pb <= pc && (r = cmp(pc, a)) >= 0) {
            if (r == 0) {
                swap_cnt = 1;
                swap(pc, pd);
                pd -= es;
            }
            pc -= es;
        }
        if (pb > pc)
            break;
        swap(pb, pc);
        swap_cnt = 1;
        pb += es;
        pc -= es;
    }
    if (swap_cnt == 0) {  /* Switch to insertion sort */
        for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
            for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0;
                 pl -= es)
                swap(pl, pl - es);
        return;
    }

    pn = (char *)a + n * es;
    r = min(pa - (char *)a, pb - pa);
    vecswap(a, pb - r, r);
    r = min(pd - pc, pn - pd - es);
    vecswap(pb, pn - r, r);
    if ((r = pb - pa) > es)
        myQsort(a, r / es, es, cmp);
    if ((r = pd - pc) > es) {
        /* Iterate rather than recurse to save stack space */
        a = pn - r;
        n = r / es;
        goto loop;
    }
}

两个最重要的功能是:

unsigned char Change(char a){
    return (unsigned char ) SortLookupTable[(int)a];
}


int compare (const void *a, const void *b){
    char *s1= *(char **)a;
    char *s2= *(char **)b;
    int ret, len, i;
    ret=0;

    if (strlen((void*)s1) > strlen((void*)s2)){
        len=strlen((void*)s1);
    }else{
        len=strlen((void*)s2) ;
    }

    for(i=0; i<len; i++){
        if ( s1[i] != s2[i]){
            if ( Change(s1[i]) < Change(s2[i]) ){
                ret=0;
                break;
            }else{
                ret=1;
                break;
            }
        }
    }

    return ret;
}