【华为od刷题(C++)】HJ14 字符串排序(sort 函数、仿函数和类)

我的代码:

#include//用于输入输出操作
#include//用于处理字符串
#include//包含排序(sort)等算法函数
using namespace std;

bool cmp(string x, string y)
//cmp 是一个用于 sort 函数的比较函数,用来指定排序的规则
{
    //return x.compare(y)<0;
    /* 这是 string 类的成员函数,它返回一个整数值
    如果返回值小于 0,表示 x 应排在 y 前面 */

    /* x.compare(y) 会对字符串 x 和字符串 y 进行比较,并返回一个整数值:
    如果 x 在字典序上小于 y,则返回负值
    如果 x 和 y 相等,则返回 0
    如果 x 在字典序上大于 y,则返回正值 */

    return x < y; //升序
    /* x < y 会返回布尔值 true 或 false
    表示如果字符串 x 在字典序上小于字符串 y,则返回 true
    这会让 sort 将 x 排在 y 前面,即升序排列 */
}

int main() {
    int n;
    cin >> n;  // 输入字符串的数量

    string str[1001];  // 存储最多 1001 个字符串
    /* str[1001] 是 无效的索引,因为数组的最大有效索引是 1000
    尝试访问它将导致 未定义行为(例如程序崩溃或访问错误的数据)
    数组的有效范围:str[0] 到 str[1000] */

    for (int i = 0; i < n; i++) { // 输入每个字符串
        cin >> str[i];
    } 

    sort(str, str + n, cmp);  // 对字符串数组排序,使用自定义的cmp函数
    /* 这行代码的作用是对 str 数组中的前 n 个字符串按升序进行排序
    使用自定义的比较函数 cmp 来决定排序的顺序
    cmp 函数会按照字典序对字符串进行排序 */

    /*str 是一个指向字符串数组的指针,表示排序区间的起始位置
    str + n 是一个指向数组最后一个元素的下一个位置的指针,表示排序区间的结束位置
    str + n 实际上等于数组的 str[n] 的位置
    但是需要注意的是,sort 排序时不包括这个位置(即 str[n] 本身不参与排序)*/

    for(int i = 0; i < n; i++){ // 输出排序后的字符串
        cout << str[i] << endl;
    }
    return 0;
}

这个程序的目的是输入多个字符串,并将它们按照字典序(即升序)进行排序,然后输出排序后的字符串

字典序(即升序)是指按照字母顺序对字符串进行排序的方式,通常类似于字典中的单词排列顺序;字典序的排序规则会根据字符串中的字符逐一比较,直到找到不同的字符为止

字典序升序排序规则:

  1. 字符的比较

    • 字典序排序依赖于字符的ASCII值(或 Unicode 编码值),即每个字符都有一个唯一的数值表示;对于字母来说,a 的 ASCII 值比 b 小,b 比 c 小,依此类推
    • 比较字符串时,会逐字符进行比较;若某一字符不同,就依据该字符的大小顺序决定字符串的排序顺序
  2. 逐字符比较

    • 比如字符串 "apple" 和 "banana",首先比较第一个字母 a 和 b,因为 a 小于 b,所以 "apple" 排在 "banana" 前面。
    • 如果两个字符串的前几个字符相同,则继续比较下一个字符,直到出现不同的字符为止
  3. 长度比较:如果两个字符串的前缀完全相同,则较短的字符串排在较长的字符串前面;例如,"apple" 和 "applepie",因为 "apple" 是 "applepie" 的前缀,所以 "apple" 排在 "applepie" 前面

sort函数:

sort 是 C++ 标准库中提供的一个用于排序的函数,定义在 头文件中;它用于对一系列元素进行排序,默认是升序排序,也可以通过传入自定义的比较函数实现降序或其他特定的排序方式

sort 使用 快速排序堆排序 或 归并排序,因此其时间复杂度通常为 O(n log n),其中 n 是待排序元素的数量

sort 适用于任何能够通过 < 运算符进行比较的元素类型

按升序排序

sort(arr, arr + n);  // 对数组 arr 中的前 n 个元素进行升序排序

按降序排序

可以使用自定义的比较函数或 greater 函数对象来实现降序排序

sort(arr, arr + n, greater());  // 使用 greater() 按降序排序

