排序:将一组杂乱无章的数据按照一定的规律(升序或者降序)组织起来
排序码:用来作为排序的依据,是数据元素的一个属性域
排序算法的稳定性:符合排序码的元素相对位置不发生变化
各种常见排序算法的分类:
1.冒泡排序:
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定
算法思路:
(1)按照升序规则,从前往后冒:
[0, bound) 是等待排序的区间
[bound, size) 是已经有序的区间 (bound,cur 从 0 开始,bound < size -1, cur > size - bound - 1,cur 从前往后,要小于有效区间)
从第一个出发,碰见比自己大的就交换位置,交换后继续向后走,直到走到最后,这个时候最大的元素就在最后,第二次还是从第一个开始冒,碰见比自己大的就交换,直到比较倒数第二个(因为最后一个已经是最大的了,不需要在比较)……直到每个元素都比较,每次冒出一个未排序区间最大的元素,下一次就减少一次比较。第一重循环就是一共有多少个元素,第二重循坏是一个元素要比较多少次。
// 交换函数
void Swap1(int* a, int* b)
{
*a = *a ^ *b;
*b = *b ^ *a;
*a = *a ^ *b;
return;
}
void Swap2(int* a, int* b)
{
*a = *a + *b;
*b = *a - *b;
*a = *a - *b;
return;
}
// (以下所有代码使用的交换函数无特别标注,都是Swap3 )
void Swap3(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
// 冒泡排序
// 从前向后冒,降序
// [bound, size) 代表有序区间
// [0, bound) 代表等待排序区间
// cur = 0 从前向后排序
void BubbleSort2(int arr[], int size)
{
if(arr == NULL || size <= 0){
return;
}
int bound = 0;
for(; bound < size - 1; bound ++){
int cur = 0;
for(; cur < size - bound - 1; cur ++){
if(arr[cur] < arr[cur + 1]){
//Swap2(&arr[cur], &arr[cur + 1]);
Swap3(&arr[cur], &arr[cur + 1]);
}
}
}
return;
}
(2)按照降序规则,从后往前冒:
[0, bound) 是已经有序的区间
[bound, size) 是等待排序的区间 (bound 从0 开始,cur 从 size - 1 开始,bound < size - 1, cur > bound,cur 从后往前,要大于有效区间)
从最后一个出发,碰见比自己大的就交换位置,交换后继续向前走,直到走到第一个元素,此时第一个元素就是最大的,第二次还是从最后一个开始,直到第二个位置(不需要和第一个比较),这样一直到最后一个,每冒一次,下次就少比较一次。
// 从后往前冒泡,升序
// [0, bound) 代表有序区间
// [bound, size) 代表等待排序区间
// cur = size - 1 从后向前排序
void BubbleSort1(int arr[], int size)
{
if(arr == NULL || size <= 0){
return;
}
int bound = 0;
for(; bound < size - 1; bound ++){
int cur = size - 1;
for(; cur > bound; cur --){
if(arr[cur - 1] > arr[cur]){
Swap1(&arr[cur - 1], &arr[cur]);
}
}
}
return;
}
2.选择排序:
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
算法思路:
(从前向后,升序)每次从边界出发,第一个元素作为擂主(不动),和第二个元素进行比较,如果擂主小,那么不交换值,cur 继续向后走,下一个值继续和擂主比,直到最后一个元素和擂主比较完,这个时候第二个元素称为擂主,从第三个元素开始比较,直到比到最后。每一次打擂台都有可能打乱原有符合排序规则元素之间的原有位置,所以不稳定。
// 选择排序 升序
// [0, bound) 是有序区间
// [bound, size) 是待排序区间
void SelectSort(int arr[], int size)
{
if(arr == NULL || size <= 0){
return;
}
int bound = 0;
for(; bound < size; bound ++){
int cur = bound + 1;
for(; cur < size; cur ++){
if(arr[bound] > arr[cur]){
Swap(&arr[bound], &arr[cur]);
}
}
}
return;
}
3.插入排序:
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定
算法思路:
(升序) [0, bound) 是已经有序的区间,[bound, size) 是等待排序的区间,bound从 1 开始,cur (cur = bound )来辅助理解完成,前面为一个有序的区间,每次从bound 位置的元素,和有序区间里的元素进行比较,找到一个合适的位置时(边找边搬运,有一个元