【问题标题】:C program sort strings in alphabetical orderC程序按字母顺序排序字符串
【发布时间】:2020-04-16 05:14:46
【问题描述】:

我是 C 编程新手,我正在尝试编写一个按字母顺序对单词进行排序的代码。我认为大写字母和小写字母不同。我的排序规则是首先考虑字母顺序,然后大写字母优先,字符较少的单词优先。对于所有单词,我们只考虑第一个和第二个字母字符,如果它们相似,我们转到下一个单词。
最后,当输入0 时,程序应该完成了。
以下是它应该做什么的示例:
输入:alireza Mohammad Arash anahita sarah Milad john Alireza Maryam 0
输出:Alireza alireza anahita Arash john Maryan Milad Mohammad sarah

#include<stdio.h>
#include<string.h>
int main() {
    int i=0, j=0, count;
    char str[25][25], temp[25];
    while (1) {
        gets(str[i]);
        if(str[i][0]=='0')
            break;
        i++;
        j++;
    }
    count=i;
    for(i=0; i<=count; i++)
        for(j=i+1; j<=count; j++) {
            if(strcmp(str[i], str[j]) > 0) {
                strcpy(temp, str[i]);
                strcpy(str[i], str[j]);
                strcpy(str[j], temp);
            }
         }
    for(i=0; i<count; i++)
        printf("%s ", str[i]);
    return 0;
}

但我的代码仅通过比较它们的 ASCII 码对单词进行排序,这导致所有大写字母都排在第一位
输入:aa bb AA we WE 0
我的输出:AA WE aa bb we
但应该是:
输出:AA aa bb WE we
我在想我是否可以做一些事情,比如为字符创建新的 ASCII 代码,但这似乎也是不可能的。 这样的字符串怎么排序?

【问题讨论】:

标签: c string sorting c-strings alphabetical


【解决方案1】:

您需要根据您的特定需求量身定制的“新”strcmp()

enum /*untagged*/ { AbeforeB = -1, AequalsB = 0, AafterB = 1 };

int tailored_strcmp(const char *a, const char *b) {
    static char baseorder[] = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
    //if a or b is the empty string
    if (*a == 0) return AbeforeB;
    if (*b == 0) return AafterB;
    int lena = strlen(a);
    int lenb = strlen(b);
    char *pa = strchr(baseorder, *a);
    char *pb = strchr(baseorder, *b);
    if (pa == NULL) return lena < lenb ? AbeforeB : AafterB;
    if (pb == NULL) return lena < lenb ? AbeforeB : AafterB;
    if (pa == pb) {
        //need to check second letter
        if (a[1] == 0) return AbeforeB;
        if (b[1] == 0) return AafterB;
        char *ppa = strchr(baseorder, a[1]);
        char *ppb = strchr(baseorder, b[1]);
        if (ppa == NULL) return lena < lenb ? AbeforeB : AafterB;
        if (ppb == NULL) return lena < lenb ? AbeforeB : AafterB;
        if (ppa == ppb) return lena < lenb ? AbeforeB : AafterB;
        return ppa < ppb ? AbeforeB : AafterB;
    }
    return pa < pb ? AbeforeB : AafterB;
}

version running at ideone,或version with improved adherence to requirements version checking 1-length strings

【讨论】:

  • 这很复杂,只是为了避免使用 stdlib 函数...
  • @wildplasser:我什至没有(还!)实现 OP 所需的所有功能! OP 希望 "Ggxx""Ggdddddd" 之前排序,因为它更短并且前两个字符相等:)
  • 嗯?因为它更短?我辞职!
  • 大声笑不要辞职:这是一个“重新发明[方形]轮子”的有趣项目:)
  • @pmg:它工作得很好,但我有一个问题,我该怎么做才能让函数早于两个返回一个字符,比如在 aa 之前打印 char a?
【解决方案2】:

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

int main(void){
   int i=0,j=0,count;
   char str[25][25],temp[25];

   for (i=0; i < 25; i++) {
       if (!fgets(str[i], sizeof str[i], stdin)) break;
       if(str[i][0]=='0')break;
       str[i][ strcspn(str[i], "\r\n")] = 0;
       }
   count=i;

   for(i=0;i<count;i++) {
      for(j=i+1;j<count;j++){
          int rc;

          rc = strcasecmp(str[i],str[j]);
          if (rc < 0) continue;
            /* strings are equal, except for case: do the normal compare */
          if (rc == 0) rc = strcmp(str[i],str[j]);
          if (rc < 0) continue;
          strcpy(temp,str[i]);
          strcpy(str[i],str[j]);
          strcpy(str[j],temp);
      }
   }
   for(i=0;i<count;i++) {
          printf("%s ",str[i]);
   }

   return 0;
}