在 C++ 中,greater 是一个函数对象(仿函数),定义在 头文件中;它用于执行 大于 操作,通常与 sort 等算法结合使用,以提供降序排序

示例代码:

#include 
#include 
#include 
#include 
using namespace std;

int main() {
    vector vec = {5, 2, 9, 1, 5, 6};

    // 默认升序排序
    sort(vec.begin(), vec.end());
    //vec.begin() 返回指向 vec 容器第一个元素的迭代器,表示排序的起始位置
    /* vec.end() 返回指向 vec 容器最后一个元素后面的迭代器,表示排序的结束位置
   (此位置不包含在排序中)*/
    
    cout << "升序排序: ";
    for (int num : vec) {
    /* vec 是一个 vector 类型的容器,包含一系列整数
    int num 表示每次循环中,num 将会依次取 vec 中的每个元素(即容器中的每个整数)
    循环体中的代码可以对 num 执行操作 */

        cout << num << " ";
    }
    cout << endl;

    // 降序排序
    sort(vec.begin(), vec.end(), greater());
    //greater() 会创建一个函数对象,表示“大于”比较操作
    //其作用是当第一个参数大于第二个参数时,返回 true ,否则返回 false 

    cout << "降序排序: ";
    for (int num : vec) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

仿函数是一个类,它重载了 operator(),使得这个类的对象可以像函数一样被调用;这个类的对象就称为 函数对象(或 仿函数

在 C++ 中,operator() 是一个特殊的运算符,被称为“函数调用运算符”;它允许对象像函数一样被调用;通过重载 operator(),我们可以让类的对象表现得像函数一样,从而增加类的灵活性和可操作性

示例代码:

#include 
using namespace std;

class Functor {
public:
    // 重载 operator(),使得对象能够像函数一样被调用
    void operator()(int x) {
        cout << "Calling object with argument: " << x << endl;
    }
};

int main() {
    Functor f;  // 创建 Functor 类型的对象

    f(42);  // 使用重载的 operator(),对象 f 被像函数一样调用
    //在这个例子中,Functor 类的对象 f 重载了 operator(),使得 f(42) 的调用变得合法
    //当调用 f(42) 时,实际上是调用了 operator()(int x),并将 42 作为参数传递进去

    return 0;
}

类(Class) 是面向对象编程(OOP)中的一个重要概念;它是一个模板或蓝图,用来定义一种类型;类描述了对象的属性(成员变量)和行为(成员函数);对象是类的实例,也就是类的具体表现

类的基本构成:

  1. 成员变量(属性):类中定义的变量,表示对象的状态
  2. 成员函数(方法):类中定义的函数,表示对象的行为或操作

类的定义通常包括成员变量、成员函数、构造函数、析构函数等

代码示例:

#include 
using namespace std;

class Person {
public:
    // 成员变量
    string name;
    int age;
    //name 和 age 是 Person 类的成员变量,表示每个 Person 对象的姓名和年龄

    // 构造函数:用于初始化对象
    Person(string n, int a) : name(n), age(a) {}
    //Person(string n, int a) 是一个构造函数,用于初始化对象的成员变量
    //构造函数在对象创建时被自动调用

    // 成员函数:用于操作对象
    void introduce() {
        cout << "Hello, my name is " << name << " and I am " << age << " years old." << endl;
    }
    //introduce() 是一个成员函数,用于打印对象的自我介绍
};

int main() {
    // 创建对象
    Person p1("Alice", 25);
    p1.introduce();  // 调用成员函数

    return 0;
}

类的特点:

  1. 封装:类将数据(成员变量)和操作数据的方法(成员函数)封装在一起,对外界隐藏了实现细节,只有接口暴露给外部使用
  2. 继承:类可以继承其他类的属性和行为,使得子类能够复用父类的代码,并可以对其进行扩展或修改
  3. 多态:通过继承和虚函数,类可以实现多态性,使得不同类型的对象可以通过相同的接口进行操作

类的构造与析构:

  • 构造函数:在对象创建时自动调用,用于初始化对象的状态
  • 析构函数:在对象销毁时自动调用,用于释放资源

类的实例(对象):

类是一个模板,实际创建出来的具体对象叫做类的实例;例如,上面的 p1 就是 Person 类的一个对象

你可能感兴趣的:(c++,华为od,算法)