初等排序 讲义

这里我们简述一下初等排序的学习内容:

  • 选择排序
  • 冒泡排序
  • 比较函数
  • 结构体函数

选择排序

(1)基本思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序排在待排序的数列的最前,直到全部待排序的数据元素排完。
(2)排序过程:
假设现在有 (n) 个数,他们分别是 (a_1, a_2, a_3, a_4, ……, a_n) ,我要将它们按照从小到大排序。

  • (1) 轮:我要选出最小的数作为 (a_1) ,于是我从 (2)(n) 遍历 (j) ,如果 (a_1 lt a_j) ,则交换 (a_1)(a_j) ,遍历结束后我们保证 (a_1) 是最小的数。
  • (2) 轮:我要选出次小的数作为 (a_2) ,于是我从 (3)(n) 遍历 (j) ,如果 (a_2 lt a_j) ,则交换 (a_2)(a_j) ,遍历结束后我们保证 (a_2) 是最次的数。
  • 如是循环……
    (3)选择排序代码示例:
#include <bits/stdc++.h>
using namespace std;
int n, a[100];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    for (int i = 1; i < n; i ++)
        for (int j = i+1; j <= n; j ++)
            if (a[i] > a[j])
                swap(a[i], a[j]);
    for (int i = 1; i <= n; i ++) cout << a[i] << " ";
    return 0;
}

这样我能保证在 (n-1) 轮比较后,我的数组能够按照从小到大的顺序排列好。这就是选择排序。
看上去有点像排老大——“我想当老大,不服的上来比一比,比过了你就当老大”。然后排完老大排老二,排完老二排老三,如是循环……
选择排序的时间复杂度是 (O(n^2))

冒泡排序

(1)基本思想:以 (n) 个人排队为例,从第 (1) 个开始,一次比较相邻的两个是否 逆序(“逆序”的意思是说:比如要按照元素从小到大排序,而此时相邻的两个元素中前者比后者大,则需要调换这两者的值),若逆序就交换两人,接着第 (2) 个和第 (3) 个比,若逆序就交换两人,接着第 (3) 个和第 (4) 比,若逆序就交换两人,……,直到 (n-1)(n) 比较,经过一轮比较后,则把最高的人排到最后,即将冒泡一样逐步冒到相应的位置。原 (n) 个人的排序就转换成 (n-1) 个人的排序问题。第二轮从第 (1) 个开始,一次比较相邻的两个人是否逆序对,若逆序就交换两人,直到 (n-1)(n) 比较。如此,进行 (n-1) 轮之后,这个数列就会变成有序的数列。
(2)排序过程:
假设现在有 (n) 个数,他们分别是 (a_1, a_2, a_3, a_4, ……, a_n) ,我要将它们按照从小到大排序。

  • (1) 轮:我开一个循环变量 (j)(1)(n-1) ,每次比较 (a_j)(a_{j+1}) ,如果 (a_j > a_{j+1}) ,则交换 (a_j)(a_{j+1})
    其实我这么循环是有原因的:一开始 (a_1)(a_2) 比较(如果逆序则交换)之后我能够保证 (a_2) 是前 (2) 个数中最大的;然后再拿 (a_2)(a_3) 比较(如果逆序则交换)之后我能够保证 (a_3) 是前 (3) 个数中最大的;……,最后我们拿 (a_{n-1})(a_n) 比较,其实是拿前 (n-1) 个数中的最大的和 (a_n) 比(如果逆序则交换),那么我们在第 (1) 轮结束的时候 (a_n) 就是我们数列中最大的数,并且它也恰好存储在了 (a_n) 中。
  • (2) 轮:我开一个循环变量 (j)(1)(n-2) ,每次比较 (a_j)(a_{j+1}) ,如果 (a_j > a_{j+1}) ,则交换 (a_j)(a_{j+1})
    同时,我这么操作一遍之后能够保证 (a_{n-1}) 是我们数列中次大的;
  • (3) 轮,我开一个循环变量 (j)(1)(n-3) ,每次比较 (a_j)(a_{j+1}) ,如果 (a_j > a_{j+1}) ,则交换 (a_j)(a_{j+1})
  • 如是循环……
    (3)冒泡排序代码示例:
#include <bits/stdc++.h>
using namespace std;
int n, a[100];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    for (int i = 1; i < n; i ++)
        for (int j = 1; j <= n-i; j ++)
            if (a[j] > a[j+1])
                swap(a[j], a[j+1]);
    for (int i = 1; i <= n; i ++) cout << a[i] << " ";
    return 0;
}

这样我能保证在 (n-1) 轮比较后,我的数组能够按照从小到大的顺序排列好。这就是冒泡排序。

比较函数和sort函数

比较函数用于确定数组中的排序规则,比如给我一个 int a[] 数组,我可以使用 algorithm 库提供给我的 sort 函数给他排序,比如,我调用:

sort(a, a+n);

能够给数组从 a[0]a[n-1] 按从小到大的顺序进行排序。因为 sort 函数就是按照默认从小到大的顺序来给数组中的元素进行排序的。
但是如果我想要使用 sort 函数来给数组中的元素按照从大到小的顺序排序呢?这个是用我们需要自定义一个比较函数,并且将函数名作为 sort 函数的第 (3) 个参数传递进去。
例如,我下面定义了一个名为 cmp 的比较函数,他里面有两个参数 ab ,这个函数返回 true 说明 a 应该排在 b 前面,返回 false 说明 b 应该排在 a 后面:

bool cmp(int a, int b) {
    return a > b;
}

然后将这个函数的名字作为参数传递给 sort 函数调用即可:

sort(a, a+n, cmp);

这样就能保证将 a[0]a[n-1] 按照从大到小排序了。

特别的,对于结构体来说,因为结构体不知道怎么比较大小,所以需要你编写比较函数并放到 sort 函数里面去给他进行排序。

说明:其实对于结构体来说,也有办法让它直到怎么比较大小,就是给结构体定义一个小于号( (lt) ),这种方法叫做“运算符重载”,但是运算符重载放在我们普及组初赛相对来说超纲了,所以这里就不过多的介绍“运算符重载”这个C++高级知识点了,目前的阶段是好好掌握比较函数。

原文地址:https://www.cnblogs.com/zifeiynoip/p/11450537.html