概念
前面学习了冒泡排序,其实我一直将冒泡和选择搞混淆,因为冒泡也是每次循环找到最大或者最小的元素,但是冒泡多了一步交换。选择排序就不同,每次循环找到最大值或者最小值,最后才将其放到队尾或者队首。
说这这里,选择排序的概念就很清楚了,有两个循环,外循环遍历所有的元素,内循环遍历找到最大值,内循环完成后,将当前循环的最大值移动到队尾。外循环完成后,排序也就完成了。示意图如下:
代码
代码来说就比较简单了,甚至比冒泡排序还要简单。如下:
public static void selectionSort(int[] arr) {
int length = arr.length;
int minIndex = 0;
//循环到数组到前一个元素即可。
for (int i = 0; i < length - 1; i++) {
minIndex = i;
for (int j = i + 1; j < length; j++) {
if (arr[j] < arr[minIndex]) minIndex = j;
}
BaseSort.swap(arr, i, minIndex);
}
}
看代码也能看出来,选择排序对于数组中元素的位置有破坏,即大家常说的选择排序不稳定。(如果数组中两个元素的位置经过排序后发生了变化,这种算法就是不稳定的)冒泡排序因为每次比较都可能交换了位置,所以冒泡排序后的数组元素的位置仍然能够保持之前的位置。(相同的元素)这也是选择排序的一个缺点吧。
优化
选择排序的优化思路也比较好想,就是在比较多过程中同时找到最大值和最小值。这样会比原有的写法快一点。代码如下:
public static void selectionSort2(int[] arr) {
int length = arr.length;
int minIndex, maxIndex;
for (int i = 0; i < length; i++) {
minIndex = maxIndex = i;
for (int j = i + 1; j < length - i; j++) {
if (arr[j] < arr[minIndex]) minIndex = j;
if (arr[j] > arr[maxIndex]) maxIndex = j;
}
if (minIndex == maxIndex) break;
BaseSort.swap(arr, i, minIndex);
//防止最大值为i的情况。
if (maxIndex == i) {
BaseSort.swap(arr, length - 1 - i, minIndex);
} else {
BaseSort.swap(arr, length - 1 - i, maxIndex);
}
}
}
代码中间唯一需要注意的地方也写了注释了,其他就没有什么可讲的了。代码我自己测试了几个用例,没有发现什么问题,但是测试较少,怀疑还是存在一些没有考虑到的情况。这里也欢迎大家指正。
题目
还是把选择排序练习一下。这里上两个题目。
思路比较简单,利用选择排序,找最大值,如果是第k大大元素,就返回,否则继续排序。优化的点其实也有:可以判断k是否大于数组中间长度,然后决定是找最大还是最小,能一定程度减少一些运算。但是因为时间问题,我实现的代码并没有做这个优化。具体的代码如下:
public int findKthLargest(int[] nums, int k) {
int length = nums.length;
int maxIndex;
for (int i = 0; i < length; i++) {
maxIndex = i;
for (int j = i + 1; j < length; j++) {
if (nums[j] > nums[maxIndex]) maxIndex = j;
}
if (i + 1 == k) return nums[maxIndex];
int tmp = nums[maxIndex];
nums[maxIndex] = nums[i];
nums[i] = tmp;
}
return 0;
}
这个也很简单,思路是直接用选择排序,可以用二元选择排序。没有什么可讲的点,但是因为力扣的时间限制,该代码没有通过。思路是正确的,后面这道题也可以选择其他时间复杂度较低的排序算法,例如:快速排序,归并排序等。选择排序思路如下:
public int[] sortArray(int[] nums) {
int length = nums.length;
int minIndex, maxIndex;
for (int i = 0; i < length; i++) {
minIndex = maxIndex = i;
for (int j = i + 1; j < length - i; j++) {
if (nums[j] < nums[minIndex]) minIndex = j;
if (nums[j] > nums[maxIndex]) maxIndex = j;
}
if (minIndex == maxIndex) break;
swap(nums, i, minIndex);
//防止最大值为i的情况。
if (maxIndex == i) {
swap(nums, length - 1 - i, minIndex);
} else {
swap(nums, length - 1 - i, maxIndex);
}
}
return nums;
}
public void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
至此,选择排序基本讲完了,也欢迎大家补充、指正。
就这样吧,结束。