11. 句子缩写

64 阅读7分钟

题目描述

输出一个词组中每个单词的首字母的大写组合。

输入描述

输入的第一行是一个整数n,表示一共有n组测试数据。(输入只有一个n,没有多组n的输入)
接下来有n行,每组测试数据占一行,每行有一个词组,每个词组由一个或多个单词组成;每组的单词个数不超过10个,每个单词有一个或多个大写或小写字母组成;
单词长度不超过10,由一个或多个空格分隔这些单词。

输出描述

请为每组测试数据输出规定的缩写,每组输出占一行。

输入示例

1
ad dfa     fgs

输出示例

ADF

提示信息

注意:单词之间可能有多个空格

本节课你讲学到的内容

  • 字符大小的比较、字符运算、字符拼接
  • ASCII码
  • getchar()函数的使用
  • 函数的定义和使用
  • 函数的形参和实参
  • 引用&

1.字符大小的比较、字符运算、字符拼接

字符串是由一个个字符组合而成的, 比如字符串"hello", 是由字符(char)类型'h'、'e'、'l'、'l'、'0'组成的,我们可以通过索引来访问每一个字符。

image.png

2.ASCII码

字符的大小是根据它们在字符集中的ASCII码值来确定的。

比如'a'对应的ASCII码是97,'A' 对应的ASCII码是65

image.png

3.代码编写

1.getchar()函数的使用

getchar()函数来吸收一个回车符,因为在输入n之后,还需要输入回车符,才会输入下一行。

#include <bits/stdc++.h>

using namespace std;
int main(){
    //接收n行测试数据
    int n;
    cin >> n;
    
    //输入中获取一个字符
    getchar();
    
    return 0;
}

2.getline()函数的使用

while循环来处理n行数据,每一行数据用getline(cin,n)来进行接收。

//接收每行输入的字符串
string s;
while(n--){
    //输入读取一行字符串,存储在字符串变量s中
    getline(cin,s);
    //定义变量result,用来输出经过处理之后的结果
    string result;
}

image.png

3.处理首字符

  1. 如果是大写字符,直接拼接
  2. 如果是小写字符,转化为大写字符,再拼接
  3. a-z的ASCII码在97-122之间,A-Z的ASCII码在65-90之间,小写字符比大写字符大32
//如果是小写字符则转化为大写字符
if(s[0] >= 'a' && s[0] <= 'z'){
    s[0] -= 32;
}
//将每行的第一个字符转换成大写后添加到result中
result += s[0];

4.处理剩下的字符

for(int i = 1;i < s.size()-1; i++){
    if(s[i] == ' ' && s[i + 1] != ' '){
        if(s[i + 1] >= 'a' && s[i + 1] <= 'z'){
            s[i + 1] -= 32;
        }
        result += s[i + 1];
    }
}

5.输出

cout << result << endl;

6.完整代码

#include <bits/stdc++.h>

using namespace std;

int main(){
    int n;
    cin >> n;
    getchar();
    while(n--){
        string s;
        getline(cin ,s);
        string result;
        if(s[0] >= 'a' && s[0] <= 'z'){
            s[0] -= 32;
        }
        result += s[0];
        for(int i = 1;i < s.size() - 1; i++){
            if(s[i] == ' ' && s[i + 1] != ' '){
                if(s[i + 1] >= 'a' && s[i + 1] <= 'z'){
                    s[i + 1] -= 32;
                }
                result += s[i + 1];
            }
        }
        cout << result << endl;
    }
    return 0;
}        

4.函数的使用

代码过于冗余,如果后面还需要小写变成大写,还需要再写一次

if (s[0] >= 'a' && s[0] <= 'z'){
    s[0] -= 32;
} 
if (s[i + 1] >= 'a' && s[i + 1] <= 'z'){
    s[i + 1] -= 32; 
}

所以我们将写一个函数来实现该功能

1.函数的定义和使用

image.png

需要满足以下条件

  1. 返回类型:返回结果是经过转换后的大写字符,所以返回类型为char
  2. 函数名:自定义,这里以changeChar为例
  3. 形参列表:之前形参列表为空,这里需要接收一个字符,所以形参列表类型为char类型,参数名为a。此时需要修改a的参数,所以需要加&传递符号。
char changeChar(char &a){
    if(a >= 'a' && a <= 'z'){
        a -= 32;
    }
    return a;
}

2.函数的形参和实参

  1. 形参和实参的概念

形参是函数定义中声明的参数,位于函数的参数列表中。形参的定义只在函数执行期间有效,在函数执行完毕后会被销毁。

实参是函数调用中传递给函数的具体值或变量,实参传递的值必须与函数的形参类型匹配,否则会发生类型错误

  1. 形参和实参的用法