更新:新版本,实现 {first_two_characters, length, rest_of_the string} ,使用相当复杂的比较函数:


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

int myverysillystringcompare(char *ll, char *rr)
{
size_t siz_l, siz_r, siz;
int rc;

siz_l = strlen(ll);
siz_r = strlen(rr);

if (!siz_l || !siz_r) return siz_r - siz_l;

siz = (siz_l < siz_r) ? siz_l : siz_r;

if( siz > 2) siz = 2;
        // Compare the first two characters, (if any) case INSIGNIFICANT
rc = strncasecmp( ll, rr, siz );
if (rc) return rc; // They differ

        // Compare the first two characters, (if any) case SIGNIFICANT
rc = strncmp( ll, rr, siz );
if (rc) return rc; // they differ

        // Compare the lengths; the shortest wins
if (siz_l != siz_r) return siz_l - siz_r;

        // Compare the rest of the string, (if any) case INSIGNIFICANT
rc = strcasecmp(ll+siz, rr+siz);
if (rc) return rc; // they differ

        // Compare the rest of the string, (if any) case SIGNIFICANT
rc = strcmp(ll+siz, rr+siz);
return rc;
}

int main(void){
   int i=0,j=0,count;
   char str[25][25],temp[25];

   for (i=0; i < 25; i++) {
       if (!fgets(str[i], sizeof str[i], stdin)) break;
       if(str[i][0]=='0')break;
       str[i][ strcspn(str[i], "\r\n")] = 0;
       }
   count=i;

   for(i=0;i<count;i++) {
      for(j=i+1;j<count;j++){
         int rc;
         rc = myverysillystringcompare(str[i],str[j]);
         if (rc <= 0) continue;
         strcpy(temp,str[i]);
         strcpy(str[i],str[j]);
         strcpy(str[j],temp);
      }
   }
   for(i=0;i<count;i++) {
          printf("%s ",str[i]);
   }

   return 0;
}

【讨论】:

  • 嗯,使用这个函数是一个很好的建议,谢谢,但是当我在可视 stdio 中运行你的代码时,由于不理解 strcasecmp 函数,它不会工作,你知道为什么吗?跨度>
  • 也许是因为微软讨厌 C? (IOW:转储它。它无法修复) BTW:20 年前有一件事:你也必须包括&lt;strings.h&gt;。也许他们忘记了?
【解决方案3】:

这里的错误是你直接使用strcmp而不改变第一个字母。因此,即使最后一个字母 'Z' 也出现在 'a' 之前。以下代码将第一个字母更改为大写,然后比较字符串,然后将字符串更改为原始状态。

#include <stdio.h>
#include <string.h>
bool islower(char c) {
    return ('a' <= c) && (c <= 'z');
}
void makeupper(char& c) {
    c = c - 'a' + 'A';
}
void makelower(char& c) {
    c = c - 'A' + 'a';
}
int main() {
    int i=0, j=0, count;
    char str[25][25], temp[25];
    while (1) {
        scanf("%s", str[i]);
        if(str[i][0]=='0')
            break;
        i++;
        j++;
    }
    count=i;
    // beware for loop conditions
    for(i=0; i<count-1; i++)
        for(j=i+1; j<count; j++) {
            bool lower1 = islower(str[i][0]);
            bool lower2 = islower(str[j][0]);
            if (lower1)
                makeupper(str[i][0]);
            if (lower2)
                makeupper(str[j][0]);
            // swap the strings under these conditions
            if (((strcmp(str[i], str[j]) == 0) && lower1 && !lower2) // string are equal but first string's first letter was lowercase and second string's first letter was uppercase
                    || (strcmp(str[i], str[j]) > 0)) { // second string comes alphabetically first
                strcpy(temp, str[i]);
                strcpy(str[i], str[j]);
                strcpy(str[j], temp);
                // undo changes
                if(lower1)
                    makelower(str[j][0]);
                if(lower2)
                    makelower(str[i][0]);
            }
            else { // undo changes
                if (lower1)
                    makelower(str[i][0]);
                if (lower2)
                    makelower(str[j][0]);
            }
        }
    for(i=0; i<count; i++)
        printf("%s ", str[i]);
    return 0;
}

此代码仅修复第一个字母,但不检查第二个字母。您可以通过将 lower1lower2 更改为 bool 数组以及相应的其余代码来实现类似的技巧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2018-11-20
    相关资源
    最近更新 更多