STL std::sort

  • 概述

    • 在 C++ 中,std::sort是一个非常有用的算法函数,它用于对给定范围内的元素进行排序。这个函数定义在<algorithm>头文件中。
  • 函数原型

    • template< class RandomIt > void sort( RandomIt first, RandomIt last );
    • template< class RandomIt, class Compare > void sort( RandomIt first, RandomIt last, Compare comp );
    • 其中firstlast是迭代器,它们定义了要排序的元素范围(左闭右开区间,即[first, last))。RandomIt是一个随机访问迭代器类型,它可以是指针(比如指向数组元素的指针)或者是符合随机访问迭代器要求的容器迭代器(如std::vectorstd::array等容器的迭代器)。第二个重载函数中的comp是一个比较函数,用于自定义元素的比较规则。
  • 使用示例(默认升序排序)

    • 下面是一个对std::vector中的整数进行排序的例子:
      #include <iostream>
      #include <vector>
      #include <algorithm>
      int main() {
          std::vector<int> numbers = {5, 2, 8, 1, 9};
          std::sort(numbers.begin(), numbers.end());
          for (int num : numbers) {
              std::cout << num << " ";
          }
          return 0;
      }

      在这个例子中,numbers.begin()numbers.end()定义了要排序的范围,也就是整个numbers向量。std::sort函数会按照升序对向量中的元素进行排序。输出结果将是1 2 5 8 9

    • 自定义比较函数(降序排序)

    • 如果想要按照降序对元素进行排序,可以提供一个自定义的比较函数。例如:
      #include <iostream>
      #include <vector>
      #include <algorithm>
      bool compare(int a, int b) {
          return a > b;
      }
      int main() {
          std::vector<int> numbers = {5, 2, 8, 1, 9};
          std::sort(numbers.begin(), numbers.end(), compare);
          for (int num : numbers) {
              std::cout << num << " ";
          }
          return 0;
      }

      这里定义了一个compare函数,它接受两个整数ab,当a > b时返回true。将这个函数作为std::sort的第三个参数传递进去,就可以让std::sort按照降序对numbers向量中的元素进行排序。输出结果将是9 8 5 2 1

  • 时间复杂度

    • std::sort通常实现为一种混合排序算法,例如 Introsort(内省排序)。它的平均时间复杂度是,其中n是要排序的元素数量。在最坏情况下,时间复杂度也是,这比一些简单的排序算法(如冒泡排序在最坏情况下的)要高效得多。
  • 稳定性

    • std::sort是不稳定的排序算法。所谓不稳定,是指在排序过程中,相等元素的相对顺序可能会改变。例如,有一个包含(1, 'a')(1, 'b')的数组(这里假设第一个元素是整数,用于排序,第二个元素是字符用于区分),经过std::sort排序后,不能保证(1, 'a')(1, 'b')的相对顺序不变。如果需要稳定排序,可以考虑使用std::stable_sort,它的时间复杂度在平均和最坏情况下也是,但它保证相等元素的相对顺序不变。

 

sort中使用 lambda

 lambda 表达式简介

lambda 表达式是 C++ 11 引入的一种匿名函数机制,它的基本语法形式如下:

 

[capture list](parameter list) -> return type {
    function body
}
  • capture list(捕获列表):用于指定在 lambda 函数体中可以访问的外部变量。它可以为空,表示不捕获任何外部变量;也可以包含按值捕获(如[x],这里x是外部变量,会将其值复制到 lambda 内部使用)或者按引用捕获(如[&y]y是外部变量,在 lambda 内部通过引用访问它,对其修改会影响外部的变量值)等不同方式。
  • parameter list(参数列表):和普通函数的参数列表类似,定义了 lambda 函数接受的参数。
  • return type(返回类型):可以显式指定返回类型,如果不指定,编译器会根据函数体中的返回语句自动推导返回类型(对于简单情况通常能正确推导)。
  • function body(函数体):包含了具体要执行的语句,实现相应的功能

使用 lambda 表达式结合std::sort进行排序

示例一:对简单数组进行降序排序

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

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9};
    // 使用lambda表达式自定义降序排序规则
    std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
        return a > b;
    });
    for (int num : numbers) {
        std::cout << num << " ";
    }
    return 0;
}

在上述代码中,std::sort的第三个参数使用了一个 lambda 表达式。这个 lambda 表达式接受两个int类型的参数ab,并返回a > b的结果,意味着按照降序对numbers向量中的元素进行排序。

示例二:对包含结构体的数组根据结构体成员进行排序

假设有如下结构体表示学生信息:

struct Student {
    std::string name;
    int score;
};

现在要根据学生的成绩对学生结构体数组进行排序,可以这样写:

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

struct Student {
    std::string name;
    int score;
};

