对于一些基础的算法理解一致不是很透彻。以冒泡算法为例,Java实现,每次复习后,过段时间总是遗忘,又要重新看,今天索性静下心来详细分析一下,虽然是最基础的算法,然而小算法中未必没有大智慧,供本人及后来人参考。
先来看一个最笨的排序:
public static void sort1(int[] a){
int count = 0 ;
for(int i=0; i<a.length; i++){
for(int j=0; j<a.length; j++){
count++ ;if(a[i] < a[j]){
int temp = a[i];
a[i] = a[j] ;
a[j] = temp ;
}
}
}
System.out.println("#sort1 forloop count - " + count);
}
这是一种比较笨的排序方法,很多新人在写排序的时候,可能这样写理解会比较直观一些,将数组循环length*length次,所有值俩俩进行一次对比,最后得出结论:
public static void main(String[] args) {
int[] arr = new int[]{12,4,54,57,87,3,41,1,3,4,1,3,4,31,2} ;
sort1(arr);
System.out.println("最终结果:" + Arrays.toString(arr));
}
结果:
#sort1 forloop count - 225
最终结果:[1, 1, 2, 3, 3, 3, 4, 4, 4, 12, 31, 41, 54, 57, 87]
可见本次执行225次循环;
再来看一个升级版:
public static void sort2(int[] a){
int count = 0 ;
for(int i=0; i<a.length; i++){
for(int j=0; j<a.length-1; j++){
count++ ;
if(a[j] > a[j+1]){
int temp = a[j] ;
a[j] = a[j+1] ;
a[j+1] = temp ;
}
}
}
System.out.println("#sort2 forloop count - " + count);
}
本方法对上一个方法进行了进一步的简化,第一层同样循环length次,而第二层循环了length-1次,同时比较只存在于第二层循环中,由于第二层的比较重,将当前下标与当前下标+1进行比较,所以总的循环数需要length-1,否则会造成数组越界,这一种算法比较常见,甚至一些培训机构对学生进行培训时也是使用这种排序算法(至于是老师水平问题还是老师考虑到学生理解能力问题采用本种方法不得而知),本方法对第二层的循环进行了-1操作,总排序次数当然要少于第一种。
执行:
int[] arr = new int[]{12,4,54,57,87,3,41,1,3,4,1,3,4,31,2} ;
sort2(arr);
System.out.println("最终结果:" + Arrays.toString(arr));
结果:
#sort2 forloop count - 210
最终结果:[1, 1, 2, 3, 3, 3, 4, 4, 4, 12, 31, 41, 54, 57, 87]
本次执行210次循环,排序结果同第一种方法,效率有所提升。
对于大学没有学过算法和数据结构相关课程,又是初入开发行业的童鞋来说,本种算法可能需要分析一下才能明白原理。
我们来分析一下第二种方法的缺陷。
先看第二层循环:
每次循环,都要将第N个数与第N+1个数进行比较,如果第N个数大,则互换位置。例如:
数组:{12,4,54,3,22,53}
第一次循环,j=0,则比较12与4的大小,发现12>4,则互换12与4的位置,结果如下:
{4,12,54,3,22,53}
第二次循环,j=1,此次比较12与54的大小,发现12<54,则保持不动,结果如下:
{4,12,54,3,22,53}
第三次循环,j=2,比较54和3大小,54>3,则互换,结果如下:
{4,12,3,54,22,53}
第四次循环,j=3,比较54和22大小,54>22,互换,结果如下:
{4,12,3,22,54,53}
最后一次循环,j=4,比较54和53大小,54>53,互换,结果如下:
{4,12,3,22,53,54}
我们发现,每一次 i 循环,都可以将arr[length-1-i]这个位置的数选举而出,也就是说,整个循环只需要length-1次(最后一轮不用排序,因为剩下的最后一个数肯定是最小值),即可完成所有数的排序,所以第二个方法可进行进一步优化: