C程序按字母顺序对字符串进行排序
C program sort strings in alphabetical order
我是 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 代码,但这似乎也是不可能的。
怎么能像这样对字符串进行排序?
这里不对的是你直接用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;
}
此代码仅修复第一个字母,但不检查第二个字母。您可以通过将 lower1
和 lower2
更改为 bool 数组来实现类似的技巧,并相应地更改其余代码。
您需要 "new" 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, or version with improved adherence to requirements or version checking 1-length strings
- 不要使用 gets() The Morris worm was 30 years ago, and gets() has been removed from the stdlib
- 标准库中有一个函数可以完全满足您的需求:
strcasecmp()
- 数组索引从 1 开始到 before 结束;最后一个有效索引是
count-1
#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,长度,rest_of_the 字符串}
,使用相当复杂的比较函数:
#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;
}
我是 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 代码,但这似乎也是不可能的。
怎么能像这样对字符串进行排序?
这里不对的是你直接用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;
}
此代码仅修复第一个字母,但不检查第二个字母。您可以通过将 lower1
和 lower2
更改为 bool 数组来实现类似的技巧,并相应地更改其余代码。
您需要 "new" 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, or version with improved adherence to requirements or version checking 1-length strings
- 不要使用 gets() The Morris worm was 30 years ago, and gets() has been removed from the stdlib
- 标准库中有一个函数可以完全满足您的需求:
strcasecmp()
- 数组索引从 1 开始到 before 结束;最后一个有效索引是
count-1
#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,长度,rest_of_the 字符串} ,使用相当复杂的比较函数:
#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;
}