在前边的排序算法(一)中已经分析过选择排序,这里主要是想讲解他的优化版本。
选择排序,是通过每次选择最小的数或者最大的数,然后将它放在它应该出现的位置上。
具体实现过程:将0号下标的数据保存,在之后的数中选择一个最小的数,如果最小的数不是0号数,则将最小的数与0号下标的数进行交换;将1号下标的数进行保存,在之后的数中 选择最小的数,如果最小的数不是1号数,进行交换。以此类推。
下边给出实现代码:
void SelectSort(vector<int>& v)
{
for(int i = 0; i < v.size() - 2; ++i)
{
int k = i;
for(int j = i + 1; j < v.size() - 1; ++j)
{
//找到最小的数的下标
if(v[j] < v[k])
k = j;
}
if(k != i)
{
swap(v[k],v[i]);
}
}
}
这样一来,对于每一趟,我们需要遍历一遍,将找到的最小的数放在应该出现的位置,所以,选择排序的时间复杂度是O(N*N),不管是最好情况还是最坏情况,找最小数的过程都需要遍历一遍,所以,选择排序最好情况也是O(N*N)。
优化版本:
根据上边的分析,如果在每一次查找最小值的时候,也可以找到一个最大值,然后将两者分别放在它们应该出现的位置,这样遍历的次数就比较少了,下边给出代码实现:
void SelectSort(vector<int>& a)
{
int left = 0;
int right = a.size() - 1;
int min = left;//存储最小值的下标
int max = left;//存储最大值的下标
while(left <= right)
{
min = left;
max = left;
for(int i = left; i <= right; ++i)
{
if(a[i] < a[min])
{
min = i;
}
if(a[i] > a[max])
{
max = i;
}
}
swap(a[left],a[min]);
if(left == max)
max = min;
swap(a[right],a[max]);
++left;
--right;
}
}
这样总共遍历的次数比起前边的一般版本就会减少一半,时间复杂度是O(N/2 * N /2)还是O(N*N)。但是,代码中,第一次交换结束后,如果left那个位置原本放置的就是最大数,交换之后,需要将最大数的下标还原。
需要注意的是,每次记住的最小值或者最大值的下标,这样方便进行交换。