前言:
选择排序的思路和我们人脑的思维很相似,是每次都挑选出符合要求的数放到合理的位置。时间复杂度和冒泡排序相同。
(冒泡排序的优点)那么冒泡排序的优点是什么呢?它的优点是进行了一定次数的冒泡以后,数组会得到一个整体相对比较有序的状态。
时间复杂度O(N^2)
空间复杂度O(1)
一.单选择排序
思路:
遍历寻找数列中最大(最小)的元素,与数列最后一个元素交换位置
因为我们要交换数,所以要记录的是下标的位置,而不是数字的值,但同时,必须要保持更新一个max(min),来确认当前的是最值 所对应的下标。
因此代码如下
void Single_SelectionSort(int *a, int length)
{
int i, j;
int max_subscript;
//最后一次剩下一个数不用进行比较,所以i < length - 1
for (i = 0; i < length - 1; i++)
{
int max = -2e9;
/*
为什么选择排序中j为什么不是j < length - i - 1 呢,而冒泡是呢?
因为冒泡会用到a[j+1],有可能越界,所以得-1避免掉。
*/
for (j = 0; j < length - i; j++)
{
if (a[j] > max)
{
max = a[j];
max_subscript = j;
}
}
swap(&a[max_subscript],&a[length - i - 1]);
}
}
二.双选排序(对选择排序的效率优化)
这是一次只选一个的单边选择排序,反正不需要开辟额外的数组,空间复杂度是O(1)那么我们为什么不用min和max同时对两边进行排序呢?这样效率会快上一倍,同时复杂度不变!
但是呢,这边里头有个很重要的思维点,想了好久好久。我想可能后面也会遇到。我标记在代码段中了,大家可以先想想。解释我放代码下头,同样代码细节也写在代码注释中:
void Double_SelectionSort(int *a,int length)
{
int i, j;
int max_subscript = 0;
int min_subscript = 0;
for (i = 0; i < length/2; i++)//循环次数由于每次减少两个,所以只需要长度整除2的次数
{
int max = -2e9;
int min = 2e9;
for (j = i; j < length - i; j++)// j = i是因为前头的位置被排序好的值占了
{
if (a[j] < min)
{
min = a[j];
min_subscript = j;
}
if (a[j] > max)
{
max = a[j];
max_subscript = j;
}
}
swap(&a[i], &a[min_subscript]);
if (max_subscript == i)//思维点就在这里
max_subscript = min_subscript;
swap(&a[length - i - 1],&a[max_subscript]);
}
}
可以试着删掉那一段,我们会发现数据时对时错。原因是我们的两次交换他是有先后顺序的。如果是同时交换,那不存在问题,可是如果第一次交换以后交换的数据,正是我们下一次交换用的数据,我们下一次交换使用的下标就出现了偏差,但庆幸的是数据不会改变,这正是我们标记下标而不是用辅助数组的好处。所以,我们要多进行一次判断,判断是否有覆盖数据位置,如果有,进行一定处理,没有正常继续。
整体代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 30
//之前写过了,就不再全写一遍了
void generate_random_number(int*, int, int);
void swap(int*, int*);
void Single_SelectionSort(int *a, int length)//单选排序
{
int i, j;
int max_subscript;
for (i = 0; i < length - 1; i++)
{
int max = -2e9;
for (j = 0; j < length - i; j++)
{
if (a[j] > max)
{
max = a[j];
max_subscript = j;
}
}
swap(&a[max_subscript],&a[length - i - 1]);
}
}
void Double_SelectionSort(int *a,int length)//双选排序
{
int i, j;
int max_subscript = 0;
int min_subscript = 0;
for (i = 0; i < length/2; i++)
{
int max = -2e9;
int min = 2e9;
for (j = i; j < length - i; j++)
{
if (a[j] < min)
{
min = a[j];
min_subscript = j;
}
if (a[j] > max)
{
max = a[j];
max_subscript = j;
}
}
swap(&a[i], &a[min_subscript]);
if (max_subscript == i)
max_subscript = min_subscript;
swap(&a[length - i - 1],&a[max_subscript]);
}
}
int main()
{
int arr[N + 10] = { 0 };
generate_random_number(arr, 0, 1024);
Double_SelectionSort(arr,N);
printf("排序后数列:\n");
for (int i = 0; i < N; i++)
printf("%d ", arr[i]);
return 0;
}
测试结果如下:
至此,Single_SelectionSort 与 Double_SelectionSort 完成。