[EOJ] 实训题 P2896 随机排序

[EOJ] 实训题 P2896 随机排序

先把题目地址贴出来:P2896.随机排序
https://acm.ecnu.edu.cn/problem/2896/

题目描述

给定一组以一个空格分隔的只含大小写字母的字符串。与普通字典序不同,按照给定的字母顺序对这组字符串排序。

设两个字符串的字母不会完全相同。如:Hat、hat、HAt 等不会同时出现。

例如:
字母顺序为 QWERTYUIOPASDFGHJKLZXCVBNM 时:

一组字符串 hat cat bat book bookworm Dallas Austin Houston fire firefox fumble

排序结果为:Austin Dallas fumble fire firefox Houston hat cat book bookworm bat

输入格式

每组数据由 2 行组成:

第 1 行为字母顺序(26 个大写字母),第 2 行是需要排序的一组字符串(只含大小写字母,长度不大于 20)。

数据不多于 100 组。需要排序的一组字符串中包含的字符串个数至少 1 个,至多 100 个。

输出格式

对于每一组数据,输出排序后的字符串。字符串之间输出一个空格,最后一个字符串后面没有空格,而是输出一个换行符。

样例

Input

QWERTYUIOPASDFGHJKLZXCVBNM
hat cat bat book bookworm Dallas Austin Houston fire firefox fumble
QWERTYUIOPASDFGHJKLZXCVBNM
How are you
QAZWSXEDCRFVTGBYHNUJMIKOLP
How are you
ABCDEFGHIJKLMNOPQRSTUVWXYZ
How are you

Output

Austin Dallas fumble fire firefox Houston hat cat book bookworm bat
you are How
are you How
are How you

题解

题目是我校大一实训课的一道训练题,虽然不难,不过我第一遍做的时候非常麻烦,参考了dalao的代码有一些想法,和大家分享一下。根据题目要求:

输入有若干组,以一个参照字符串的输入开始,后面跟一组用空格分隔的字符串,需要我们对这组字符串进行分割、存储、排序、输出。很自然有以下思路:

  1. 定义一个全局变量字符串Alphaet,每组输出以 while(cin >> Alphaet) 为开始。

  2. 在每组输出的第二行里是多个字符串组成的一整个字符串。为了处理它们,第一遍我的想法是用cin和getchar()结合,通过判断单个字符是否是’\n’决定是否跳出这轮读取。跳出后再对该组的字符串进行排序输出即可。存储字符串可以采用char[100] [21]这样的二维字符数组,或者string s[100]字符串数组以及STL Vector。 这里以vector为例。

  3. 上面的处理方式是可行的。但略显笨拙,于是参考了dalao的写法如下:

    string line,t;
    vector<string>s;
    getline(cin, line);
    stringstream linestream;
    linestream << line; //linestream.str(line); 这种写法也是可行的 相当于把line传入到了stream中
    while(linestream >> t) s.push_back(t);
    

    stringstream 是定义在头文件 #include 中的一种类。可以用来进行数据类型转换,以及字符串拼接等等。感兴趣的朋友可以参考这篇博文:

    我们这里拿来进行分割字符串,也是可行的,按照上述的操作,每组数据的第二行(也就是我们需要的长字符串)会被依次分割后导入到容器中。接着我们用直接用sort(),在写好了cmp函数的情况下排序即可。

  4. cmp函数头定义如下:bool cmp(string aa,string bb) 。根据题目要求,我们需要参照给定的字符串中的字母排序(已经保存在Alphaet中),对我们的字符串进行排序。

    • 这里不难想到,由于题目已经提前说了只有大写字母,所以我们显然要将待排序的字符串都转为大写字母,当然不转换的情况下直接逐字符用toupper()函数进行比对也是可以的。
    • 逐位对aa和bb中的字符进行比对,可以用find()函数找到其分别在Alphaet中的位置,再按升序排序即可。如果这一位相同就比下一位。如果一直比到较短的字符串结束还是相同,如:aa = ”abcd“ ,bb = “AbcdeF”。由于大小写在这里不作区分,那么到aa遍历结束,仍然不能排序成功,那么此时显然是要让短的排在前面,直接 return aa.size() < bb.size() 即可。

两份AC代码如下:

1.自己实现的:
#include
#include
#include
#include
#include
#include
using namespace std;

string alphaet;

bool cmp(string aa,string bb)
{
  int len1 = aa.size(), len2 = bb.size();
  for(int i = 0; i < min(len1, len2); ++i)
  {
    char c1 = toupper(aa[i]), c2 = toupper(bb[i]);
    if(c1 != c2)
     return alphaet.find(c1,0) < alphaet.find(c2,0);
  }
  return len1 < len2;
}

int main()
{
  string line,t;
  vector <string> s;
  while(cin >> alphaet)
  {
     char ch;
     s.clear();
     while(1)
     {
         cin >> t;
         ch = getchar();
         s.push_back(t);
         if(ch == '\n') break;
     }
  	 sort(s.begin(), s.end(), cmp);
  	 int len = s.size();
  	 for(int i = 0; i < len; ++i)
        cout << s.at(i) << ((i == len - 1)?'\n':' ');
  }
  return 0;
}


参考修改后的:
#include
#include
#include
#include
#include
#include
using namespace std;

string alphaet;

bool cmp(string aa,string bb)
{
  int len1 = aa.size(), len2 = bb.size();
  for(int i = 0; i < min(len1, len2); ++i)
  {
    char c1 = toupper(aa[i]), c2 = toupper(bb[i]);
    if(c1 != c2)
     return alphaet.find(c1) < alphaet.find(c2);
      //find(目标字符串,初始查找地址(缺省就从头开始))
  }
  return len1 < len2;
}

int main()
{
  string line,t;
  vector <string> s;
  while(cin >> alphaet)
  {
     getchar();  //  这里为了消除第一行留下的'\n',如果没有此行,下行的getline得不到正确的结果。 
  	 getline(cin, line);
  	 stringstream linestream;
  	 linestream << line; //  linestream.str(line);
  	 s.clear();  //  清空vector,便于重新输入
  	 while(linestream >> t) s.push_back(t);
  	 sort(s.begin(), s.end(), cmp);
  	 int len = s.size();
  	 for(int i = 0; i < len; ++i)
        cout << s.at(i) << ((i == len - 1)?'\n':' ');
  }
  return 0;
}


Note

Stringstream的用法是我之前没有用过的,这样写出来的代码更加优美和简洁,此外它还有其他一些用法已经贴在文中的链接里,大家有兴趣的可以自行浏览。

你可能感兴趣的:([EOJ] 实训题 P2896 随机排序)