一、排序
1、排序的目的:把数组中的各个元素按照从小到大或者从大到小的顺序排列(也有可能是
别的顺序),排序后的结果保存在同一个数组中。
例如:2 7 9 5 1 从小到大排序后的结果是 1 2 5 7 9
2、排序的方法:选择排序法、冒泡排序法、…
二、选择排序法
1.
第一轮从 a[0]~a[n-1]中找到最小值,与 a[0]交换值,把最小值放在 a[0]的位置
第二轮从 a[1]~a[n-1]中找出最小值,与 a[1]交换值,把最小值放在 a[1]的位置
…
最后一轮从 a[n-2]~a[n-1]中找出最小值,与 a[n-2]交换值,把最小值放在 a[n-2]的位置
n-1 轮后,前 n-1 个元素放好了,最后的 a[n-1]自然是最大的元素
核心问题:在一堆数组元素中找出最小值对应的下标。
例:
使用选择排序法,对随机 7 个整数进行从小到大的排序
初始: [
49
38 65 97 76
13
27]
一次:
13
[
38
65 97 76 49
27
]
二次:
13 27
[
65
97 76 49
38
]
三次:
13 27 38
[
97
76
49
65]
四次:
13 27 38 49
[
76
97
65
]
五次:
13 27 38 49 65
[
97
76
]
六次:
13 27 38 49 65 76
[97]
2.选择排序法核心代码(元素类型:
int
、用函数select实现)
//使用选择排序法,把长度为 n 的整型数组 a 进行从小到大的排序
void selectSort(int a[ ], int n) //注意把数组变量定义成函数形参时的写法
{
for(int i = 0; i < n-1; i++)
{
//在 a[i]到 a[n-1]中,找到最小的元素对应的下标 min,交换 a[min]和 a[i]
int min=i; //假设第 i 个元素最小,min 负责记录当前看到的最小元素下标
for(int j = i+1; j < n; j++) //看看余下的其他元素有没有更小的,j 代表下标
{
if(a[j]<a[min])
{
min=j; //如果看到更小的,就修改 min 值 } }
swap(a[i],a[min]); //这时 a[min]是最小的,与 a[i]交换就换到了应该的位置
}
}
3、选择排序法核心代码(元素类型:int、另一种写法)
思想:一旦发现大小关系不对(即下标在前面的 a[i]比下标在后面的 a[j]大),则交换
void selectSort(int a[ ], int n)
//如果元素类型 double,则 void selectSort(double a[ ], int n)
{
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i] > a[j])
{
swap(a[i], a[j]);
}
}
}
}
4、用函数模板实现选择排序(元素类型:任意)
template<typename T>
void selectSort(T a[ ], int n)
{
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i] > a[j])
{
swap(a[i], a[j]);
}
}
}
}
5、选择排序法完整代码
例:输入一个正整数 m,然后输入 m 个整数,对这 m 个整数使用选择排序法从小到大排序,
然后输出排序后的 m 个整数,每个整数输出后都要换行。
#include<iostream>
using namespace std;
template<typename T>
void selectSort(T a[ ], int n)
{
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i] > a[j])
{
swap(a[i], a[j]);
}
}
}
}
int main()
{
int m;
cin >> m;
int *a = new int[m];
for (int i = 0; i < m; i++)
{
cin >> a[i];
}
selectSort(a, m); //注意调用函数时,把数组变量当函数实参的写法
for (int i = 0; i < m; i++)
{
cout << a[i] << endl;
}
delete[ ]a;
return 0;
}
三、冒泡排序法
1、使用冒泡排序法,把长度为 n 的整型数组 a 从小到大排序:
每次都是两个下标相邻的数字进行比较,如果大小关系不对(即前一个数比后一个数大),
则交换它们,以保证前一个数小于后一个数。
每轮循环都可以产生一个当前最大的数,这个数在以后的循环中不参与比较。
例:用冒泡法对 5 个整数进行从小到大的排序
初始:
[9 8 5 7 6]
第一轮:
[
8 9
5 7 6]
[8
5 9
7 6]
[8 5
7 9
6]
[8 5 7
6
(
9
)]
第一轮结束后,最后一个数字(9)可以确定是最大的数字。
第二轮:
[
5 8
7 6 (9)]
[5
7 8
6 (9)]
[5 7
6
(
8
) (9)]
第二轮结束后,倒数第二个数字(8)可以确定是第二大的数字。
第三轮:
[
5 7
6 (8) (9)]
[5
6
(
7
) (8) (9)]
第三轮结束后,倒数第三个数字(7)可以确定是第三大的数字。
第四轮:
[
5
(
6
) (7) (8) (9)]
第四轮结束后,倒数第四个数字(6)可以确定是第四大的数字。
最后一个数字(5)一定是第五大的数字(即最小的数字)
2、选择冒泡排序法核心代码(元素类型:
int
、用函数实现)
//使用冒泡排序法,把长度为 n 的整型数组 a 进行从小到大的排序
void bubbleSort(int a[ ], int n)
{
for (int i = n - 2; i >= 0; i--)
{
for (int j = 0; j <= i; j++)
{
if (a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
}
}
}
}
代码解读:
(1)当 i = n - 2 时,j 的循环从 0 到 n-2,j 的循环里进行的比较有:
a[0]和 a[1],a[1]和 a[2],a[2]和 a[3],…,a[n-2]和 a[n-1]
那么 a[0]到 a[n-1]中最大的数字最终保存在了 a[n-1]中。
(2)当 i = n - 3 时,j 的循环从 0 到 n-3,j 的循环里进行的比较有:
a[0]和 a[1],a[1]和 a[2],a[2]和 a[3],…,a[n-3]和 a[n-2]
那么 a[0]到 a[n-2]中最大的数字最终保存在了 a[n-2]中。
…
(3)当 i 最后一次循环等于 0 时,j 的循环只循环一次(j=0),j 的循环里进行的比较有:
a[0]和 a[1],那么 a[0]和 a[1]中最大的数字最终保存在了 a[1]中。
3、用函数模板实现冒泡排序(元素类型:任意)
template<typename T>
void bubbleSort(T a[], int n)
{
for (int i = n - 2; i >= 0; i--)
{
for (int j = 0; j <= i; j++)
{
if (a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
}
}
}
}
4、冒泡排序法完整代码
例:输入一个正整数 m,然后输入 m 个整数,对这 m 个整数使用冒泡排序法从小到大排序,
然后输出排序后的 m 个整数,每个整数输出后都要换行。
#include<iostream>
using namespace std;
template<typename T>
void bubbleSort(T a[], int n)
{
for (int i = n - 2; i >= 0; i--) {
for (int j = 0; j <= i; j++)
{
if (a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
} } } }
int main()
{
int m;
cin >> m;
int* a = new int[m];
for (int i = 0; i < m; i++)
{
cin >> a[i];
}
bubbleSort(a, m);
for (int i = 0; i < m; i++)
{
cout << a[i] << endl;
}
delete[ ]a;
return 0;
}
说明:如果是固定长度的数组,例如 10 个浮点数从小到大排序,那么只需要修改主函数
const int m = 10;
double a[m];
//...
并且删除 delete[ ]a;
此时 bubbleSort 函数或者 selectSort 函数,如果使用函数模板定义,不需要修改函数代码。