2.1形参

//a和b是传递的形参,只在函数体{}中有效
void printSum(int a, int b){
    int sum = a + b;
    cout << sum << endl;
}

2.2实参

int main(){
int x = 3;
int y = 4;
//这里进行函数调用,x和y是实参。
 printSum(x, y);
 cout << x << y << endl;
    return 0;
}

2.3当函数执行时,实参的值会复制一份给形参,函数中的修改只会影响形参的值,不会影响传递的实参

//a 和 b 是传递的实参
//当函数执行时,实参的值会复制一份给a,b
//a = 1,b = 2;
void printSum(int a, int b){
    int sum = a + b;
    a++;
    b--;
    cout << a << endl;//2
    cout << b << endl;//1
}


int main(){
    int x = 1,y = 2;
    printSum(x , y);
    cout << x << endl;//1
    cout << y << endl;//2
}

3.引用&

  1. 引用上的操作会影响到所指向的变量。
  2. 在声明引用时,需要在变量名前使用&符号。引用必须在声明时进行初始化,就不能改变引用的目标。
int a = 10;
int &n = a;
  1. 引用常常做为函数参数来使用,以便于函数内部修改函数调用时传递的变量。

当函数传递参数时,通常会创建参数的副本。使用引用参数可以避免不必要的参数复制,这对于大型数据结构(如数组)尤其有用,因为复制这些数据结构会产生显著的开销。

例如:

#include <iostream>
#include <algorithm> // 用于std::copy

using namespace std;

// 定义一个包含大型数组的结构体
struct LargeData {
    int data[1000]; // 假设存储1000个整数的数组

    LargeData() {
        fill(data, data + 1000, 1); // 初始化数组
    }

    // 拷贝构造函数(用于跟踪复制行为)
    LargeData(const LargeData& other) {
        copy(other.data, other.data + 1000, data);
        cout << "拷贝构造函数被调用,数据被复制!" << endl;
    }
};

// 按值传递:触发拷贝构造,产生副本
void processByValue(LargeData arr) {
    cout << "处理按值传递的数据(副本)" << endl;
}

// 按常量引用传递:无拷贝,直接操作原数据
void processByRef(const LargeData& arr) {
    cout << "处理引用传递的数据(无副本)" << endl;
}

int main() {
    LargeData bigArray; // 创建原始数据

    cout << "--- 按值传递测试 ---" << endl;
    processByValue(bigArray); // 调用时触发拷贝构造

    cout << "\n--- 按引用传递测试 ---" << endl;
    processByRef(bigArray); // 无拷贝构造

    return 0;
}

输出结果:

--- 按值传递测试 ---
拷贝构造函数被调用,数据被复制!
处理按值传递的数据(副本)

--- 按引用传递测试 ---
处理引用传递的数据(无副本)

代码解析:

  1. 结构体 LargeData
  • 包含一个大小为1000的整型数组,模拟大型数据结构。
  • 显式定义拷贝构造函数,输出提示信息以验证复制行为。
  1. 函数 processByValue
  • 参数按值传递,调用时会触发拷贝构造函数,生成数据的完整副本。
  • 适用于需要操作数据副本的场景,但复制大数组效率低下。
  1. 函数 processByRef
  • 参数使用 const LargeData&,即常量引用,避免复制。
  • 直接操作原始数据,无拷贝开销,提升性能。
  • const 确保函数内不会修改原数据,保证安全性。

核心结论

  • 按值传递:适合小型数据或需要独立副本的场景,但大型数据复制成本高。
  • 引用传递:避免复制,提升效率,尤其适合数组、对象等大型数据。常量引用(const &)在只读场景中进一步保障数据安全。
  1. 引用的作用域通常在声明他的函数内,超过作用域后引用将无效。
#include <bits/stdc++.h>

using namespace std;

void changeValue(int &a){
    a = 100;
}

int main(){
    int x= 10;
    cout << x << endl;//10
    changeValue(x);//传递x的引用给函数
    cout << x << endl;//100
    return 0;
}

5.代码优化

#include <bits/stdc++.h>

using namespace std;

char changeChar(char &a){
    if(a >= 'a' && a <= 'z'){
        a -= 32;
    }
    return a;
}

int main(){
    int n;
    cin >> n;
    getchar();
    while(n--){
        string s;
        getline(cin,s);
        string result;

        result += changeChar(s[0]);
        for(int i = 1;i < s.size()-1; i++){
            if(s[i] == ' ' && s[i + 1] != ' '){
               
                result += changeChar(s[i + 1]);
            }
        }
        cout << result << endl;
    }
    return 0;
}