1. 冒泡排序
(升序排列)
- 对长度为n的数组,从左到右扫描n-1次。
- 每一次从左到右较上一次少扫描最后那个元素。(因为上一次循环已经挑出当时最大的元素,并放在最右边了,那一部分扫描也不会有任何顺序的改变)
- 如果过程中右侧元素比左侧元素大,交换顺序。
(计划补一张流程图方便理解)
#include<iostream>
using namespace std;
template<class T>
void BubbleSort(T list[], const int n)
{
// 需要从左到右扫描n-1遍
for(int i=0; i<n-1; i++)
// 每次后i个已经排好序了,终止条件多减个i
for(int j=0; j<n-i-1; j++)
// 如果扫描过程中,左边比右边大,交换
if(list[j] > list[j+1])
swap(list[j], list[j+1]);
}
int main()
{
int a[] = {2,4,6,8,0,1,3,5,7,9};
BubbleSort<int>(a, 10);
//输出结果
for(int k=0; k<10; k++)
{
cout << a[k] << " ";
}
cout << endl;
return 0;
}
2.选择排序
(升序排列)
选择排序与冒泡排序区别的是,
冒泡排序把最大的元素往右移动,而且每次都执行实打实的交换,效率很低。
选择排序把最小的元素往左移动,每轮循环只记录最小的索引,结束次轮循环后再执行交换。
(计划补一张流程图方便理解)
#include<iostream>
using namespace std;
template<class T>
void SelectSort(T list[], const int n)
{
// 扫描 n-1 遍
for(int i=0; i<n-1; i++)
{
// 设置最小索引为开始索引
int min = i;
// 从开始索引之后第一个开始扫描
for(int j=i+1; j<n; j++)
// 如果遇到了比当前最小索引更小的,替换记录的索引
if(list[j]<list[min])
min = j;
// 最后把i出的和记录的最小索引替换
swap(list[i],list[min]);
}
}
int main()
{
int x[] = {1,3,4,6,7,9,5};
SelectSort<int>(x, 10);
// 输出结果
for(int k=0; k<7; k++)
{
cout << x[k] << " ";
}
cout << endl;
return 0;
}
3. 插入排序
(升序排列)
- 把数组的左半部分认定为暂时排好的队伍,从右半部分抽出第一个元素和左边的元素从后往前分别比较。
- 如果右半部分抽出的第一个元素比左半部分当前的元素小,则左半部分数组中已经比较完元素分别往右赋值1个长度(俗称向右移动距离1),直到找到抽出的元素找到属于应该在的位置。
每轮循环过后,左半部分的数组长度加1,右半部分数组长度减1,直到左半部分数组完全把右半部分数组吞并,全部排序完成。
(计划补一张流程图方便理解)
#include<iostream>
using namespace std;
template<class T>
void InsertionSort(T* a, int n)
{
// 从索引1开始,把索引0认为是左边的起始数组
for(int i = 1; i<n; i++)
{
// key是待插入的元素(右边数组的第一个元素)
T key = a[i];
// j为左边数组最后面的元素的索引
int j = i - 1;
while (j >= 0 && key < a[j])
{
// 左边数组赋值往右移位置
a[j+1] = a[j];
j--;
}
// key把左边数组空的坑填上(属于它自己真实的位置)
a[j+1] = key;
}
}
int main()
{
double a[] = {2.1, 4.0, 6.7, 8.2, 1.1, 3.4, 5.8, 7.0};
InsertionSort<double>(a, 8);
for(int k=0; k<8; k++)
{
cout << a[k] << " ";
}
cout << endl;
return 0;
}