排序算法作为算法的基础,我想大家都不陌生,甚至是张口就来的程度。什么插入排序,选择排序,冒泡排序,快速排序等等。但是真到了要你把代码写下来的时候,很多人都是懵逼的。
那么,废话不多说。现在就让我通过一系列的文章,带大家一次性的深入理解排序的原理,争取学习一次,终身受用。
冒泡排序和选择排序的共同点
这里为啥要把冒泡排序和选择排序放到一起讲呢?其实他们的共同点都是把牌堆分为无序和有序两部分,一开始都是无序的。然后依次从无序的牌堆里筛选出最大的值放到有序的牌堆里。
至于这个筛选的过程,他们分别采用了不同的方式。冒泡排序是依次把最大值进行位置交换交换到有序牌堆里。而选择排序是进行依次比较比较出最大值放到有序牌堆里。
选择排序
每次都是从无序牌堆的最左边拿相临的两个值进行比较,拿出最大的数放到有序牌堆的最右边。然后依次进行,直到所有的牌都进入有序牌堆。
private static void selectionSort(int[] arr){
for(int i=arr.length-1;i>=0;i--){
int MAX = Integer.MIN_VALUE;
int num = i;
for(int j=i;j>=0;j--){
if(arr[j]>MAX){
MAX = arr[j];
num = j;
}
}
swap(num,i,arr);
for(int x=0;x<arr.length;x++){
System.out.print(arr[x]);
}
System.out.println();
}
}
swap方法:先把arr中i位置的值,暂时存到temp值里。然后将arr中j位置的值赋给arr[i]。最后将临时存放的temp的值赋给arr[j],从而达到了交换的效果。
private static void swap(int i,int j,int[] arr){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
然后我们在main方法里进行调用
int[] arr = new int[]{5,7,3,1,2,7,6};
bubbleSort(arr);
起始状态:i=arr.length-1 所以j的取值范围是0-(arr.length-1),也就是在无序牌堆里取出最大的牌放到有序牌堆的最右边。
第一步,最大的值为标注为紫色的7,也就是num所在的位置,i指向arr.length-1,将num和i的位置进行交换,也就是将7和6进行交换。此时,有序牌堆为7。
第二步,最大的值为标注为紫色的7,也就是num所在的位置,i指向arr.length-2,将num和i的位置进行交换,也就是将7和6进行交换。此时,有序牌堆为7,7。
第三步,最大的值为标注为紫色的6,也就是num所在的位置,i指向arr.length-3,将num和i的位置进行交换,也就是将6和2进行交换。此时,有序牌堆为6,7,7。
第四步,最大的值为标注为紫色的5,也就是num所在的位置,i指向arr.length-4,将num和i的位置进行交换,也就是将5和1进行交换。此时,有序牌堆为5,6,7,7。
第五步,最大的值为标注为紫色的3,也就是num所在的位置,i指向arr.length-5,最大值和i指向的值相等,不进行交换。此时,有序牌堆为3,5,6,7,7。后续第六步,第七步同。
整体演变步骤如下:
选择排序的特点:
时间复杂度为O(n*n)
假设被排序的数列中有n个数。遍历一趟的时间复杂度是O(n),需要遍历多少次呢? n-1!因此,选择排序的时间复杂度是O(n*n)。
选择排序的最好和最坏和平均的时间复杂度都是O(n*n)。
空间复杂度为O(1):选择排序用到的额外的存储空间只有一个,那就是用于交换位置的临时变量temp,其他所有操作都是在原有待排序列上处理的,所以空间复杂度为 O(1)。
稳定排序:如果按照我们的方式进行倒序查找的情况下,选择排序是稳定的。在比较过程中,只有前面的元素比后面的元素大时才会被选为最大值。相等的情况下排在后面位置的元素会被优先选择为MAX。
结论:
选择排序是一种比较好理解的排序算法,也是表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。而且由于在内存中,写的效率是比读的效率低很多的。冒泡排序频繁的进行写操作,所以它的效率是比较低的。选择排序频繁的进行比较操作,写操作比较低,所以它的效率是优于冒泡排序的。
关于不同排序算法的对比,我们放到这一系列的文章的最后进行讨论。
为了帮助大家面试,我整理了一份面试资料。总共几十页PDF,加我公众号 天鹭城,回复2,一次性送给大家。