选择排序是一种更加简单直观的排序方法。
需求: 排序前:{4,6,8,7,9,2,10,1}
排序后:{1,2,4,5,7,8,9,10}
一、排序原理:
在序列中选择合适的元素放在合适的位置。
1.每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处 的值大于其他某个索引处的值,则假定其他某个索引出的值为最小值,最后可以找到最小值所在的索引
2.交换第一个索引处和最小值所在的索引处的值
也就是说,每次选序列中最小的元素分别放在第1、2、3......位,每次被放在合适位置的元素,在下一步排序中就不需考虑。
我们解释一下第一趟排序:
我们暂且认为最小的元素索引为min=0,这个位置现在元素为4;接下来我们拿着最小索引处的值依次和后面的元素比较。我们拿着索引min=0的元素4和索引=1处的元素6比较,4小于6,我们的最小索引人仍然为0;我们再拿4和8比较,4小于8,最小索引还是0;4和7比,4小于7,最小索引还是0;4和9比,4小于9,最小索引还是0;4和2比较,此时发现4大于2,最小索引所处的位置就不是0了,我们需要把它换成元素2所在位置的索引,为min=5;继续2和10比较,2小于10,最小索引还是5;2和1比较,最小索引所处的位置就不是5了,我们需要把它换成元素1所在位置的索引,为min=7.
到此为止,我们找到了最小元素所在的索引为7,找出来以后我们要把1放到序列第1个位置,只需要交换元素1和元素4即可,即交换索引7和索引0就可以。
以此类推,第2躺排序,交换元素2和元素6,即索引1和索引5......此时(1、2)已经有顺序了。最后剩一个元素10就不需要再找了,放到原位置。
二、选择排序的API:
类名 | Selection |
构造方法 | Selection():创建Selection对象 |
成员方法 | 1.public static void sort(Comparable[] a):对数组内的元素进行排序 2.private static boolean greater(Comparable v,Comparable w):判断v是否大于w 3.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值 |
其API设计和我们的冒泡排序很类似,只不过是类名不一样。
初始状态下,第一次排序所有元素都要参加,第二次索引0位置上的元素就不需要参加了,已经放在合适的位置了,只需要让剩余的元素参加排序。
第二次索引1处的元素也确定好了,第三次排序就不需要管前两个元素。我们发现第一次排序从索引0开始,第二次从索引1开始......最大可以为数组长度-2(因为数组长度-1处,只剩下一个元素,他就自己排到最后了,不需要继续排)
public class select {
/*
对数组a中的元素进行排序
*/
public static void sort(Comparable[] a){
for (int i=0;i<=a.length-2;i++){
//假定本次遍历,最小值所在的索引是i
int minIndex=i;
for (int j=i+1;j<a.length;j++){
//由于默认第一个元素所在位置为最小索引i,只需从下一个元素开始
//需要比较最小索引minIndex处的值和索引处的值
if (greater(a[minIndex],a[j])){
//跟换最小值所在的索引
minIndex=j;
}
}
//交换i索引处和minIndex索引处的值
exch(a,i,minIndex);
}
}
/*
比较v元素是否大于w元素
*/
private static boolean greater(Comparable v,Comparable w){
return v.compareTo(w)>0;
}
/*
数组元素i和j交换位置
*/
private static void exch(Comparable[] a,int i,int j){
Comparable t = a[i];
a[i]=a[j];
a[j]=t;
}
}
三、选择排序时间复杂度分析
选择排序使用了双层for循环,其中外层循环完成了数据交换,内层循环完成了数据比较,所以我们分别统计数据 交换次数和数据比较次数:
数据比较次数: (N-1)+(N-2)+(N-3)+...+2+1=((N-1)+1)*(N-1)/2=N^2/2-N/2;
数据交换次数: N-1
时间复杂度:N^2/2-N/2 +(N-1)=N^2/2+N/2-1;
根据大O推导法则,保留最高阶项,去除常数因子,时间复杂度为O(N^2);
不适合元素多的排序