选择排序顾名思义,就是从序列中依次选择最小的、次小的、第3小的、……,让这些元素分别作为结果序列的第1个、第2个、第3个、……,或者,从序列中依次选择最大的、次大的、第3大的、……,让这些元素分别作为结果序列的最后、次后、倒数第3个、……。由此达到排序的目的。当然,这种描述只是大体的思想,不同的选择排序会在实现细节上体现出不同的做法。下面,我们先看看简单选择排序。
以序列:49、38、65、97、76、13、27、 49 为例。第1趟排序,寻找完整序列里头最小的元素,找到13,则13与该序列的头49交换位置(注:不要误以为这个是交换排序),得:13、38、65、97、76、49、27、 49 。第2趟排序时,由于上一趟排序导致完整序列的头个元素存放了最小者,则意味着这个位置的元素不需要考虑了,只需处理整个序列第2个元素开始到最后的部分。对该部分找到最小者为27,则27与该部分的头38交换位置,得:13、27、65、96、76、49、38、 49 。接下来的第 i 趟排序道理完全一样,处理完整序列第 i 个到结尾部分的元素,寻找这个部分的最小者,然后与这个部分的头交换位置。这样的过程直至处理完第7趟为止(此时,仅剩下两个要处理的元素了),最终得:13、27、38、49、 49 、65、76、97。就这么简单,不愧是简单选择排序了,实际上该排序最核心的部分体现在寻找序列最值的动作上,而这个是比较简单的问题。
同样,由于简单选择排序过程中可能会涉及到元素间的跨越式位置变动,使得其为不稳定排序。代码如下:
以序列:49、38、65、97、76、13、27、 49 为例。第1趟排序,寻找完整序列里头最小的元素,找到13,则13与该序列的头49交换位置(注:不要误以为这个是交换排序),得:13、38、65、97、76、49、27、 49 。第2趟排序时,由于上一趟排序导致完整序列的头个元素存放了最小者,则意味着这个位置的元素不需要考虑了,只需处理整个序列第2个元素开始到最后的部分。对该部分找到最小者为27,则27与该部分的头38交换位置,得:13、27、65、96、76、49、38、 49 。接下来的第 i 趟排序道理完全一样,处理完整序列第 i 个到结尾部分的元素,寻找这个部分的最小者,然后与这个部分的头交换位置。这样的过程直至处理完第7趟为止(此时,仅剩下两个要处理的元素了),最终得:13、27、38、49、 49 、65、76、97。就这么简单,不愧是简单选择排序了,实际上该排序最核心的部分体现在寻找序列最值的动作上,而这个是比较简单的问题。
同样,由于简单选择排序过程中可能会涉及到元素间的跨越式位置变动,使得其为不稳定排序。代码如下:
void selectSort(int list[],int length)
{
for(int i=0;i<length-1;++i)
{
int min=i;
for(int j=i+1;j<length;++j)
{
if(list[j]<list[min])
min=j;
}
int temp=list[i];
list[i]=list[min];
list[min]=temp;
}
}
设序列元素个数为n。对于简单选择排序而言,主要的操作几乎集中于每趟排序中,寻找对应序列部分最小者所产生的元素比较操作。第 i 趟排序,要进行n-i 次比较,则总比较次数为1+2+……+n-1=n(n-1)/ 2。无论初始序列如何,都要经过上述过程,故无最好与最坏情况之分。由此,简单选择排序的时间复杂度为O(
n2
)。由于该算法没有使用随元素个数改变而改变数量的辅助存储空间,则空间复杂度为O(1)。