有没有一种方法可以使用排序将向量与字符串序列进行比较?

Posted

技术标签:

【中文标题】有没有一种方法可以使用排序将向量与字符串序列进行比较?【英文标题】:Is there a method to compare a vector to a string sequence using sort? 【发布时间】:2017-02-22 00:52:17 【问题描述】:

我有一个vector<string>,其中包含几个基于用户输入的单词。它们都使用名为container 的变量存储在向量中。我需要将字符串中的单词排列成非常规的 QWERTY 顺序,或者换句话说,我需要根据字符串对它们进行排序 string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM"; 所以示例运行看起来像这样

Enter a word: apple Enter a word: pear Enter a word: peach

Words sorted in QWERTY order: pear peach apple

我目前只能存储这些字符串,而且由于它们不是按字母顺序排列的,我不能在 if 语句中使用字符值,

有人提示我使用排序选择或插入来将我的向量字符串与 QWERTY 序列进行比较,但我无法在我的教科书或网上找到任何关于如何将其应用于我的代码的示例。任何帮助将不胜感激,感谢您的宝贵时间。

【问题讨论】:

您不需要任何排序选择。这是一个非常简单的查找表,可以找到与 qwerty 字符串对应的字符。另外,请选择一种语言,C 或 C++。 C++ 解决方案是两行,也许是一行。 对不起,我不习惯浏览这个网站,我想我输入了错误的标签。我不明白你所说的查找表是什么意思,有什么好的参考资料可以看看吗? 跳出框框思考。如果myword 是“梨”怎么办。什么是sequence[myword[0]]sequence[myword[1]]sequence[myword[2]]、、sequence[myword[3]]?因此,在您的排序中,您使用“PEAR”的字符作为查找来比较序列数组的值。 它们的数值应该是 10,3,11,4,对吧? 请记住,数组是从 0 开始的,所以应该是 9、2、10、3。 【参考方案1】:

只需使用std::string::find 查找符号的索引并比较它们:

bool sequenceLess( const std::string &s1, const std::string &s2 )

    static const std::string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
    for( size_t i = 0; i < s1.length(); ++i ) 
        if( i >= s2.length() ) return false;
        auto idx1 = sequence.find( ::toupper( s1[i] ) );
        auto idx2 = sequence.find( ::toupper( s2[i] ) );
        if( idx1 == idx2 ) continue;
        return idx1 < idx2;
    
    return true;

另一个版本是将字符串转换为索引向量并进行比较:

std::vector<size_t> convert( const std::string &s )

    static const std::string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
    std::vector<size_t> r( s.size() );
    std::transform( s.begin(), s.end(), r.begin(), [sequence]( char c ) 
         return sequence.find( ::toupper( c ) );
      );
    return r;


// now comparison is obvious
bool sequenceLess( const std::string &s1, const std::string &s2 )

    return convert( s1 ) < convert( s2 );

这个解决方案效率低,但出于学习目的应该没问题。

【讨论】:

【参考方案2】:

一种选择是用您的特殊字母表中的相应字符替换每个字符。然后进行排序并改回来。

例如:

we -> bc, er -> cd

【讨论】:

给每个角色赋予某种价值?我该如何应用排序功能呢? 我明白你的意思,但我不需要为字母表中的每个字母设置一个循环吗?如果我为它们分配不同字母的值,它不会打印不正确吗?【参考方案3】:

您可以尝试自定义排序。 请参考此链接 Sorting a vector of custom objects

下面是我的代码示例,但我处理的是小写字母。

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

struct mySort
     inline bool operator() (const string& s1, const string& s2)
    
        bool isSort = false;

        if(s1.length() < s2.length())
            return true;
        else if(s1.length() > s2.length())
            return false;
        

        //s1.length() == s1.length()
        string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
        int index1 = 0 , index2 = 0;
        for(int i = 0 ; i < s1.length() ; i++)

            for(int j = 0 ; j < sequence.length() ; j++)
                if(s1[i] == sequence[j])
                    index1 = j;

                
                if(s2[i] == sequence[j])
                    index2 = j;
                
            

            if(index1 < index2)return true;
        

        return false;
    
;

int main()


    vector<string> myVector;
    myVector.push_back("APPLE");
    myVector.push_back("PEAR");
    myVector.push_back("PEACH");
    sort(myVector.begin(), myVector.end(), mySort());
    for(int i = 0 ; i < myVector.size() ; i++)
        cout<<myVector[i]<<endl;
    

    return 1;

