选择排序优化
一、选择排序回顾
选择排序的逻辑其实是将数据分为待排序数据和已排序数据,每次从未排序部分找出最小(大)元素,放到已排序序列的末尾。我们以从小到大顺序排列为例: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]);}}
}
这样一来就实现了选择排序的优化,如果有问题,欢迎在评论区留言。