int main() {
    std::vector<Student> students = {
        {"Alice", 80},
        {"Bob", 90},
        {"Charlie", 70}
    };
    // 使用lambda表达式按照学生成绩升序排序
    std::sort(students.begin(), students.end(), [](const Student& s1, const Student& s2) {
        return s1.score < s2.score;
    });
    for (const Student& s : students) {
        std::cout << s.name << " " << s.score << std::endl;
    }
    return 0;
}

示例三:使用捕获列表的情况

假设我们有一个外部变量,想要在排序的 lambda 表达式中使用它来影响排序规则,比如根据一个外部给定的阈值来筛选元素进行排序:

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

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9};
    int threshold = 5;
    // 使用lambda表达式结合捕获外部变量,对大于阈值的元素升序排序
    std::sort(numbers.begin(), numbers.end(), [threshold](int a, int b) {
        // 只比较大于阈值的元素
        if (a > threshold && b > threshold) {
            return a < b;
        }
        return false;
    });
    for (int num : numbers) {
        std::cout << num << " ";
    }
    return 0;
}

在这个例子中,lambda表达式的捕获列表[threshold]按值捕获了外部变量threshold,然后在 lambda 函数体中根据这个阈值来决定元素的比较和排序逻辑,这里只对大于阈值的元素进行升序排序的比较,其他情况返回false(表示不交换顺序)。

总之,通过使用 lambda 表达式与std::sort结合,可以方便快捷地根据各种复杂或简单的自定义规则来对容器中的元素进行排序,增强了排序操作的灵活性。

std::sort的示例代码

 

以下是一些不同场景下使用 std::sort 的示例代码,涵盖了对基本数据类型数组、结构体数组以及自定义比较规则等情况的排序操作:

示例一:对整数数组进行升序排序

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

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9};
    std::sort(numbers.begin(), numbers.end());
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}

在这个示例中,使用 std::sort 对 std::vector 容器中的整数元素按照默认的升序规则进行排序,然后通过循环输出排序后的数组元素,输出结果为 1 2 5 8 9

示例二:对字符数组进行降序排序(使用自定义比较函数)

#include <iostream>
#include <algorithm>
#include <cstring>

// 自定义比较函数,用于实现字符的降序比较
bool compareChars(char a, char b) {
    return a > b;
}

int main() {
    char characters[] = "hello";
    int size = std::strlen(characters);
    std::sort(characters, characters + size, compareChars);
    std::cout << characters << std::endl;
    return 0;
}

这里定义了 compareChars 函数来指定字符的降序比较规则,然后使用 std::sort 对字符数组 characters 进行排序,最终输出排序后的字符数组,结果为 "olleh"

示例三:对结构体数组根据结构体成员进行排序

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

// 定义结构体表示学生信息
struct Student {
    std::string name;
    int score;
};

// 自定义比较函数,按照学生成绩升序排序
bool compareStudents(const Student& s1, const Student& s2) {
    return s1.score < s2.score;
}

int main() {
    std::vector<Student> students = {
        {"Alice", 80},
        {"Bob", 90},
        {"Charlie", 70}
    };
    std::sort(students.begin(), students.end(), compareStudents);
    for (const Student& s : students) {
        std::cout << s.name << " " << s.score << std::endl;
    }
    return 0;
}

此示例定义了 Student 结构体来表示学生信息,包含姓名和成绩两个成员。通过自定义 compareStudents 函数,按照学生成绩的升序规则,使用 std::sort 对 students 结构体数组进行排序,之后循环输出排序后的学生信息,输出顺序会按照成绩从小到大排列。

示例四:使用函数对象(仿函数)实现复杂比较规则的排序

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

// 定义结构体表示商品信息
struct Product {
    std::string name;
    int quantity;
    double price;
};

// 定义函数对象(仿函数),按照商品库存数量降序排序,如果库存相同则按照价格升序排序
class ProductComparator {
public:
    bool operator()(const Product& p1, const Product& p2) const {
        if (p1.quantity!= p2.quantity) {
            return p1.quantity > p2.quantity;
        }
        return p1.price < p2.price;
    }
};

int main() {
    std::vector<Product> products = {
        {"Apple", 10, 5.5},
        {"Banana", 8, 3.2},
        {"Orange", 10, 4.0}
    };
    std::sort(products.begin(), products.end(), ProductComparator());
    for (const Product& p : products) {
        std::cout << p.name << " " << p.quantity << " " << p.price << std::endl;
    }
    return 0;
}

在这个示例中,针对 Product 结构体表示的商品信息,定义了 ProductComparator 函数对象,其重载的 operator() 函数实现了复杂的比较规则:先按照商品库存数量降序排序,如果库存数量相同,则按照价格升序排序。使用 std::sort 结合这个函数对象对 products 向量中的商品结构体进行排序,最后输出排序后的商品信息。

这些示例展示了 std::sort 在不同场景下的应用,你可以根据实际需求灵活运用该函数来实现各种排序操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听音乐就好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值