一、选择排序回顾
选择排序的逻辑其实是将数据分为待排序数据和已排序数据,每次从未排序部分找出最小(大)元素,放到已排序序列的末尾。我们以从小到大顺序排列为例:2,3,4,1,6,9,0,5,7 ,从数组中找到最小元素,记录其下标,然后将它和最左边元素进行交换,
第一次:变成0,3,4,1,6,9,2,5,7;0就属于已排序元素;第二次:找到最小值为1,记录其下标,和未排序元素中的首部元素(也就是已排序的尾部)进行交换,变成0,1,3,4,6,9,2,5,7,此时0,1就是已排序的序列,3,4,6,9,2,5,7就是未排序序列,接下来重复上述操作即可;
那代码怎么写呢,利用双重循环,外面一层for循环是用来记录已排序数组,也就是i = 0时,是第一次排序的交换位置,i = 1时,第二次交换位置,以此类推;
那内层循环呢,由于外层循环是从i位置插入,那内层循环就是从i+1的位置开始,那么我们就可以先定义最小值minV是arr[i],index = i,如果有元素比这个位置元素小,就进行交换,如果没有,就说明i下标位置元素就是最小值,不用交换,直接让外层循环i++即可;最后剩余一个元素,肯定就是最小元素,所以外层循环的次数就是n-1次,但是内层循环终止条件必须是下标为n-1,因为每次都必须将所有元素进行比较,下标为n-1包含在其中;
这里可能有点绕,外层循环是负责元素插入的,内层循环是负责比较元素的;当外层循环剩余最后一个元素时,肯定不需要再交换了;
代码实现
void select(int* arr, int n) {
int index, minV;
for (int i = 0; i < n-1; i++) {
minV = arr[i];
index = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < minV) {
minV = arr[j];
index = j;
}
}
swap(&arr[index], &arr[i]);
}
}
注意:由于跨元素交换,所以选择排序是一个不稳定的排序算法;
二、选择排序优化
由于每次都是在其中选择一个最小的值,那么我们能不能再选择一个最大值,将它放在序列的末尾,这样一来,序列最前面排最小值,序列后面排序最大值,每次从未排序序列中找2个元素,就能省去将近一半的时间;
但是要注意,由于我们每次交换是一次循环中交换2个数,如果我们左边L的位置是最大值,我们先进行交换swap(&arr[indMIN],&arr[L]);那后面进行最大值交换时,indMAX下标的值已经被换到indMIN的位置,所以我们要分情况进行交换,避免第一个最小值交换影响后面最大值交换(因为C语言中交换是有先后顺序的,并不是两个元素同时交换)。
代码实现
void selectPro(int* arr, int left,int right) {
int maxV, minV, L = left, R = right;
int n = right - left + 1;
int indMAX,indMIN;
for (L, R; L < R;L++,R--) {
indMIN = L;//最左边元素
indMAX = R;//最右边元素
maxV = arr[R];//初始化最大值为最右边元素
minV = arr[L];//初始化最小值为最左边元素
for (int j = L + 1; j <= R; j++) {
if (minV > arr[j]) {//如果存在比minV小的数,就记录对应值和下标
minV = arr[j];
indMIN = j;
}
if (maxV < arr[j]) {//如果存在比maxV大的数,就记录对应值和下标
maxV = arr[j];
indMAX = j;
}
}
if (indMAX == L) {//如果最大值下标在左边L下标的位置上
swap(&arr[indMIN], &arr[L]);
swap(&arr[indMAX], &arr[indMIN]);
}
else {//如果不重叠
swap(&arr[indMIN], &arr[L]);
swap(&arr[indMAX], &arr[R]);
}
}
}

这样一来就实现了选择排序的优化,如果有问题,欢迎在评论区留言。
1485

被折叠的 条评论
为什么被折叠?