这是结果,

PS : 可能我漏掉了一些条件,只是分享给大家,如何应用自定义排序。

【讨论】:

这是我看惯了的代码风格,所以我想我可以理解得更好一点。不过我有点困惑,因为在这种情况下,“制服”和“上级”这两个词并没有正确地按 qwerty 顺序排序, 因为我设置了length的优先级高于sequence,所以subdue比superior短,所以先来。 [PS:请务必输入大写字母] 顺便说一句,这只是一个示例代码,向您展示它是如何工作的。您可以在struct内部设计自己的排序条件,希望我的分享对您有所帮助。 对不起,我的帖子没有说清楚!单词的长度无关紧要,我只是尝试根据字母排序(Q->W->E等)进行排序,所以不需要第一个布尔值?但是,是的,您的示例非常有帮助!非常感谢您的宝贵时间。 那么就不用比较长度了,但是要找出最短的长度。 int shortestLen = s1.length();如果(s1.length()>s2.length())shortestLen = s2.length()。所以在循环中,使用 for(int i = 0 ; i 【参考方案4】:

您可以为字符串重载&lt; 运算符,然后使用位于&lt;algorithm&gt; 的c++ 函数sort() 我不太明白您究竟想如何使用该规则对字符串进行排序,因此由您对两个字符串的比较进行编码,就是这样。

【讨论】:

【参考方案5】:

编辑:添加了查找表并更正了 getless 中的测试。

这是另一种使用 std::sort 和一个函数的解决方案,该函数测试每个字符串并在一个字符串按 QWERTY 顺序小于另一个字符串时返回 true

#include <algorithm>
#include <string>
#include <vector>
#include <cctype>
#include <iostream>

typedef std::vector<std::string> StringVect;
std::string sequence = "QWERTYUIOPASDFGHJKLZXCVBNM";
std::vector<int> lookup(26);

bool getless(const std::string& s1, const std::string& s2)

    for (size_t i = 0; i < std::min(s1.size(), s2.size()); ++i)
        if (s1[i] != s2[i])
            return (lookup[toupper(s1[i])-'A'] < lookup[toupper(s2[i])-'A']);
    return s1.size() < s2.size();
;

int main()

    StringVect sv =  "apple" , "pear" , "peach" ;

    // build the lookup table
    int i = 0;
    std::for_each(sequence.begin(), sequence.end(), [&](char ch) lookup[ch-'A'] = i; ++i; );

    // sort the data
    std::sort(sv.begin(), sv.end(), getless);

    // output results
    for (auto& s : sv)
      std::cout << s << "\n";

Live Example

构建了一个查找表,将字符的相对 ASCII 位置映射到在sequence 字符串中找到该字符的位置。比如lookup[0]A的位置(即10),lookup[1]B的位置(即23),等等

getless 函数扫描字符串并测试与每个字符串的i'th 字符相关联的字符以及相应的查找位置。

for 循环基本上“等待”被比较的两个字符串中的字符差异。如果s1 字符串中的字符的查找值小于s2 中字符的查找值,那么我们立即返回“true”,即s1 s2,我们返回 false

如果字符相等,我们会继续循环,直到用完要比较的字符。如果两个字符串在我们退出 for 循环之前都相等,我们返回真或假,具体取决于字符串的长度(较短的字符串意味着 s1

【讨论】:

你有没有注意到你的例子得到了错误的答案?所需的结果是 pear 的顺序 比较sequence[toupper(s1[i]) - 'A'] &lt; sequence[toupper(s2[i]) - 'A'] 并不像您认为的那样。例如,'R' 是 0x52,所以 'R' - 'A' 是 0x11 或 17 十进制。同时'C'是0x43所以'C' - 'A'是0x02或2个十进制。比较序列[17] 和序列[2] 是比较'K' 和'E'。由于 'E' CH 排序在 PEAR 之前,这是错误的方式。 @FrankBoyne 我意识到了错误并更正了示例。实际上有两个问题,一个与查找表有关,如果循环结束而没有在 getless 函数中返回 true 或 false,则该函数应该返回两个字符串中较短的长度。

以上是关于有没有一种方法可以使用排序将向量与字符串序列进行比较?的主要内容,如果未能解决你的问题,请参考以下文章

对已经排序了 n 个第一个元素的向量进行排序?

有没有一种简单的方法可以按字母顺序对字符串中的字符进行排序

算法之各种排序

八大排序之快速排序

图 - 拓扑排序 (二)

排序之快排(JS)