在C ++中按非ASCII顺序的第一个字母对字符串向量进行排序
Posted
技术标签:
【中文标题】在C ++中按非ASCII顺序的第一个字母对字符串向量进行排序【英文标题】:Sorting a vector of strings by the first letter in non-ascii order in C++ 【发布时间】:2016-10-11 06:32:50 【问题描述】:我有一个包含单词列表的文本文件。
我使用ifstream
将这些单词读入vector
,现在我尝试按类似于以下的顺序对它们进行排序:
A a B b C c [...]
我尝试在气泡搜索算法中使用第三个 for 循环来实现这一点,以查看每个单词的第一个字符(我知道这远非最有效的方法,尤其是在我使用大型数据集时)
然后检查字母和下一个字母是大写还是小写,如果大写字母与当前字母相同,则切换,但这似乎不起作用。
void bubble_Sort (vector <string> & words)
for (unsigned i = words.size(); i >= 2; --i)
for (unsigned k = 0; k + 1 < i; k++)
int hi = k+1;
string temp1 = words[hi];
string temp2 = words[k];
int smallsize = words[hi].size();
int smallprecedence = 0;
if (words[k].size() < words[hi].size())
smallsize = words[k].size();
for (unsigned j = 0; j < smallsize; j++)
if (temp1[j] >= 'A' && temp1[j] <= 'Z')
if (temp2[j] >='a' && temp2[j] <= 'z')
char lowercase1 = temp1[j] + 32;
if (lowercase1 == temp2[j])
string temp = words[k];
words[k] = words[hi];
words[hi] = temp;
break;
else if (temp2[j] >= 'A' && temp2[j] <= 'Z')
if (temp1[j] < temp2[j])
string temp = words[k];
words[k] = words[hi];
words[hi] = temp;
break;
if (temp1[j] >= 'a' && temp1[j] <= 'z')
if (temp2[j] >= 'A' && temp2[j] <= 'Z')
char uppercase1 = temp1[j] - 32;
if (uppercase1 < temp2[j])
string temp = words[k];
words[k] = words[hi];
words[hi] = temp;
break;
else if (temp2[j] >= 'a' && temp2[j] <= 'z')
if (temp1[j] < temp2[j])
string temp = words[k];
words[k] = words[hi];
words[hi] = temp;
break;
else if (temp1[j] == temp2[j] && temp1.size() < temp2.size())
++smallprecedence;
if (smallprecedence == smallsize)
string temporary = words[k];
words[k] = words[hi];
words[hi] = temporary;
【问题讨论】:
您是否正在实施自己的冒泡排序作为练习?如果没有,你应该使用std::sort
并实现比较功能。
是的,我正在尝试使用冒泡排序按 A a B b 等顺序对向量进行排序,即使在 ascii 中 a 大于 B,这是我一直遇到的问题有。
【参考方案1】:
不要重新发明***。只需修改默认比较函数,使 aA
编辑我使用了错误的比较函数。对于<
,它应该返回true
,对于>=
,它应该返回false
。这个问题已经解决了
std::vector<std::string> vec;
//
std::sort(vec.begin(), vec.end(), [](const std::string& lhs, const std::string& rhs)
const char* s1=lhs.c_str();
const char* s2=rhs.c_str();
while(true)
// first ignore case
if ( std::toupper(*s1) < std::toupper(*s2) ) return true;
if ( std::toupper(*s1) > std::toupper(*s2) ) return false;
// end of both strings, exact match
if ( *s1 == 0 && *s2 == 0 ) return false;
// compare upper case vs lower case ('A' vs 'a')
if ( *s1 > *s2) return false;
if ( *s1 < *s2) return true;
++s1; ++s2;
);
【讨论】:
【参考方案2】:首先,摆脱硬编码的 ASCII 主义。 C 和 C++ 早就有判断一个字符是字母、数字、大写还是小写等的函数了,查一下。
其次,清楚地描述决定您希望结果的顺序的因素。
第三,根据该描述,编写一个函数,它接受两个字符串,并告诉您第一个字符串是否应该在第二个之前。在排序中使用那个函数。
【讨论】:
【参考方案3】:您可以使用std::sort
对向量进行排序,并使用std::string::at()
获取对std::string
中第一个字符的引用:
std::vector<std::string> vec;
//
std::sort(vec.begin(), vec.end(), [](const std::string& lhs, const std::string& rhs)
char l_ch, r_ch;
l_ch = lhs.at(0);
r_ch = rhs.at(0);
return l_ch < r_ch;
);
【讨论】:
在使用at()
之前最好检查空字符串。
@FrerichRaabe:你说得对,只是提供了一个 sn-p,甚至没有测试代码。 std::compare 可以用于比较,但 OP 坚持第一个字母【参考方案4】:
我认为跳过完全相同的前缀然后用大写比较一次就足够了:
std::vector<std::string> vec;
//
std::sort(vec.begin(), vec.end(), [](const std::string& lhs, const std::string& rhs)
const char* s1=lhs.c_str();
const char* s2=rhs.c_str();
while(*s1 && *s1 == *s2) ++s1; ++s2;
int rc = toupper(*s1) - toupper(*s2);
if (rc) return rc;
return *s1 - *s2;
);
如果您只需要按首字母比较,只需删除while(*s1 && *s1 == *s2) ++s1; ++s2;
【讨论】:
以上是关于在C ++中按非ASCII顺序的第一个字母对字符串向量进行排序的主要内容,如果未能解决你的问题,请参考以下文章
如何在 swift 中按字母顺序对 JSON 字符串进行排序?