借鉴某位佬的代码,注释比较多,里面也有一些我不太懂的部分,欢迎大家一起讨论。
测试用例粘这个:
4
a\b\c
a\d\e
b\cst
d\
0
下面是代码部分:
#include <iostream>
#include<string>
#include<algorithm> //有sort函数
#include<vector>
using namespace std;
const int maxn=11;
vector<string> vec[maxn]; //vec是一个元素类型为string,大小为11的vector(也就是容器)
int n; //路径总条数
string s; //每条路径
int main()
{
while(cin>>n&&n!=0){ //输入路径总条数
for(int i=0;i<n;i++)
{
cin>>s; //输入每条路径
vec[i].clear(); //把上一次的测试用例清除掉
vec[i].push_back(s); //把新的测试用例放入
}sort(vec,vec+n); //默认从小到大排序
for(int i=0;i<n;i++)
{
s=vec[i][0]; //第一个路径,这里的vector[i][0]为什么不能用vector[i]呢?我不太懂这个
vec[i].clear();//把带\的字符串清除掉,准备填入新的不带\的字符串
int j=0,index;
while(j<s.size()){//截取,将“a\b\c”的字符串分割成{"a","b","c"}这样的字符串数组
if((index=s.find('\\',j))!=string::npos){ //这里的意思是从字符串s下标为j的位置开始寻找,string::npos是指直到字符串的结尾(最大值为-1,通常和find搭配使用)
vec[i].push_back(s.substr(j,index-j));//substr截取函数,从第j位开始截取,截取index-j位,截取下来的是字母
j=index+1; //从\的后一个位置继续扫描并截取
}
else{
vec[i].push_back(s.substr(j,s.size()-j));//字符串的最后一个也要保存进去
break;
}
}
}
for(int i=0;i<n;i++) //打印
{
if(i==0){ //第一个直接输出
for(int j=0;j<vec[i].size();j++)
{
for(int k=0;k<j;k++)cout<<" ";
cout<<vec[i][j]<<endl;
}
}
else{//找到与前一个字符串的第一个不相等的位置
int j=0;
while(j<vec[i-1].size()&&j<vec[i].size()&&vec[i][j]==vec[i-1][j])//找到与前一个字符串的第一个不相等的位置
j++;
if(j==0) //如果第一个字母就不相同,直接输出
{
for(int k=0;k<vec[i].size();k++){
for(int l=0;l<k;l++)cout<<" "; //输出的是第几个字母前面就空几格
cout<<vec[i][k]<<endl;
}
}else{ //找到的第一个不同的位置j,从j开始输出
for(int k=j;k<vec[i].size();k++){
for(int l=0;l<k;l++)cout<<" ";
cout<<vec[i][k]<<endl;
}
}
}
}
cout<<endl;
}
}
下面只是一些我自己的一些知识补充,可不看
1.
vector.clear()函数并不会把所有元素清零。
vector有两个参数,一个是size,表示当前vector容器内存储的元素个数,一个是capacity,表示当前vector在内存中申请的这片区域所能容纳的元素个数。
通常capacity会比size大,如果往vector中push_back数据,这样就不用重新申请内存和拷贝元素到新内存区域了,便于节省时间。
所以vector.clear()的真正作用是:把size设置成0,capactiy不变。
2.
sort()基本使用方法:
sort()函数可以对给定区间所有元素进行排序。它有三个参数sort(begin, end, cmp),其中begin为指向待sort()的数组的第一个元素的指针,end为指向待sort()的数组的最后一个元素的下一个位置的指针,cmp参数为排序准则,cmp参数可以不写,如果不写的话,默认从小到大进行排序。如果我们想从大到小排序可以将cmp参数写为greater()就是对int数组进行排序,当然<>中我们也可以写double、long、float等等。
例如:sort(num,num+10,greater());
sort中的cmp也可以自己定义,通俗来讲就是比较方式,如果我们需要按照其他的排序准则,那么就需要我们自己定义一个bool类型的函数来传入。
例如:
#include <iostream>
#include<string>
#include<algorithm> //有sort函数
#include<vector>
using namespace std;
struct Student{
int number; //学号
int score; //成绩
};
const int MAXN=100;
Student arr[MAXN];
bool Compare(Student x,Student y){
if(x.score==y.score) //成绩相等比较学号
return x.number<y.number;
else
return x.score<y.score; //成绩不等比较成绩 按照升序排列,如果想按照降序排列,则是return x.score>y.score
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&arr[i].number,&arr[i].score);
}
sort(arr,arr+n,Compare); //按照比较函数比较,然后用sort排序(快排)
for(int i=0;i<n;i++)
{
printf("%d %d\n",arr[i].number,arr[i].score);
}
}
3.
什么是string::npos
C++手册里面给出的定义是这样的,string::npos就是一个公有的静态的常量类型的成员变量。使用前需要包含头文件。
具体定义如下:
static const size_type npos = static_cast<size_type>(-1);
1
这里的size_type就是类型size_t,size_t是一个无符号整形,那么-1也就是其最大值。
那么npos其实就是size_t的最大值,放到string类中也代表着:”until the end of the string”,作为一个返回值,在string类中代表的意思就是没有找到任何匹配字段(find, rfind, find_first_of,find_first_not_of等);
所以不要对npos有什么畏惧,它就是一个值,一个无符号整形的最大值。
什么地方用到了string::npos
std::string::npos 及时一个特殊的常量值,正式有了这个值才能让string和其他stl的迭代器使用不一样,也正是因为有了它才能让string类型的查找相对于其他同类型的stl查找效率更高。
string::npos常被用于find, rfind, find_first_of, find_last_of, find_first_not_of, substr, erase和find_last_not_of`,这些函数返回的类型都是size_t类型,当这些函数返回值和string::npos相等时说明查询到字符串结尾也没有找到查找的字符/字符子串。
string::npos的正确用法
使用stl迭代器习惯了很容易写出这样的代码,但是编译的时候却发现编译出错,这时因为find返回的时size_t类型的值,而不是迭代器。
auto iter = name.find(‘d’);
if (iter != name.end()) {
}
正确的用法如下:
// 查找s2字符串在s1中的位置
void fun(string s1, string s2)
{
// 查找s2字符串在s1中的位置
auto found = s1.find(s2);
// 检查位置是否等于string::npos,如果不等说明找到了,如果相等说明没找到
if (found != string::npos) {
cout << "first " << s2 << " found at: " << (found)
<< endl;
} else {
cout << s2 << " is not in"
<< "the string" << endl;
}
}
如果你不确定find返回值类型,最好使用auto,而不要使用int等类型承接,这样如果类型大小不一样会导致判断失误,比如你用uint16_t类型接返回值,来和string::npos判断是否相同,两个值都被赋值-1是,得到的值是不同的,一个是0xffff,一个是0xffffffff。
使用string::npos来去除字符串中的元音字母
std::string Disemvowel(const std::string& str) {
// 定义一个字符串,用来承接剔除元音字母之后的字符串
std::string vowelless;
// 定义一个包含所有原因字母的字符串
std::string vowels = "aeiouAEIOU";
// 迭代查找,如果不是元音字母,就把它放到vowelless中
for (char c : str) {
if (vowels.find(c) == std::string::npos) {
vowelless += c;
}
}
// 将所有非原因字母组成的字符串返回
return vowelless;
}
因此,可以看出std::string::npos是一个特殊的常量值,用来说明没有查找到的状态,这个值被用于std::string的很多成员函数,当这些成员函数返回std::string::npos时就说明没有找到你期望的值。