何为选择排序?其实选择排序是最好理解的排序,就是每次遍历数组,从中选出一个最大的和一个最小的数,把最小的数放到数组的最左边,最大的数放到数组的最右边,两边缩小一个位置(因为最大和最小的数已经排好了),再遍历剩下的数找出最小的和最大的数放到第二个位置和倒数第二个位置,以此类推,最终就能使数组有序。
动图如下:
但是这里的动图演示的是每次找出数组中的一个最小值放到左边,其实遍历一遍是可以同时找到最大值和最小值的,这样的话效率会高一倍。这个看个人喜好吧,想一次选最大和最小或者一次就选一个最小都是可以的。
毫无疑问,选择排序需要执行的次数是:第一次遍历数组选最小值需要n次,第二次遍历数组找最小值需要n-1次,以此类推,最后递减到1次,这是一个等差数列的求和,所以时间复杂度为经典的O(N^2), 而且选择排序对数据敏感性不高,就是无论是什么情况的数据它的时间复杂度都是O(N^2),因为即使数组本来就是有序的,但是每一次仍然需要遍历剩下的所有数才能选出最小的。所以选择排序是最“稳定”的排序,但是这个“稳定”是一个调侃的词。由于选择排序的效率是非常稳定的慢,所以在实际中很少被使用。
参考代码如下:
//这里的代码是每一次同时选出一个最大值和最小值的, //参数n代表数组的元素个数 void SelectSort(int* a, int n) { assert(a); //左下标 int left = 0; //右下标 int right = n - 1; int i = 0; //只要左右下标还没有相遇,就说明两个下标之间 // 还有没排好的数据,一直循环到left==right while (left < right) { //可以设待排序的数组中的任意一个数的下标作为最大值或者最小者 // 的下标,因为后面比较的时候会被真正的最大最小值换掉,但是不 //能用不是数组内的值作为基准 int mini = left; int maxi = left; //遍历一遍选出最大值和最小值的下标,由于left作为基准了,所以 //i可以直接从left+1开始,不用跟自己比较了 for (i = left + 1; i <= right; i++) { if (a[i] < a[mini]) { mini = i; } if (a[i] > a[maxi]) { maxi = i; } } //最小值换到左边 Swap(&a[left], &a[mini]); //但是这里需要注意,因为left可能就是最大值的下标 //所以在把最小值换到左边的时候可能把最大值从左边 //换到了最小值的位置,所以如果找到的最大值的下标是 //left,即left==maxi的话,经过了上面的交换,最大 //值就被交换了,需要修正一下最大值的下标,此时它应该 //在原来最小值的位置mini上,所以maxi=mini修正一下。 //如果每次只找一个最小值的话就不会出现这种需要修正的 //情况咯 if (left == maxi) { maxi = mini; } //最大值换到右边 Swap(&a[right], &a[maxi]); //左边最小,右边最大之后下一次就不用对这两个数排序了 //所以两边缩小一个位置,即left++,right--,再从剩 //下的数中遍历找最大和最小值,迭代走下去,直到left和right相遇 ++left; --right; } }